API reference#
The Outbox API is REST over JSON. It mirrors the Resend API: the same paths, request bodies, response shapes, and error envelope. Any Resend SDK works against it by changing only the base URL.
Base URL#
Whatever host you deployed to:
https://outbox.example.comLocally that is http://localhost:3000. Unlike Resend there is no separate api.
hostname โ the API is served at the root and the dashboard lives under /app, so a base
URL swap is all an SDK needs.
Authentication#
Send your API key as a bearer token:
Authorization: Bearer ob_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxKeys are created in the dashboard or through the API and shown exactly once. Only a SHA-256 hash is stored, so a lost key cannot be recovered โ create a new one and delete the old.
Keys carry a permission:
full_accessโ every endpoint.sending_accessโPOST /emailsandPOST /emails/batchonly. Every other endpoint returns401 restricted_api_key.
A key may also be restricted to one domain, in which case it can only send from that domain.
User-Agent#
Every request must include a User-Agent. Requests without one are rejected:
{
"statusCode": 403,
"name": "invalid_user_agent",
"message": "The User-Agent header is required. Set it to identify your application, e.g. `my-app/1.0`."
}Every official SDK and most HTTP clients set this automatically. Bare curl does too.
Explicitly clearing it โ curl -H "User-Agent:" โ is what trips this.
Response codes#
| Status | Meaning |
|---|---|
200 | Success |
201 | Created |
400 | Malformed request or bad parameter |
401 | Missing key, or a restricted key on a forbidden endpoint |
403 | Invalid key, unverified sending domain, or missing User-Agent |
404 | Resource not found |
409 | Conflict โ a duplicate, or a concurrent idempotent request |
422 | Validation failed or a required field is missing |
429 | Rate limit exceeded |
5xx | Server error |
Errors#
Every error uses the same envelope:
{
"statusCode": 422,
"name": "missing_required_field",
"message": "Missing `subject` field."
}name is the stable machine-readable slug โ switch on it rather than parsing message.
See Errors for the full list.
Rate limits#
The default is 10 requests per second per team, shared across all of that team's API
keys, matching Resend's default. Change it with RATE_LIMIT_PER_SECOND.
Exceeding it returns 429 with the standard headers:
retry-after: 1
ratelimit-limit: 10
ratelimit-remaining: 0
ratelimit-reset: 1Back off and retry. A client that ignores 429s will drop requests.
Pagination#
List endpoints return a consistent envelope and use cursor pagination. See Pagination.
{
"object": "list",
"has_more": false,
"data": []
}Idempotency#
POST /emails and POST /emails/batch accept an Idempotency-Key header. Repeating a
request with the same key replays the original response instead of sending again โ see
Emails.
Endpoints#
| Group | Paths |
|---|---|
| Emails | /emails, /emails/batch, /emails/:id, /emails/receiving |
| Domains | /domains |
| API keys | /api-keys |
| Contacts | /contacts |
| Contact properties | /contact-properties |
| Segments | /segments, /audiences |
| Topics | /topics |
| Broadcasts | /broadcasts |
| Templates | /templates |
| Suppressions | /suppressions |
| Webhooks | /webhooks |
| Automations | /automations, /events/send |
| Metrics | /emails/metrics, /segments/metrics |
| Logs | /logs |