# Received messages

Incoming-message pagination, prepared fields, processing states, downloads, and deletion.

Source: https://cherami.to/docs/api/messages



All routes require bearer authentication. Missing or other-account resources return `404`.

## List messages [#list-messages]

`GET /v1/inboxes/{inbox_id}/messages?limit=20`

Returns `200` with `messages` and `next_cursor`. Messages are ordered newest-received first. `limit` is 1–100, default 20. Follow the returned cursor as a URL-encoded `cursor` parameter on the same URL. See [pagination](https://cherami.to/docs/api/errors#pagination).

```json
{
  "messages": [{
    "id": "22222222-2222-4222-8222-222222222222",
    "inbox_id": "11111111-1111-4111-8111-111111111111",
    "thread_id": null,
    "envelope_from": "sender@example.com",
    "envelope_to": "my-agent@cherami.to",
    "subject": null,
    "received_at": "2026-10-01T00:00:00.000Z",
    "processing_status": "pending"
  }],
  "next_cursor": null
}
```

Every summary contains the fields above. `subject` may be null. `thread_id` is null until parsing succeeds. Only ready summaries additionally contain `from`, with a parsed address or null if absent. It is omitted for other states. There are no body previews in the list.

A parsed address is a mailbox (`{"name":"Sender","address":"sender@example.com"}`) or group (`{"name":"Team","group":[{"name":"Sender","address":"sender@example.com"}]}`). Parsed From is sender-supplied, not proof of identity. `envelope_from` is the SMTP sender and may be a bounce address.

## Count messages [#count-messages]

`GET /v1/inboxes/{inbox_id}/messages/count` returns `200` with `{"count":3}`.

This is the current count, including unfinished messages, not an unread count or a snapshot shared with pagination.

## Read a message [#read-a-message]

`GET /v1/messages/{message_id}` returns `200` with the summary metadata except the list-only `from`, plus:

| Field          | Value                                                            |
| -------------- | ---------------------------------------------------------------- |
| `message_id`   | RFC message identifier or null; distinct from the resource `id`. |
| `raw_size`     | Original MIME size in bytes.                                     |
| `processed_at` | Processing completion timestamp or null.                         |
| `content`      | Present only when `processing_status` is `ready`.                |

`content` has these fields:

| Field                                                        | Value                                                                                   |
| ------------------------------------------------------------ | --------------------------------------------------------------------------------------- |
| `from`, `sender`                                             | Parsed address object or null.                                                          |
| `reply_to`, `to`, `cc`, `bcc`                                | Arrays of parsed address objects; empty when absent.                                    |
| `subject`, `message_id`, `in_reply_to`, `references`, `date` | Parsed header strings or null. `date` is sender-supplied, not the service receipt time. |
| `text`, `html`                                               | Body strings or null. HTML is untrusted text, not safe application markup.              |
| `attachments`                                                | Array of attachment metadata, empty when absent.                                        |

Each received attachment has `id` (string), `filename` (string or null), `size` (bytes), `mime_type`, `disposition` (string or null), `content_id` (string or null), and `related` (boolean). Use its `id` in the attachment download route.

### Processing states [#processing-states]

`pending` and `processing` mean prepared content is not ready. Check later with bounded backoff. `ready` supplies `content`; `failed` does not. All four states can return detail `200`. Raw MIME remains available in unfinished and failed states. Missing stored content can return `503 content_unavailable`.

## Download raw MIME [#download-raw-mime]

`GET /v1/messages/{message_id}/raw`

Returns `200` with original MIME bytes, `Content-Type: message/rfc822`, and attachment disposition. This does not require successful parsing.

## Download an attachment [#download-an-attachment]

`GET /v1/messages/{message_id}/attachments/{attachment_id}`

Returns `200` with file bytes, `Content-Type: application/octet-stream`, and attachment disposition. Use the ID returned in ready content, not a guessed filename. An unavailable attachment or a message that is not ready returns `404`; missing stored content can return `503`.

Downloads use `no-store`, `nosniff`, and a sandbox content security policy. Reported filenames and MIME metadata do not establish that files are safe to execute or render.

## Delete a message [#delete-a-message]

`DELETE /v1/messages/{message_id}` returns `202`:

```json
{"id":"22222222-2222-4222-8222-222222222222","status":"deletion_pending"}
```

Permanently deletes the received message and its attachments, including when parsing is unfinished. No trash or undo. It is no longer available for retrieval or as a new reply target. Repeated deletion is safe and can return `202` or `404`.

[Receiving guide](https://cherami.to/docs/guides/receiving) · [Deletion guide](https://cherami.to/docs/guides/deletion)
