Threads
Conversations: messages of one inbox grouped by their reply headers or, failing that, by subject and participants.
Get a thread
Section titled “Get a thread”GET /v1/threads/{id}
Auth: API key (Authorization: Bearer rz_live_…)
Returns a conversation and its messages as compact items, oldest first. A thread belongs to
one inbox. At most the newest 500 messages are included (truncated is true when there are
more; message_count is the total). Does not mark messages as read. Threads of deleted
inboxes are not found. Works in every account status.
Problem codes: unauthorized (401), not_found (404).
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
id |
path | string | yes | Thread id (thr_…), from a message’s thread_id. Any other value gets 404 not_found. |
Responses
Section titled “Responses”The thread.
Content type application/json.
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
inbox_id |
string | yes | |
subject |
string or null | yes | The subject of the oldest message in messages. Untrusted. |
message_count |
integer (1–) | yes | Number of messages in the thread, counting all of them even when truncated. |
last_message_at |
string or null (date-time) | yes | When the newest message was received. |
truncated |
boolean | yes | True when the thread has more than 500 messages; only the newest 500 are in messages. |
messages |
array of CompactMessage (max 500 items) | yes | Oldest first. |
messages[].id |
string | yes | |
messages[].thread_id |
string | yes | |
messages[].inbox_id |
string | yes | |
messages[].from |
string or null | yes | The first address in the From header, lowercase. It can be forged unless sender_trust is aligned_pass. Null when there is no usable address or the message could not be parsed. |
messages[].to |
array of string (max 100 items) | yes | Addresses in the To and Cc headers, lowercase, at most 100. For a message that could not be parsed, the inbox address. |
messages[].subject |
string or null | yes | The subject without invisible characters, at most 2 KB (UTF-8). Null when empty or missing. Untrusted. |
messages[].snippet |
string (length 0–200) | yes | The first 200 characters (Unicode code points, so an emoji is never cut in half) of reply_text (or of text when reply_text is empty), with whitespace collapsed. Untrusted. |
messages[].received_at |
string (date-time) | yes | When Replyz accepted the message. |
messages[].sender_trust |
string: aligned_pass, dkim_pass, unauthenticated |
yes | How far the sender is authenticated. Today every message is unauthenticated: aligned_pass and dkim_pass are planned (docs/features/safety.md). They will be based on Cloudflare’s own authentication results, located by position; ambiguous cases are unauthenticated.- aligned_pass: Cloudflare reports a DMARC pass for the domain of from. The mail comes from that domain; its content is still untrusted.• dkim_pass: Cloudflare reports a valid DKIM signature but no DMARC pass. The signature can belong to any domain, so from can still be forged.• unauthenticated: everything else. from can be forged.A message that could not be parsed is always unauthenticated. |
messages[].injection_risk |
string: low, medium, high |
yes | Heuristic risk that the content tries to instruct an AI. - high: instruction-like text hidden from a human reader, Unicode tag characters (invisible text), two or more kinds of instruction-like text, one kind together with hidden content, or instructions in a text/plain part that the HTML does not show.• medium: one kind of instruction-like text, a hiding signal (hidden_content, zero_width_chars, long_encoded_blob, text_part_differs), or a message that could not be parsed.• low: none of these. This does not mean the content is safe. |
messages[].otp_like |
boolean | yes | Heuristic: true when the code finder of POST /v1/messages/{id}/extract finds a likely code in the subject and the new text (reply_text, or text when it is empty). A hint only; get the code itself with extraction. |
messages[].has_attachments |
boolean | yes | |
messages[].returned_before |
boolean | yes | True if wait, GET /v1/messages/{id} or POST /v1/messages/{id}/extract had returned this message before this call. |
{ "id": "thr_01M6R6JZDERMT2DVG0T8ABTX4J", "inbox_id": "ibx_01M6R4T180ZADNV1160NS1SRNP", "subject": "Dinner on Friday?", "message_count": 2, "last_message_at": "2026-11-06T10:47:40.117Z", "truncated": false, "messages": [ { "id": "msg_01M6R6JZDERMT2DVG0T8ABTX4J", "thread_id": "thr_01M6R6JZDERMT2DVG0T8ABTX4J", "inbox_id": "ibx_01M6R4T180ZADNV1160NS1SRNP", "from": "ana@example.com", "to": [ "atlas-wo7tw5@youreplyz.com" ], "subject": "Dinner on Friday?", "snippet": "Hi! Are you free for dinner on Friday at 8? I booked a table at the usual place. The menu is attached. Ana", "received_at": "2026-11-06T10:31:05.902Z", "sender_trust": "unauthenticated", "injection_risk": "low", "otp_like": false, "has_attachments": true, "returned_before": true }, { "id": "msg_01M6R7HAANT4D11FHFZPYG0C2V", "thread_id": "thr_01M6R6JZDERMT2DVG0T8ABTX4J", "inbox_id": "ibx_01M6R4T180ZADNV1160NS1SRNP", "from": "ana@example.com", "to": [ "atlas-wo7tw5@youreplyz.com" ], "subject": "Re: Dinner on Friday?", "snippet": "Also, can you bring the wine? Thanks!", "received_at": "2026-11-06T10:47:40.117Z", "sender_trust": "unauthenticated", "injection_risk": "low", "otp_like": false, "has_attachments": false, "returned_before": false } ]}unauthorized: the Authorization header is missing, is not Bearer rz_live_…, or holds an
unknown or revoked key.
| Header | Description |
|---|---|
WWW-Authenticate |
Always Bearer realm="replyz". |
Problem object (application/problem+json). Codes: unauthorized.
Example: unauthorized: missing or malformed key
{ "type": "https://docs.replyz.io/errors/unauthorized", "code": "unauthorized", "status": 401, "message": "Missing or malformed API key.", "fix": "Send the header Authorization: Bearer rz_live_… with the api_key from POST /v1/signup.", "docs": "https://docs.replyz.io/errors/unauthorized.md"}not_found: no such thread in this account, or its inbox was deleted.
Problem object (application/problem+json). Codes: not_found.
Example: not_found: thread
{ "type": "https://docs.replyz.io/errors/not_found", "code": "not_found", "status": 404, "message": "Thread not found.", "fix": "Use a thread_id from a message.", "docs": "https://docs.replyz.io/errors/not_found.md"}internal_error: something failed on Replyz’s side. Retry after a few seconds.
Problem object (application/problem+json). Codes: internal_error.
Example: internal_error
{ "type": "https://docs.replyz.io/errors/internal_error", "code": "internal_error", "status": 500, "message": "Something went wrong on our side.", "fix": "Retry in a few seconds.", "docs": "https://docs.replyz.io/errors/internal_error.md"}