API reference

Errors and limits

The error format, what each status code means, the rate limit, plan volumes and how to retry safely.

Error format

Every error answers with a non-2xx status and a JSON body:

{
  "error": true,
  "url": "/api/emails",
  "statusCode": 422,
  "statusMessage": "Suppressed after a bounce, complaint or unsubscribe, so not sent: ada@example.com",
  "message": "Suppressed after a bounce, complaint or unsubscribe, so not sent: ada@example.com"
}
statusCode
number
The HTTP status, repeated in the body.
statusMessage
string
A short description of what went wrong.
message
string
A human-readable explanation. For unexpected server errors it is only Server Error, so no internals leak.

Branch on statusCode in your code, and log message for the person debugging it.

Status codes

StatusMeaning hereRetry?
400 Bad RequestThe request is malformed: invalid JSON, a missing or invalid address, or content that breaks the rules of Send email, such as templateId and html in the same request.No. Fix the request.
401 UnauthorizedThe API key is missing, not sent as Bearer <key>, unknown or revoked. See Authentication.No. Fix the key.
403 ForbiddenAuthenticated, but not allowed to do this. In the dashboard this is a team role that does not permit the action, such as a Developer creating an API key.No.
404 Not FoundThe template or email does not exist in this workspace, or the URL is wrong.No.
409 ConflictThe request clashes with what already exists, for example adding a domain the workspace already has.No.
422 Unprocessable EntityThe request is well formed but cannot be sent: the from domain is not verified in this workspace, or a recipient is on your suppression list.No. Change the sender or the recipient.
429 Too Many RequestsYou hit the rate limit or your plan's monthly volume.After Retry-After, or after the monthly volume resets or you upgrade.
500 Internal Server ErrorSomething failed on our side.Yes, with backoff.
502 Bad GatewayAmazon SES rejected the message.Yes, with backoff.
503 Service UnavailableA dependency is temporarily unavailable.Yes, with backoff.

Rate limit

Each API key can make 10 requests per second. A request over the limit answers 429 with a Retry-After header that says how many seconds to wait before trying again:

HTTP/1.1 429 Too Many Requests
Retry-After: 1
Content-Type: application/json

Spread bursts out with a queue in your application rather than retrying in a tight loop. Every request counts, including Retrieve email calls, so prefer webhooks to polling.

Monthly volume

Every plan includes a number of emails per month. Once you reach your plan's volume, sending answers 429 until the volume resets or you move to a larger plan.

PlanEmails per month
Free3,000
Starter25,000
Pro75,000
Business250,000
Scale750,000
Enterprise1,000,000 or more

Prices and features are on the pricing page.

Retries

Retry only what can succeed on a second attempt: 429 and 5xx responses, and requests that failed in the network before any response arrived.

  1. Send every email with an Idempotency-Key, and keep the same key across retries. A retry then cannot send the email twice, even when the first attempt reached us.
  2. On 429, wait for Retry-After seconds.
  3. On 5xx or a network error, back off exponentially with jitter: about 1, 2, 4, 8 seconds, up to a ceiling you choose.
  4. Give up after a few attempts and record the failure so a person can look at it.

Never retry 400, 401, 403, 404 or 422 unchanged. The same request gets the same answer.