Errors & limits
Errors return JSON with a human message and a stable code: { "error": "...", "code": "quota_exceeded" }. Handle codes, not messages.
Error codes
| Status | Code | Meaning |
|---|
| 401 | invalid key | The API key is missing, malformed, or revoked. |
| 402 | billing_required | Production sending needs an active plan. |
| 403 | quota_exceeded | Monthly quota (or the pay-as-you-go safety ceiling) reached. |
| 403 | account_paused | The deliverability autopilot paused sending — check Metrics. |
| 403 | attachments_require_paid | Production attachments are a paid-plan feature. |
| 403 | contact_limit_reached | Your plan's contact allowance is full. |
| 409 | domain_not_ready | The from-domain isn't verified yet. |
| 409 | recipient_suppressed | A recipient is on your suppression list. |
| 409 | broadcast_not_draft | Broadcasts can only be sent once. |
| 422 | invalid_payload | Validation failed — the error message says which field. |
| 422 | mixed_simulation | Simulator and real recipients can't share one send. |
| 429 | daily_limit_reached | Warm-up ramp or plan daily cap hit; limits grow automatically. |
| 429 | rate_limited | Too many requests — respect Retry-After. |
Limits
| Recipients per message | 10 across to/cc/bcc |
| Batch size | 100 emails per call |
| Content size | html ≤ 1MB, text ≤ 500KB, attachments ~5MB decoded total |
| API rate | 120 requests/min per key on send (30/min on the Free tier); Retry-After on 429 |
| Idempotency keys | ≤ 256 chars, replay returns the original result |
| Overage | Paid plans keep sending past quota at $0.50/1k up to a 10x safety ceiling — no hard cutoff |