Reference
More ways to use this page
Errors
Every error from the API is JSON, with an error code for your program and a message for a person. A request that fails validation also has issues, one per invalid field:
{
"error": "invalid_request",
"message": "The request is invalid: to.0: Invalid email address",
"issues": [{ "path": "to.0", "message": "Invalid email address" }]
}
Some errors add fields, such as the suppressed recipients or when a limit resets. Each operation’s page in the reference lists them.
Two refusals are plain text, not JSON: 429 Too Many Requests and 413 Request Entity Too Large. They come from the proxy in front of the API, as Limits explains. A body over the size limit meets the proxy first, so it gets the plain-text 413.
Retry or fix
rate_(429): wait the seconds inlimited retryAfter, which theRetry-Afterheader also gives, then send again. The refused message was not stored. If you meet this limit often, ask support to raise it.sending_(503): sending is disabled for everyone for the moment. Retry after the seconds in thedisabled Retry-Afterheader.monthly_(429): wait untilcap_ reached resetsAt, or have an administrator of your account raise the cap under Account › Usage. Limits says how far they can raise it.- A 5xx status: retry with a growing delay, under the same idempotency key so the message cannot go twice.
- Any other code: read its meaning in the table below. Most need a fix to the request or the account, and fail the same way if sent again unchanged.
On rate_ and monthly_, scope says whose limit it is: the account’s (account), the server’s own (server) or the test servers’ (test). Test mail never counts toward the account’s monthly cap. A webhook can warn you before the cap is used up.
The SDK throws SendoraError for every failed call. It has the same code, the HTTP status and the body’s extra fields, such as issues, retryAfter, scope, limit, cap, used, resetsAt, suppressed and existingId. retryable says whether trying again could succeed. A lost connection or a timeout is the same error, with connection_ or timeout and no status.
The SDK retries rate limits, sending_ and server errors itself for a few seconds. If retryAfter is longer than that, it throws at once so you can schedule the retry.
The SDK raises a SendoraError for every failed call. Its class depends on the status, such as RateLimitError for 429. It has the same code, the HTTP status and the body’s extra fields, such as issues, retry_, scope, limit, cap, used, resets_, suppressed and existing_. retryable says whether trying again could succeed. A lost connection is an APIConnectionError with connection_, and a timeout an APITimeoutError with timeout, both without a status.
The SDK retries rate limits, sending_ and server errors itself for a few seconds. If retry_ is longer than that, it raises at once so you can schedule the retry.
When an account cannot send
payment_(402): the account has no active payment, for instance before a card is saved. Activate payment under Account › Billing in the dashboard. Every send from a live server fails until then.required account_(403): Sendora has not approved the account yet. Every account is reviewed by hand before a live server can send. A test server works before that.not_ active account_(403): Sendora has paused the account, for instance after a failed payment. Support tells you why. A pause for an unpaid subscription lifts once you save a working card under Account › Billing.paused
Over SMTP, the same refusals arrive as SMTP replies, which SMTP submission lists.
Error codes
| Code | Status | Meaning |
|---|---|---|
account_ | 403 | The account is closed, or not yet approved for a live server's sends or an inbound stream. |
account_ | 403 | The account is paused by Sendora. |
broadcast_ | 409 | The broadcast is completed or cancelled already; nothing is left to cancel. |
content_ | 410 | The content of this received message is gone; the stream’s content window has passed. The message itself stays 13 months. |
content_ | 409 | The stored content of this received message cannot be opened. Sendora has been told. |
default_ | 409 | The default stream of a server cannot be archived. |
domain_ | 409 | The account already has that domain. |
domain_ | 400 | The name is Sendora’s own, or a return-path host; no account can receive on it. |
from_ | 422 | The From domain is not a verified sending domain of this server. |
idempotency_ | 422 | The Idempotency-Key was already used for a different request. |
idempotency_ | 400 | Batch sends need an Idempotency-Key header. |
inbound_ | 409 | The stream already has a domain, or another account holds the name verified. |
inbound_ | 409 | A server has one inbound stream at a time; archive it to make another. |
invalid_ | 400 | The body, the query or a header does not match what the route takes. |
last_ | 409 | The only live secret of a webhook cannot be deleted; create another first. |
last_ | 409 | This is the only live key of the server; create another before revoking it. |
list_ | 422 | On a broadcast stream Sendora writes the List-Unsubscribe pair itself, so a message may not carry one. |
mode_ | 400 | A server’s mode is fixed when it is created; create a new server for the other mode. |
monthly_ | 429 | The monthly cap of the account, the server or the test servers is used up. |
not_ | 404 | No such broadcast of this server. |
payment_ | 402 | The account has no active subscription. |
rate_ | 429 | More was sent within a minute than the limit allows. |
recipient_ | 422 | One or more recipients are on the suppression list of the stream. |
request_ | 413 | The body exceeds 10 MB. |
secret_ | 409 | The webhook already holds two live secrets: one in use and one to roll to. Delete one before creating another. |
sending_ | 503 | Sending is disabled for everyone for the moment; retry after the seconds in Retry-After. |
server_ | 409 | The account already has a server with that name. |
server_ | 409 | Messages of the server are still being delivered; try again once they have left. |
server_ | 409 | The account has as many servers as it may; Sendora raises the cap on request. |
server_ | 409 | This server sends Sendora’s own sign-in mail and cannot be renamed or removed. |
spam_ | 403 | The recipient reported a message as spam; only Sendora support lifts that, at the recipient’s own request. |
stream_ | 422 | The stream is archived and takes no new messages. |
stream_ | 409 | The server already has a stream with this name, archived or not. |
stream_ | 422 | A test server has no inbound stream; receive on a live server. |
stream_ | 422 | A broadcast goes on a broadcast stream; the streamId names a transactional one. |
stream_ | 422 | The streamId names no stream of this server. |
stream_ | 422 | An inbound stream receives mail; it takes no messages and has no suppression list. Name a transactional or broadcast stream. |
stream_ | 422 | Sendora has paused the stream after complaints; it takes no messages until support has resumed it. |
substitution_ | 422 | The subject, text or HTML names a {{ key }} that a message does not give. |
test_ | 422 | Addresses at simulator.sendora.se act out an outcome on a test server; a live server never sends to them. |
token_ | 409 | The server or the account already holds two live keys: one in use and one to rotate to. Revoke one before creating another. |
unauthorized | 401 | The key is missing, malformed or revoked. |
unsubscribe_ | 403 | The recipient unsubscribed themselves; only Sendora support lifts that, at the recipient’s own request. |
unsubscribe_ | 422 | A message on a broadcast stream must carry {{ unsubscribe_url }} in every part it has. |
webhook_ | 409 | The server already has a webhook for that URL. |
wrong_ | 403 | The key is of the other kind: a server key (sk_) where an account key (ak_) is needed, or the reverse. The message names the kind the operation takes. |