Reference

Errors

The error envelope, status codes, and every stable error code.

Every error is JSON with a stable, machine-readable error code and the matching HTTP status. No stack traces, no surprises.

Error envelope
{ "error": "validation_failed", "detail": "at least one recipient is required" }

error is always present. detail is an optional human-readable elaboration. Some codes carry extra context fields (field, max, limit, status, alias, …) documented on the operation that returns them.

Status codes

StatusMeaning
400Malformed JSON body (invalid_json)
401Missing, unknown, or revoked key (unauthorized)
402Plan limit reached — contacts, webhooks (contact_limit_reached, webhook_limit_reached)
403Authenticated but not permitted (insufficient_scope — key scope, domain scope)
404Not found — tenant-scoped, never distinguishes "doesn't exist" from "not yours" (not_found)
409Conflicting state transition (not_draft, not_editable, not_cancelable, alias_exists, …)
422Validation failure (validation_failed, invalid_email, subject_required, from_domain_not_verified, template_not_found, …)
429rate_limit_exceeded or quota_exceeded — see Rate limits
5xxSomething broke on our side — safe to retry with an Idempotency-Key

Common codes on the send path

CodeStatusMeaning
unauthorized401No/unknown API key
insufficient_scope403sending_access key used on a management route
from_domain_not_verified422from domain not verified (or key scoped to another domain)
validation_failed422Payload failed a rule — detail says which (empty subject/body, bad recipient, …)
template_not_found422Unknown template_alias
scheduled_at_must_be_in_the_future422scheduled_at in the past
missing_field422A required field is absent (field names it)
rate_limit_exceeded429Per-minute burst limit (Retry-After included)
quota_exceeded429Daily send quota used up (Retry-After included)
idempotent_replay_failed—The stored result for this Idempotency-Key could not be replayed

A suppressed recipient is not an error: the send returns 200 { "status": "suppressed" } and nothing is sent.

Retrying errors

  • 429 — honour Retry-After, then retry with the same Idempotency-Key.
  • 5xx / timeouts — retry with the same key; the replay returns the original result without re-sending or re-consuming quota.
  • 4xx — fix the request. Retrying unchanged just repeats the failure. A rejected send refunds any quota unit it consumed, so a bug here costs you requests, not mail.

See also: Rate limits & quotas and the API reference for per-endpoint responses.

On this page