List messages

.md

Walk a mailbox, newest first, with a cursor.

Scopesmail:read
GET/v1/me/mail/messages

One row per message, newest first. See Reading mail for why the unit is a message rather than a conversation.

Request

curl "https://api.proppertrading.com/v1/me/mail/messages?folder=inbox&limit=30" \
  -H "Authorization: Bearer ptat_9f2c1a44_3b8e7d2f5c9a1b4e6d8f0a2c4e6b8d1f"
ParameterDescription
folderinbox, archive, drafts, sent, spam or trash. Defaults to inbox
mailboxOne mailbox id, such as mbx_w6sy3skvgydh5e3b. An id you cannot read, a number included, falls back to all of yours
starred1 for starred only. Reaches across folders
unread1 for unread only. Narrows whatever else is selected and stays in the folder
labelA label id of this environment, such as lbl_p6m3x8b2k9q4w7td. Reaches across folders. An id that names none of them, a number included, is refused, not ignored
assignedme, for the conversations handed to you. Nothing else is accepted
qA search. See the operators
limitUp to 100. Defaults to 20
starting_afterThe next_cursor of the previous page

starred, label, assigned and q each make the list span the inbox, the drafts and what was sent, and leave the bin and spam out. folder is then only a fallback for where a search looks.

unread is the exception: it narrows, it never widens. Asking for unread mail while looking at the inbox answers with unread inbox mail, not with everything unread wherever it sits. It combines with the others, so starred=1&unread=1 is the starred mail you have not read.

Response

{
    "data": [
        {
            "object": "mail_message",
            "id": "msg_h3k8q2w7n4r9t5vx",
            "thread_id": "thr_c4n8w2k7p5x9m3qd",
            "address_id": "mbx_w6sy3skvgydh5e3b",
            "direction": "inbound",
            "from_email": "[email protected]",
            "from_name": "Jamie Rivera",
            "participants": ["Jamie Rivera"],
            "subject": "Payout request",
            "preview": "Hi, I passed the evaluation last week and wanted to ask",
            "labels": [
                {
                    "id": "lbl_p6m3x8b2k9q4w7td",
                    "name": "Payouts",
                    "color": "blue"
                }
            ],
            "position": 1,
            "count": 3,
            "folder": "inbox",
            "is_starred": false,
            "is_read": true,
            "has_attachments": false,
            "message_at": "2026-08-19T13:30:36.000000Z",
            "assignee": { "id": "usr_t7q3m8k2x9n4w6pb", "name": "Han Aarts" },
            "answered": {
                "id": "usr_t7q3m8k2x9n4w6pb",
                "name": "Han Aarts",
                "at": "2026-08-19T14:02:11.000000Z"
            },
            "notes": 2
        }
    ],
    "meta": {
        "request_id": "req_01kz4bkr1aj1gv63d8fv3133ey",
        "has_more": true,
        "next_cursor": "MjAyNi0wOC0xOSAxMzozMDozNi4wMDAwMDB8bXNnX2gzazhxMnc3bjRyOXQ1dng"
    }
}
FieldDescription
idThe message, such as msg_h3k8q2w7n4r9t5vx. What every other mail endpoint takes in its path. See Ids
thread_idThe conversation, such as thr_c4n8w2k7p5x9m3qd. The same on every row of one exchange, so it is what to group on when an app wants to
address_idThe mailbox the message sits in, the id from list mailboxes
position, countWhich message of its conversation this is, and how long that conversation runs. The only thing on a row that says there is an exchange at all
participantsWho the row is about: the sender, or the recipients on something you sent
previewThe first line of the text body, quotes stripped
assigneeWhose job the conversation is: { "id", "name" }, or null. Both belong to the conversation, not to this message, so every row of the same thread carries the same one. Change it with assign, and see who it may go to with list assignees
notesHow many notes the team has left on the conversation. The notes themselves come with the conversation
answeredWho answered it last and when, as { "id", "name", "at" }, while that answer is still the last word in it. Null once somebody replies again

Paging

The cursor is opaque and carries both the date the list sorts on and the id of the last row, which breaks its ties. Pass the whole next_cursor back as starting_after, and do not build one yourself.

A cursor handed out before 2026-10-08 carries a number instead of an id and is refused with invalid_cursor. Start again from the first page.

Offset paging is not offered. Mail arrives while you are walking a list, and offsets silently skip and repeat rows when it does.

Errors

StatusCodeMeaning
400invalid_folderNot one of the six folders
400invalid_cursorNot a cursor we handed out, or one from before 2026-10-08
400invalid_limitNot a positive integer
403insufficient_scopeThis device does not hold mail:read
404resource_not_foundThe label id names no label in this environment. A label deleted elsewhere is the usual cause, and a number is another
403mailbox_not_permittedThe account may not open a mailbox at all