Send error codes
The full list of errors of POST /api/v1/public/emails and the email read endpoints. An error comes in the standard public API format; errors in the request body also list every violation in details[].
Error format
{
"ok": false,
"error": {
"code": "BAD_REQUEST",
"message": "The request failed validation.",
"details": [
{ "field": "to[1].email", "reason": "INVALID_EMAIL", "value": "not-an-email" },
{ "field": "subject", "reason": "REQUIRED" }
]
},
"meta": { "requestId": "01JB2W...", "timestamp": "2026-09-30T10:15:00.120Z" }
}
error.code— a machine-readable code; handle errors by it, not bymessage.error.message— a description in English.error.details[]— not every error has it. An item is{ field?, reason, value? }:field— the path to the field insidedata:to[1].email,headers.Message-ID,attachments[3];reason— what's wrong with the field, seereasonindetails[];value— the field value when it's safe to return: an address — yes, attachment content — no. ForMAX_LENGTHandLIMIT_EXCEEDED,valueholds the allowed limit.
meta.requestId— give it to support if you need help with a specific request.
Body format errors are returned all at once: one 400 BAD_REQUEST error lists every violation of the request in details[], including system headers and the number of attachments. If the request has no other violations, system headers come with the 400 HEADER_NOT_ALLOWED code, and extra attachments with the 400 ATTACHMENT_COUNT_EXCEEDED code.
reason in details[]
reason | Meaning |
|---|---|
REQUIRED | A required field is missing or empty |
INVALID_TYPE | Wrong value type |
INVALID_EMAIL | Invalid address |
MAX_LENGTH | Length exceeded; value holds the limit |
LIMIT_EXCEEDED | Too many items (recipients, replyTo, attachments) or the total attachment size exceeded; value holds the limit |
MUTUALLY_EXCLUSIVE | Fields can't be combined: html/text, templateId, templateAlias |
DUPLICATE_RECIPIENT | An address repeats across to, cc, and bcc |
INVALID_BASE64 | Attachment content isn't base64 |
HEADER_NOT_ALLOWED | A system header in headers |
INVALID_CURSOR | The sending history cursor is from other filters, another list, or corrupted — start from the first page |
RECIPIENT_* | A rejected recipient — in RECIPIENT_SUPPRESSED and RECIPIENT_BOUNCED errors; the codes are in Email statuses and events |
Error codes
Authorization and limits
| HTTP | error.code | Cause | Action |
|---|---|---|---|
| 401 | INVALID_API_TOKEN | The token is invalid, not found, or revoked | Check or reissue the token |
| 401 | ACCOUNT_BANNED | The account is blocked | Contact support |
| 403 | SCOPE_REQUIRED | The token lacks the required scope. message names it: email.send for sending, email.read for reading | Add the scope to the token |
| 403 | PUBLIC_API_DISABLED | Public API access is disabled for the account | Contact support |
| 429 | RATE_LIMIT_EXCEEDED | The API key's request limit or the sender domain's email limit is exceeded — the latter has reason: DOMAIN_RATE_LIMIT in details, see Rate limit | Wait Retry-After seconds and retry with the same Idempotency-Key |
Idempotency
| HTTP | error.code | Cause | Action |
|---|---|---|---|
| 400 | INVALID_IDEMPOTENCY_KEY | Idempotency-Key doesn't match the format | Fix the key |
| 409 | IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_PAYLOAD | The key was already used with a different body | Retry with the same body or use a new key |
| 409 | REQUEST_ALREADY_IN_PROGRESS | A request with this key is still running | Wait Retry-After seconds and retry with the same key |
More in Idempotency and quota.
Request body
| HTTP | error.code | Cause | Action |
|---|---|---|---|
| 400 | BAD_REQUEST | Body format and limits — details in details[] | Fix the fields from details[] |
| 400 | HEADER_NOT_ALLOWED | A system header in headers: one details[] item per header | Remove the header; for Reply-To use the replyTo field |
| 400 | ATTACHMENT_COUNT_EXCEEDED | More than 20 attachments | Reduce the number of files |
| 400 | ATTACHMENT_TOO_LARGE | Attachments exceed 15 MB in total | Compress the files or link to them in the email body |
| 400 | ATTACHMENT_TYPE_FORBIDDEN | A disallowed file type — for example, an executable; the fileName extension and the content are checked | Use another format |
| 413 | PAYLOAD_TOO_LARGE | The request body is larger than 32 MB | Reduce attachments or put a link to the file in the email body |
Sending key and domain
| HTTP | error.code | Cause | Action |
|---|---|---|---|
| 404 | SENDING_KEY_NOT_FOUND | No key with this keyId in the account, it was deleted, or it's an SMTP key | Check keyId; for HTTP sending, use a key for sending through the API |
| 404 | SENDING_KEY_DOMAIN_NOT_FOUND | The from.email domain isn't in the account | Add and verify the domain or fix from.email |
| 409 | SENDER_DOMAIN_BLOCKED | The sender domain or the key's domain is blocked | Contact support |
| 422 | SENDING_KEY_NOT_ACTIVE | The sending key — explicit or default — isn't in the enabled status: a new key is still awaiting moderation, or the key is disabled or banned | Check the key status; pass another keyId or change the default key |
| 422 | SENDING_KEY_DEFAULT_NOT_CONFIGURED | keyId isn't passed and the sender domain has no default key | Pass keyId or set a default key |
| 422 | SENDING_KEY_DOMAIN_NOT_VERIFIED | The key's domain isn't verified | Verify the domain in the dashboard |
| 422 | SENDER_DOMAIN_MISMATCH | from.email isn't in the sending key's domain | Send from an address in the key's domain or don't pass keyId |
Template and content
| HTTP | error.code | Cause | Action |
|---|---|---|---|
| 404 | TEMPLATE_NOT_FOUND | No template with this templateId or templateAlias in the account | Check the id or alias |
| 422 | TEMPLATE_SYNTAX_ERROR | The template doesn't compile | Fix the template |
| 422 | CONTENT_SYNTAX_ERROR | html or text doesn't compile | Fix the content |
Recipients and quota
| HTTP | error.code | Cause | Action |
|---|---|---|---|
| 422 | RECIPIENT_SUPPRESSED | All to recipients unsubscribed from the key's emails or complained. The email isn't sent to anyone, including cc and bcc | Don't retry: the response will be the same |
| 422 | RECIPIENT_BOUNCED | No to recipient can be sent the email, and at least one is rejected by the list of undeliverable addresses. The email isn't sent to anyone, including cc and bcc | Don't retry; remove the addresses from details[] with codes RECIPIENT_KNOWN_BOUNCED, RECIPIENT_BLOCKED, RECIPIENT_INVALID, RECIPIENT_DOMAIN_INVALID from your base |
| 402 | PAYMENT_REQUIRED | The quota isn't enough for all recipients of the email; the current remaining quota is in X-Quota-Remaining | Wait for the next billing period or change your plan, then retry with the same Idempotency-Key |
If only some recipients are rejected, the email is accepted with 202 and the rejected ones appear in recipients[] with their status — see When some recipients are rejected.
Reading emails
| HTTP | error.code | Cause | Action |
|---|---|---|---|
| 404 | EMAIL_NOT_FOUND | No such email, it belongs to someone else, it was accepted before ДД.ММ.ГГГГ, or the id isn't a UUID; often recipients[].id was passed instead of data.id | Check that the path has data.id from the send response |
| 404 | EMAIL_RECIPIENT_NOT_FOUND | The email has no such recipient | Check recipientId |
| 400 | BAD_REQUEST | An invalid sending history filter or cursor — the field is in details[].field | Fix the parameter; on INVALID_CURSOR, start from the first page |
| 404 | SENDING_KEY_NOT_FOUND | The sending history keyId filter has a key that isn't in the account | Check keyId |
Service failures
| HTTP | error.code | Cause | Action |
|---|---|---|---|
| 500 | INTERNAL_SERVER_ERROR | An unexpected error | Retry with the same Idempotency-Key |
| 503 | SERVICE_UNAVAILABLE | The service is temporarily unavailable | Retry with the same Idempotency-Key with increasing delays |
On 5xx the email isn't sent and no quota is charged — retry the request with the same Idempotency-Key.
What to retry
| Response | Retry? |
|---|---|
429, 409 REQUEST_ALREADY_IN_PROGRESS | Yes, after Retry-After |
500, 503, dropped connection, timeout | Yes, with the same Idempotency-Key and increasing delays |
402 | Yes, after changing your plan or when the next billing period starts, with the same Idempotency-Key |
422 RECIPIENT_SUPPRESSED, 422 RECIPIENT_BOUNCED | No — the response won't change |
401, 403 | Yes, after fixing the token or the scope, with the same Idempotency-Key |
Other 4xx | No — first fix the request or the account (key, domain, template); then send with a new Idempotency-Key |
See also
- Send a transactional email.
- Idempotency and quota.
- Email statuses and events — recipient reason codes.
- Authentication — tokens and scopes.