API Reference

Integrate mail.cx into your application to create temporary inboxes, receive emails, and handle real-time mailbox events via WebSocket.

Base URL

https://api.mail.cx/api

All API requests should be made to this base URL. HTTPS is required.

Authentication

All API requests require an API token sent via the x-api-token header. You can create tokens in your Dashboard under the Tokens page.

curl https://api.mail.cx/api/mailboxes \
  -H "x-api-token: tm_live_your_token_here"

Quick start

1. Create a mailbox:

curl -X POST https://api.mail.cx/api/mailboxes \
  -H "x-api-token: tm_live_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{"local_part":"myinbox","domain":"qabq.com"}'

2. List emails in the mailbox:

curl https://api.mail.cx/api/mailboxes/{mailbox_id}/emails \
  -H "x-api-token: tm_live_your_token_here"

3. Read a specific email (full content with body and attachments):

curl https://api.mail.cx/api/emails/{email_id} \
  -H "x-api-token: tm_live_your_token_here"

Rate limits

Rate limits are applied in two layers: per-IP globally (100 requests/second for all users), and per-user (across all tokens). Free and Pro users also have monthly Ops quotas based on received emails.

LimitFreePro
Per-user global85/min20/s
Monthly Ops quota1,500/mo200,000/mo

Authenticated requests include X-Ops-Limit and X-Ops-Remaining headers showing your monthly Ops usage. Rate limit 429 responses include a Retry-After header; Ops quota 429 responses do not (resets monthly).

What counts as an Op?

Ops is a monthly quota based on received emails:

  • Every email received by a registered user consumes 1 Op
  • API calls do not consume Ops
  • Webhook deliveries do not consume Ops
  • Anonymous users are not subject to Ops limits (IP-based rate limits apply instead)

Endpoints

Mailboxes

POST
/api/mailboxes

Create a new temporary mailbox

API token required
GET
/api/mailboxes/:id/emails

List emails in a mailbox

API token required
DELETE
/api/mailboxes/:id

Delete a mailbox and all its emails

API token required

Both fields are optional. If omitted, a random 6-character address on the default domain is generated.

ParameterRules
local_part3–20 chars, lowercase a–z 0–9 . _ - only. Cannot start or end with . _ or -. Some names are reserved (admin, postmaster, abuse, etc.).
domainDefaults to system domain. Authenticated users may specify a verified custom domain.

Emails

GET
/api/emails/:id

Get full email content (body, attachments, headers)

API token required
GET
/api/emails/:id/raw

Download the original .eml file

API token required
GET
/api/emails/:id/attachments/:index

Download an attachment by index (0-based)

API token required
DELETE
/api/emails/:id

Delete a single email

API token required

Tokens

POST
/api/tokens

Create a new API token

API token required
GET
/api/tokens

List your API tokens

API token required
DELETE
/api/tokens/:id

Revoke an API token

API token required

Domains (Pro)

POST
/api/domains

Add a custom domain

Pro plan required
GET
/api/domains

List your custom domains

Pro plan required
DELETE
/api/domains/:id

Remove a custom domain

Pro plan required

Domain Emails (Pro)

GET
/api/domain-emails?address=user@yourdomain.com

List emails for a specific address under your domain (no mailbox needed)

Pro plan required
GET
/api/domain-emails?domain=yourdomain.com

List all emails across your entire domain (no mailbox needed)

Pro plan required

Both endpoints support pagination via offset and limit query parameters. Default: 20 items per page, max 50. Response includes total count for building pagination.

GET /api/domain-emails?domain=yourdomain.com&offset=0&limit=20

// Response
{
  "emails": [...],
  "total": 142,
  "offset": 0,
  "limit": 20
}

Webhooks (Pro)

POST
/api/webhooks

Create a webhook endpoint

Pro plan required
GET
/api/webhooks

List your webhooks

Pro plan required
DELETE
/api/webhooks/:id

Delete a webhook

Pro plan required
POST
/api/webhooks/:id/rotate

Rotate webhook signing secret

Pro plan required
GET
/api/webhooks/:id/deliveries

View recent delivery attempts (last 20)

Pro plan required

Webhook guide

Webhooks send an HTTP POST to your URL whenever an email arrives. Use them to integrate mail.cx with your application in real time.

Payload format

Each delivery sends a JSON payload with signature headers. The payload includes email metadata — not the full email body. Use the email_id to fetch the complete email via GET /api/emails/:id.

POST https://your-server.com/webhook
Content-Type: application/json
X-Webhook-ID: evt_abc123
X-Webhook-Timestamp: 1709721600
X-Webhook-Signature: sha256=a1b2c3...

{
  "id": "evt_abc123",
  "type": "email.received",
  "created_at": "2024-03-06T12:00:00Z",
  "data": {
    "email_id": "uuid",
    "mailbox_id": "uuid",
    "address": "inbox@qabq.com",
    "from": "sender@example.com",
    "sender": "sender@example.com",
    "subject": "Your verification code",
    "preview_text": "Your code is 123456...",
    "size": 2048,
    "created_at": "2024-03-06T12:00:00Z"
  }
}

Verifying signatures

Every webhook request includes HMAC-SHA256 signature headers. Always verify the signature before processing the payload to ensure it came from mail.cx.

import hmac, hashlib

def verify_webhook(payload: bytes, timestamp: str, signature: str, secret: str) -> bool:
    message = f"{timestamp}.{payload.decode()}"
    expected = hmac.new(secret.encode(), message.encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)

Expected responses

Your endpoint should respond quickly. The system interprets your HTTP status code as follows:

Your responseWhat happens
2xxDelivery marked as successful. Failure count resets to 0.
4xxTreated as a failure. The delivery will be retried with exponential backoff.
5xxTreated as a failure. The delivery will be retried with exponential backoff.
Timeout (>5s)Connection aborted. Treated as a failure and retried.

Retry schedule

Failed deliveries are retried up to 5 times with exponential backoff: 15s, 1min, 5min, 10min, 20min. After 5 consecutive failures, the webhook status changes to "failing". Rotating the secret resets the failure count and restores the webhook to active.

Limits & requirements

Max webhooks per user1
Delivery rate limitNo per-user limit
Delivery timeout5s
Max retry attempts5
URL protocolHTTPS

Use GET /api/webhooks/:id/deliveries to view the last 20 delivery attempts, including HTTP status codes, errors, and response times — useful for debugging integration issues.

WebSocket

Connect to the WebSocket endpoint for real-time email notifications. Authenticate by sending an auth message as the first frame. The server sends ping frames every 30 seconds.

// Connect
const ws = new WebSocket("wss://api.mail.cx/api/ws");

// Authenticate (send as first message)
ws.send(JSON.stringify({
  type: "auth",
  token: "tm_live_your_token_here"
}));

// Receive new emails
ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  // { type: "new_email", data: { id, from, subject, mailbox_id } }
};

Errors

All errors return a JSON object with an error field:

{
  "error": "rate_limit_exceeded"
}
StatusDescription
400Bad request — invalid parameters
401Unauthorized — missing or invalid token
403Forbidden — insufficient permissions or account disabled
404Not found — resource does not exist
410Gone — email expired and was deleted
429Too many requests — rate limit exceeded

Security

  • All API traffic is encrypted via TLS (HTTPS required)
  • Tokens are stored as SHA-256 hashes — we never see your plaintext token
  • Webhook payloads are signed with HMAC-SHA256 for verification