Errors

One error envelope, one code per failure, a matching HTTP status.

Every 4xx and 5xx response uses the same envelope:

{
  "error": {
    "code": "invalid_request",
    "message": "Body must be JSON."
  }
}
  • code is stable and machine-readable — branch on it.
  • message is human-readable and may change.

Some send failures that were still logged include a message_id alongside code and message, so you can look the attempt up later.

Status codes

StatuscodeMeaning
400invalid_requestThe body failed validation (bad JSON, missing or malformed field).
401unauthorizedNo usable credential: missing header, or an invalid, revoked or expired key.
403forbiddenThe key is valid but not allowed here — its scope is too low, or it lacks the send grant. The body carries required_scope or required_grant, plus key_scope. See Authentication.
404template_not_foundNo template with that slug in this project.
404not_foundNo such message in this project.
409template_not_publishedThe template exists but has no published version.
409sends_pausedThe project's kill switch is on — no sends leave until it's cleared.
422suppressedThe recipient is on the suppression list (bounce, complaint, or manual block).
429daily_capThe project's daily send cap has been reached.
429monthly_capThe provider plan's monthly send limit has been reached.
429rate_limitedToo many requests in a short window. Retry after a short backoff.
502provider_errorThe email provider rejected the request.
500internalAn unexpected server error. Safe to retry with the same Idempotency-Key.

suppressed, sends_paused, daily_cap, and monthly_cap are policy outcomes, not bugs — the request was well-formed but the send was deliberately blocked. Handle them distinctly from invalid_request.

On this page