OTPBox / Guides / Temp mail API
REST API · Free keyConsumer temp-mail sites are built for a person in a browser tab. A test suite, a script or an AI agent needs the same idea as an API: create a throwaway address, wait for the email, and get the one-time code back as JSON. OTPBox is that disposable email API. You can have a working key in one request, with no account and no card, and the whole round trip (create, wait, read, delete) is four calls.
curl -X POST https://otpbox.io/api/v1/keys/free
{ "id": "lic_...", "key": "...", "plan": "free", "quotaLimit": 200 }
key. It is shown once and can't be read back later.POST /api/v1/keys/sandbox mints a sandbox key the same way. With it, each new inbox already holds one synthesized message with a random 6-digit code, and it never receives real mail. See Get a key.Send the key as a bearer token on every other call. The examples below read it from $OTPBOX_KEY:
export OTPBOX_KEY=... # the "key" from the response above
curl -X POST https://otpbox.io/api/v1/inboxes \
-H "authorization: Bearer $OTPBOX_KEY" \
-H "content-type: application/json" \
-d '{}'
201 Created
{ "id": "a1b2c3d4e5f6", "address": "bold.quartz844@otpbox.io", "domain": "otpbox.io",
"createdAt": 1790000000000, "expiresAt": 1790003600000, "token": "..." }
The address can receive mail right away. Use it in whatever sign-up or login form you're testing. Pass "local" in the body to choose the part before the @ (409 address_unavailable if it's taken). An inbox expires 1 hour after creation by default, and you can delete it sooner.
Don't write a polling loop. Ask for the code with a timeout, and OTPBox holds the request open until a code arrives or the timeout passes:
curl "https://otpbox.io/api/v1/inboxes/a1b2c3d4e5f6/otp?timeout=20" \
-H "authorization: Bearer $OTPBOX_KEY"
{ "code": "482913", "messageId": "msg_...", "from": "noreply@example.com",
"subject": "Your verification code", "receivedAt": 1790000300000 }
timeout is in seconds, from 0 to 25. However long it waits, it's one metered request.404 no_otp with timedOut: true. Call again if you want to keep waiting.from or subject (literal, case-insensitive substrings) or since (epoch milliseconds) when an inbox gets more than one kind of mail.Plenty of flows email a link instead of a code. OTPBox extracts links too, and labels each one verification, password_reset, magic_login, unsubscribe, tracking or general:
curl "https://otpbox.io/api/v1/inboxes/a1b2c3d4e5f6/links?type=verification&timeout=20" \
-H "authorization: Bearer $OTPBOX_KEY"
{ "links": [ { "messageId": "msg_...", "url": "https://example.com/verify?t=...",
"host": "example.com", "type": "verification",
"from": "noreply@example.com", "subject": "Confirm your email",
"receivedAt": 1790000300000 } ] }
/links takes the same filters and timeout as /otp, plus type. If nothing matches, the list comes back empty. To read a whole message (text, sanitized HTML, attachments), call GET /api/v1/messages/:id with the messageId, or use POST /api/v1/inboxes/:id/wait to wait for the next full message. See Waiting for mail.
curl -X DELETE https://otpbox.io/api/v1/inboxes/a1b2c3d4e5f6 \
-H "authorization: Bearer $OTPBOX_KEY"
{ "ok": true }
The inbox and every message in it are deleted immediately. If you forget, it's removed when it expires anyway.
Plain fetch, built into Node 18 and later, with no package to install:
const API = 'https://otpbox.io/api/v1';
const headers = { authorization: `Bearer ${process.env.OTPBOX_KEY}` };
const inbox = await fetch(`${API}/inboxes`, {
method: 'POST',
headers: { ...headers, 'content-type': 'application/json' },
body: '{}',
}).then((r) => r.json());
console.log('Sign up with', inbox.address);
// ...trigger the email from the app you're testing...
const res = await fetch(`${API}/inboxes/${inbox.id}/otp?timeout=20`, { headers });
const otp = res.ok ? (await res.json()).code : null; // 404 no_otp if nothing arrived
await fetch(`${API}/inboxes/${inbox.id}`, { method: 'DELETE', headers });
Prefer a client library? otpbox-sdk on npm and otpbox on PyPI wrap the same endpoints. For a browser test, see the Playwright guide.
A consumer temp-mail site, OTPBox's own homepage inbox included, is a web page for a person. You open it, copy the address and read the email. That works when you're signing up by hand. It breaks down when code has to do it, and the usual workaround is to scrape the site. Here is what changes when the inbox is an API:
| Scraping a consumer temp-mail site | OTPBox temp mail API | |
|---|---|---|
| Interface | HTML meant for people, which can change without notice | Documented REST endpoints that return JSON |
| Access | Whatever the site allows, including any bot checks it adds | A bearer key, free with one request |
| Getting the code | Find it in the email body yourself | Already extracted, in a code field |
| Links | Pick the right href out of the HTML | Extracted and labeled (verification, magic_login, ...) |
| Waiting for mail | Reload and re-parse in a loop | Server-side wait of up to 25 s, one request |
| Push notifications | Usually none | Signed webhooks (otp.extracted, link.detected, ...) |
| AI agents | The agent has to drive the web page | An MCP server with 13 tools |
| Cleanup | Depends on the site | DELETE the inbox, or it expires 1 hour after creation |
For a feature-by-feature look at one well-known consumer site, see OTPBox vs. Temp-Mail.org. For developer test-email tools, see OTPBox vs. Mailinator vs. Mailosaur, vs. Mailosaur and vs. MailSlurp.
message.received, otp.extracted or link.detected and get a POST signed with HMAC-SHA256 instead of waiting on a request. See Webhooks.https://otpbox.io/mcp, so an agent can create an inbox and read the code mid-task. See the email MCP server guide.POST /api/v1/batches creates up to 50 inboxes in one call. See Batches.POST /api/v1/identities returns a synthetic persona (name, country, profile) backed by a real inbox. See Test identities.Idempotency-Key header on POST /api/v1/inboxes so a retried create doesn't make a second inbox. See Idempotency keys.| Plan | Requests / month | Price |
|---|---|---|
| Personal free key | 200 per key | $0, no account |
| Organization Free | 200, pooled across keys | $0 |
| Organization Pro | 5,000, pooled across keys | $9 / month |
| Enterprise | Custom | Custom |
Going over the quota returns 429 quota_exceeded. Overage is never charged; you upgrade or wait for the next cycle. GET /api/v1/usage shows where a key stands. Details are on the pricing page.
OTPBox only receives mail and can't send it. Some services block known disposable-email domains, so the API works best for testing sign-up and login flows you control.
Sign up, mint a key, and the dashboard shows your first code arriving live. Try it in the dashboard
Rather skip the account? curl -X POST https://otpbox.io/api/v1/keys/free gives you a free key with 200 requests a month.