Skip to main content

Send

POST /v1/email/messages sends one message to one recipient, with the application’s live key and the email:send scope.
html and text together are at most 512 KiB. There are no attachments, no templates and no list of recipients: render the message on your side and call once per recipient. The answer is 202 Accepted:
price_halalas is what this message took from your balance.
Send an Idempotency-Key per business event and retry a 502 or a network error with the same key. A replay returns the original 202 with Idempotent-Replayed: true and sends nothing. A 502 send_failed releases the key, so the retry sends. See Reliability and limits.

Read a message

GET /v1/email/messages/{id} needs email:read (which email:send includes) and answers for a message of the key’s application; any other id answers 404 not_found.

Statuses

accepted then sent then delivered; bounced or failed end it. Statuses only move forward. A bounce can arrive after delivered, when a mailbox accepts the message and refuses it later: the status becomes bounced. A complaint, the recipient marking the message as spam, sets complained_at on the delivered message and suppresses the address; the status and the price stay.

The suppression list

Each account keeps one list of addresses it will not send to: every permanent bounce and every complaint, from any of its applications. A send to a listed address answers 422 recipient_suppressed before anything is recorded or charged. Email → Suppressed lists every address with its reason and the message that caused it. An address that bounced by mistake can be removed there; an address that complained cannot.

Webhooks

The application’s webhook receives four events, signed and retried like every other:
to is masked to its first character and its domain: match on id or your reference. error is null on email.delivered, and bounce is null on every event but email.bounced. The event catalog has each event.

Errors

The checks every endpoint shares come first: the rate limit, the key, its access (403 insufficient_scope names email:send or email:read), the account’s state and the request’s shape (400 invalid_request for a missing to or subject, neither html nor text, or a subject over 255 characters). Then, in this order: GET /v1/email/messages/{id} answers live_key_required and 404 not_found.
Last modified on October 12, 2026