REST API v1

Developer REST API Documentation

Programmatically create disposable inboxes, extract OTP codes or magic links, list messages, and register webhooks. Data endpoints require an active Full Access plan — see Pricing. Key and webhook management works from any account.

Where teams actually use this API

CI/CD signup & registration tests

Spin up a fresh inbox per test run in Selenium, Cypress, or Playwright, complete a real signup flow end-to-end including OTP verification, then tear the alias down — no shared test account to get rate-limited or locked out.

QA teams verifying transactional email

Confirm a welcome email, password-reset flow, or notification actually renders correctly and arrives promptly — list messages to inspect full content, not just the extracted code.

AI agents that need to "own" an inbox

An autonomous agent signing up for a third-party tool on your behalf needs somewhere to receive its own OTP without a human relaying it — the MCP server exposes exactly this API as agent tools.

Load and synthetic-monitoring scripts

Scripts that repeatedly exercise a signup or verification endpoint to catch regressions need disposable, rate-limit-safe addresses on every run rather than reusing (and eventually burning out) one real mailbox.

Webhook-driven backend integrations

Register a webhook once and have your own backend get notified the instant mail arrives on any of your aliases — no polling loop to maintain, and the HMAC signature lets you verify deliveries without exposing your API key to the receiving endpoint.

Bulk account provisioning for internal tooling

Internal scripts that need to create several throwaway accounts on a third-party SaaS tool (staging environments, sandboxed integrations) can generate a fresh, working inbox per account from a single script instead of doing it by hand.

1. Authentication

Authenticate every data-endpoint request with your secret API key in the X-API-Key header. Generate a key from your dashboard, or via the key-management endpoints below — the raw key is shown exactly once, at creation, and never again.

X-API-Key: zephbox_9f87a6b5c4d3e2f10987

Free accounts may hold 1 active key at a time (expires after 7 days); Full Access accounts get up to 5 (expires after 30 days, matching the billing cycle). Revoke a key any time — revocation is immediate and can't be undone from the same key.

Code example:

2. Inboxes

POST/api/developers/aliases/

Creates a new disposable inbox for your account. No request body needed.

curl -X POST "https://api.zephbox.com/api/developers/aliases/" \
  -H "X-API-Key: YOUR_API_KEY"
        
const res = await fetch('https://api.zephbox.com/api/developers/aliases/', {
  method: 'POST',
  headers: { 'X-API-Key': 'YOUR_API_KEY' }
});
const alias = await res.json();
console.log('Address:', alias.email);
        
import requests

headers = {'X-API-Key': 'YOUR_API_KEY'}
res = requests.post('https://api.zephbox.com/api/developers/aliases/', headers=headers)
print(res.json()['email'])
        

Response — 201 Created

{
  "id": 4821,
  "alias": "x7k2p9",
  "email": "[email protected]",
  "is_expired": false,
  "time_remaining": 86400,
  "message_count": 0
}
        

403 if your account doesn't have an active Full Access plan; 400 if the pool has no capacity right now (rare, retry shortly).

GET/api/developers/aliases/{alias}/messages/

Lists every message received by an inbox, most recent first — use this when you need more than just the latest OTP, e.g. to render a full inbox view or audit everything an alias received.

curl -X GET "https://api.zephbox.com/api/developers/aliases/x7k2p9/messages/" \
  -H "X-API-Key: YOUR_API_KEY"
        
const res = await fetch('https://api.zephbox.com/api/developers/aliases/x7k2p9/messages/', {
  headers: { 'X-API-Key': 'YOUR_API_KEY' }
});
const messages = await res.json();
        
res = requests.get('https://api.zephbox.com/api/developers/aliases/x7k2p9/messages/', headers=headers)
messages = res.json()
        

Response — 200 OK

[
  {
    "message_id": 91823,
    "subject": "Your verification code",
    "sender": "[email protected]",
    "received_at": "2026-08-29T10:15:00Z"
  }
]
        
DELETE/api/developers/aliases/{alias}/

Deactivates an inbox immediately instead of waiting for its natural expiry — useful for cleaning up test aliases at the end of a CI run rather than letting the pool fill up with dead addresses.

curl -X DELETE "https://api.zephbox.com/api/developers/aliases/x7k2p9/" \
  -H "X-API-Key: YOUR_API_KEY"
      

Returns 204 No Content on success. This deletes the alias and its messages the same way natural expiry does — it's not recoverable.

3. Verification codes

GET/api/developers/aliases/{alias}/otp/

Extracts a verification code or magic link from the alias's most recent message. Returns the latest message with code/link set to null if nothing matched — never a bare 404 once mail has arrived.

curl -X GET "https://api.zephbox.com/api/developers/aliases/x7k2p9/otp/" \
  -H "X-API-Key: YOUR_API_KEY"
        
const res = await fetch('https://api.zephbox.com/api/developers/aliases/x7k2p9/otp/', {
  headers: { 'X-API-Key': 'YOUR_API_KEY' }
});
const { code, link } = await res.json();
console.log('Code:', code);
        
import requests

headers = {'X-API-Key': 'YOUR_API_KEY'}
res = requests.get('https://api.zephbox.com/api/developers/aliases/x7k2p9/otp/', headers=headers)
print(res.json()['code'])
        

Response — 200 OK

{
  "message_id": 91823,
  "subject": "Your verification code",
  "sender": "[email protected]",
  "received_at": "2026-08-29T10:15:00Z",
  "code": "482913",
  "link": null
}
        
GET/api/developers/aliases/{alias}/wait-for-otp/

Long-polls: blocks server-side (bounded, up to 20 seconds, default 15) until a new message arrives on this alias — one that arrives after the call starts, not one already sitting in the inbox — then returns its extracted code/link. Times out with 408 if nothing arrives in time. This is what you want for "trigger a signup, then wait for the OTP" rather than polling /otp/ in a loop.

curl -X GET "https://api.zephbox.com/api/developers/aliases/x7k2p9/wait-for-otp/?timeout=20" \
  -H "X-API-Key: YOUR_API_KEY"
      

Query param timeout (seconds, max 20) is optional. See our webhooks vs. polling guide for when to reach for this versus a webhook.

4. API key management

GETPOST/api/developers/api-keys/

These management endpoints authenticate with your regular account login (JWT/session from the dashboard), not an API key — an API key can't be used to manage other API keys. GET lists your keys (hashes never shown, only the prefix). POST creates one; the raw key appears exactly once in that response.

curl -X POST "https://api.zephbox.com/api/developers/api-keys/" \
  -H "Authorization: Bearer YOUR_JWT" \
  -H "Content-Type: application/json" \
  -d '{"name": "CI runner"}'
      
POST/api/developers/api-keys/{id}/revoke/

Revokes (doesn't delete the record of) a key — it stops authenticating immediately and can't be un-revoked.

5. Webhooks (Full Access)

GETPOST/api/developers/webhooks/

Register up to 5 endpoints per account (also authenticated via your regular login, not an API key). Once registered, every new message to any of your aliases triggers a POST to your URL with an X-Kmail-Signature header — an HMAC-SHA256 hex digest of the raw request body, signed with the endpoint's own secret, so you can verify the delivery genuinely came from zephbox before trusting it. Delivery auto-retries on failure and auto-disables an endpoint that keeps failing, so a dead URL doesn't silently eat your webhook budget forever.

curl -X POST "https://api.zephbox.com/api/developers/webhooks/" \
  -H "Authorization: Bearer YOUR_JWT" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://yourapp.example.com/webhooks/zephbox"}'
      
DELETE/api/developers/webhooks/{id}/

Removes a registered endpoint. zephbox refuses to register a webhook URL pointing at a private/internal address (SSRF protection) — use a real, publicly reachable endpoint.

Webhook, long-poll, or plain poll — which one?

Use a webhook if your own backend is reachable from the internet and you want push delivery with no wasted requests. Use wait-for-otp for a synchronous script or test that's actively waiting right now and would rather block briefly than manage a webhook receiver. Plain polling against /otp/ works too, but wastes requests against your rate limit compared to either of the above. See our webhooks vs. polling guide for the fuller comparison.

Automate all of this from Python without hand-rolling HTTP calls using the zephbox Python SDK, or wire zephbox directly into an AI agent via the MCP server.