The api.email API is REST over HTTPS with JSON bodies. The base URL is https://api.email/v1.
Authentication
Send your API key as a bearer token on every request:
Authorization: Bearer ae_live_…
Keys are shown once when you create them and can be revoked at any time. Test keys work everywhere but never deliver email.
Errors
Errors use HTTP status codes and a consistent body:
{ "error": { "code": "domain_not_verified", "message": "acme.com is not verified", "hint": "Add the two CNAME records shown in the dashboard." } }
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request |
A field is missing or malformed; message names it. |
| 401 | unauthorized |
The key is missing, revoked or wrong. |
| 403 | domain_not_verified |
The from domain is not verified yet. |
| 404 | not_found |
The id does not exist in your account. |
| 429 | rate_limited |
Too many requests; retry after the Retry-After header. |
| 5xx | — | Temporary problem on our side; retry with backoff. |
Retry only 429 and 5xx, and reuse the same Idempotency-Key when you do.
Emails
POST /v1/emails sends an email. Fields are described in Sending email. Returns 200 {"id": "em_…", "status": "queued"}, or "scheduled" with scheduled_at.
GET /v1/emails lists recent emails, newest first. Filter with ?status=, ?to= or ?tag=.
GET /v1/emails/{id} returns one email:
{
"id": "em_8f2c1a",
"status": "delivered",
"from": "Acme <[email protected]>",
"to": ["[email protected]"],
"subject": "Reset your password",
"created_at": "2026-10-25T09:12:01Z",
"events": [
{ "type": "email.sent", "at": "2026-10-25T09:12:02Z" },
{ "type": "email.delivered", "at": "2026-10-25T09:12:04Z" }
]
}
Email status is one of queued, scheduled, sent, delivered, bounced, complained or canceled.
DELETE /v1/emails/{id} cancels a scheduled email that has not been sent yet.
Domains
POST /v1/domains with {"name": "acme.com"} adds a domain and returns its id, status and the two CNAME records to publish. Pass "return_path": "mail" to use a prefix other than send for the sending subdomain. GET /v1/domains lists your domains. GET /v1/domains/{id} returns the current verification status of each record. DELETE /v1/domains/{id} removes a domain; sending from it stops immediately.
Routes
POST /v1/routes with {"match": "[email protected]", "forward": "https://acme.com/hooks/inbound"} creates a route and returns {"id": "rt_…", "secret": "whsec_…"}. Deliveries from the route are signed with that secret, using the same scheme as webhooks. match takes an address or a catch-all like *@in.acme.com. GET /v1/routes lists routes; DELETE /v1/routes/{id} removes one.
Inbound messages
GET /v1/inbound lists recent email.received events, newest first. GET /v1/inbound/{id} returns one message with the same fields as the webhook payload. GET /v1/inbound/{id}/attachments/{n} downloads attachment number n (from 0) for 7 days after the message arrived.
Webhooks
POST /v1/webhooks with {"url": "...", "events": ["email.delivered", "email.received"]} creates an endpoint and returns {"id": "wh_…", "secret": "whsec_…"}. GET /v1/webhooks lists endpoints; DELETE /v1/webhooks/{id} removes one.
Pagination
List endpoints return up to 50 items with a next_cursor. Pass it as ?cursor= to get the next page; a missing next_cursor means you have reached the end.