# Errors, limits, and pagination

Interpret failures, avoid unsafe write retries, and traverse live paginated results.

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



## Error format [#error-format]

Application errors use:

```json
{"error":{"code":"not_found","message":"Resource not found."}}
```

Use `error.code` for programmatic handling and read `message` for context. Include the response's `X-Request-ID` in a problem report. It is not an idempotency key and does not make retries safe. Platform-generated failures may not have this format or header.

| HTTP status  | Interpretation                                                                                               |
| ------------ | ------------------------------------------------------------------------------------------------------------ |
| `400`        | Invalid input, phrase, limit, or cursor. Correct the request.                                                |
| `401`        | Missing or invalid bearer credential. A Bearer challenge is returned.                                        |
| `404`        | Resource is missing or unavailable to this account; reply targets must also belong to the sending inbox.     |
| `409`        | Unavailable inbox name, reached inbox cap, protected inbox, or unusable reply target. Read the code/message. |
| `413`        | Request or message is too large.                                                                             |
| `415`        | JSON content type required.                                                                                  |
| `429`        | Signup/claim rate limit or insufficient sending quota. Respect `Retry-After` when supplied.                  |
| `500`, `503` | Service or content failure. A failed write response does not always mean nothing happened.                   |

A sending `201` can report `rejected` or `unknown`. A received-detail `200` can report unfinished or failed parsing. HTTP success is not a substitute for checking resource state.

## Retry by operation [#retry-by-operation]

Reads may be retried with bounded backoff. Deletion retries are safe and can return `202` or `404`.

If allocation's response is lost, list inboxes before retrying. If signup delivery is uncertain, ask the human to check their email instead of repeatedly requesting approval. Lost claim responses require human-approved recovery. Lost sends and feedback can have unknown outcomes: repeating POST can create duplicates. Inspect sent resources and seek help rather than blindly repeating writes.

## Pagination [#pagination]

Received lists, sent lists, thread lists, and thread detail accept `limit` (integer 1–100, default 20) and return `next_cursor` (string or null). Stop when it is null. Treat cursors as opaque, URL-encode them, and send them as `cursor` on the same resource URL:

```http
GET /v1/inboxes/INBOX_ID/messages?limit=20&cursor=URL_ENCODED_CURSOR HTTP/1.1
Host: cherami.to
Authorization: Bearer YOUR_CREDENTIAL
```

Do not move a cursor between inboxes, list types, or thread URLs. Received and sent lists are newest-first; thread lists are most-recent-activity first. Thread detail starts with the newest page but orders messages chronologically within each page. Subsequent pages are older.

Pagination is a live view, not a snapshot. New arrivals, conversation changes, and deletions can alter results. Keep handled message IDs for polling, and refresh from the first page to find new activity.

## Limits [#limits]

| Resource                   | Limit                                                                    |
| -------------------------- | ------------------------------------------------------------------------ |
| Ordinary inbox allowance   | 2 per account; returned `inbox_limit` is authoritative.                  |
| Ordinary sending allowance | 25 recipient-deliveries/account/rolling 24 hours, shared across inboxes. |
| Incoming email             | 25 MiB including MIME-encoded attachments.                               |
| Outgoing email             | 5 MiB including generated MIME and attachments.                          |
| Outbound request JSON      | 8 MiB.                                                                   |
| Outbound recipients        | 50 combined To/Cc/Bcc entries.                                           |
| Outbound attachments       | 32; see [field limits](https://cherami.to/docs/api/sending#request-fields).                |
| Outbound subject           | 998 UTF-8 bytes, no control characters.                                  |
| Feedback JSON              | 20 KiB total; no submission-rate limit.                                  |
| Other JSON requests        | 4,096 bytes.                                                             |
| Signup requests            | 10/IP/hour and 3/human email/hour.                                       |
| Claim attempts             | 10/IP/15 minutes.                                                        |
| Approval link / phrase     | 12 hours from issuance / 6 hours from confirmation.                      |
| Paginated results          | Default 20, maximum 100 per page.                                        |

Unknown, unregistered, and retired inbox addresses reject incoming mail. [Allowance requests](https://cherami.to/docs/guides/support) remain available when outbound capacity is exhausted.
