Create temporary inboxes and read incoming mail programmatically. Built for QA, CI/CD pipelines, and automated signup testing. Official SDKs for Node and Python, an MCP server for AI assistants, and a free tier that needs no signup at all.
See plans and how many Founders slots are left βNo signup, no API key needed to start. Create an inbox, then read its messages. That's the whole flow.
curl -X POST https://api.best-tempmail.com/v1/inboxescurl https://api.best-tempmail.com/v1/inboxes/[email protected]/messagesThat's it. Inboxes created via the API stay live for 2 hours and receive real email instantly through the same infrastructure that powers the website. Poll the messages endpoint to watch for incoming mail.
Official clients for Node and Python, plus an MCP server so an AI assistant can use the API directly. All open source and free: what you can do through them depends on the plan your key is on.
npm install best-tempmailpip install best-tempmailLets an assistant create inboxes, wait for mail, and read verification codes on your behalf. Add it to any MCP host such as Claude Desktop, Cursor or VS Code.
npx -y best-tempmail-mcpA machine-readable description of every endpoint lives at https://api.best-tempmail.com/v1/openapi.json. Import it into Postman or Insomnia to have every call ready to run, or use it to generate a client in a language we do not ship an SDK for.
The free tier requires no authentication at all. Just call the API. Paid plans (for higher limits) use an API key sent in a header.
To use a paid plan, include your key in the x-api-key header on every request:
curl https://api.best-tempmail.com/v1/inboxes \
-X POST \
-H "x-api-key: btm_sk_live_your_key_here"Keep your key safe. Treat it like a password. You get your key instantly after subscribing, with no account needed. Lost it? Recover it with your purchase email on the recover page.
An inbox created with an API key belongs to that key. Only that key can read it, wait on it, extract codes from it, or delete it. Any other caller gets a 404, identical to the response for an address that never existed.
That last detail is deliberate. A 403 would confirm the address exists and belongs to somebody, which would let anyone probe for live addresses. A 404 tells them nothing.
It matters most when you choose your own usernames. An inbox called [email protected] is easy to guess, and without ownership checks anyone could read the verification codes arriving in it.
Free inboxes are created without a key, so there is no key to check them against and they stay readable by anyone who knows the address. In practice that is not exploitable, because free callers only ever receive random addresses like [email protected]. But if you are testing anything sensitive, or choosing your own usernames, use a paid key and the inbox is private to you.
Start free with no signup at all. Paid plans add a higher rate limit and commercial use. Limits are per hour, with separate burst protection.
| Capability | Free | Founders / Developer | Pro |
|---|---|---|---|
| Price | $0 | $19.99/yr or $19.99/mo | $29.99/mo |
| Requests per hour | 150 | 2,000 | 5,000 |
| Burst | 100 / 10s | 300 / 10s | 300 / 10s |
| Inbox creation | 3 / day per IP | Unlimited | Unlimited |
| Inbox lifetime (default) | 2 hours | 2 hours | 24 hours |
| Inbox lifetime (maximum) | 2 hours | 7 days | 30 days |
| Polling, wait, WebSocket | Yes | Yes | Yes |
| Webhooks | No | Yes | Yes |
| OTP extraction | No | Yes | Yes |
| Attachment downloads | No | No | Yes |
| Concurrent waits | 5 | 5 | 20 |
| API key | Not required | Required | Required |
Founders is limited to the first 100 developers, with the same limits as Developer, billed yearly instead of monthly, and your rate stays locked while your subscription is active.
When you exceed your hourly limit, the API returns a 429 with an upgrade link. Free-tier inbox creation is capped at 3 per day per IP.
Response HeadersRead these headers to self-throttle before you hit a limit. Present on every response.
| Header | Meaning |
|---|---|
| X-RateLimit-Limit | Your plan's hourly request limit |
| X-RateLimit-Remaining | Requests remaining in the current hour |
| X-RateLimit-Reset | Unix timestamp when the window resets |
| X-Request-ID | Unique ID for the request (quote it in support emails) |
| X-API-Version | The API version that served the request |
All endpoints live under https://api.best-tempmail.com/v1 and return JSON. Paid plans send the x-api-key header; examples below show the free (keyless) form.
/v1/inboxesCreate a new inbox. Every field is optional: omit them all for a random address on a random domain, living for the default time.
lifetime_minutes sets how long the inbox lives, capped at your plan's maximum: 2 hours on Free, 7 days on Founders and Developer, 30 days on Pro. Defaults to 2 hours, or 24 hours on Pro.
Asking for longer than your plan allows does not fail. The inbox is created at the maximum and the response carries a note saying so, because a request that silently produced a 2-hour inbox would fail a test days later with nothing to explain why.
Long lifetimes exist for mail that does not arrive immediately: trial-expiry notices, weekly digests, and follow-up sequences that land days after the signup that triggered them.
curl -X POST https://api.best-tempmail.com/v1/inboxes \
-H "Content-Type: application/json" \
-d '{"username":"myprefix","domain":"alagen.site","lifetime_minutes":10080}'{
"success": true,
"address": "[email protected]",
"created_at": "2026-09-14 08:00:00",
"expires_at": "2026-09-21 08:00:00",
"lifetime_minutes": 10080
}/v1/inboxes/{address}/messagesList all messages in an inbox (summaries). Poll this to watch for incoming mail.
curl https://api.best-tempmail.com/v1/inboxes/[email protected]/messages{
"success": true,
"address": "[email protected]",
"messages": [
{
"id": "a1b2c3d4e5f6a7b8",
"from": "[email protected]",
"subject": "Your verification code",
"date": "2026-07-04T20:01:00.000Z",
"has_attachments": false
}
]
}/v1/inboxes/{address}/messages/{id}Read one full message, including body text and HTML. Scoped to the inbox for security: you must know both the address and the message ID.
curl https://api.best-tempmail.com/v1/inboxes/[email protected]/messages/a1b2c3d4e5f6a7b8{
"success": true,
"message": {
"id": "a1b2c3d4e5f6a7b8",
"from": "[email protected]",
"to": "[email protected]",
"subject": "Your verification code",
"date": "2026-07-04T20:01:00.000Z",
"text": "Your code is 123456",
"html": "<p>Your code is 123456</p>",
"attachments": []
}
}/v1/inboxes/{address}Get metadata about an inbox: when it was created, when it expires, and how many messages it holds.
curl https://api.best-tempmail.com/v1/inboxes/[email protected]{
"success": true,
"address": "[email protected]",
"created_at": "2026-07-04 20:00:00",
"expires_at": "2026-07-04 22:00:00",
"message_count": 1
}/v1/inboxes/{address}Delete an inbox and stop it from receiving mail.
curl -X DELETE https://api.best-tempmail.com/v1/inboxes/[email protected]{
"success": true,
"address": "[email protected]",
"deleted": true
}/v1/domainsList the available inbox domains. Fetch this instead of hardcoding domains. The list can change over time, and this keeps your code working.
curl https://api.best-tempmail.com/v1/domains{
"domains": ["alagen.site", "dextde.site"]
}/v1/statsService statistics and the current domain list.
curl https://api.best-tempmail.com/v1/stats{
"active_inboxes": 42,
"total_inboxes_created": 12345,
"domains": ["dextde.site", "linsal.site", "martaz.site", "simtim.site", "alagen.site"],
"api_version": "1",
"time": "2026-07-04T20:00:00.000Z",
"status": "ok"
}/v1/healthLightweight connectivity check. Use it to confirm the API is reachable.
curl https://api.best-tempmail.com/v1/health{
"status": "ok",
"version": "1",
"time": "2026-07-04T20:00:00.000Z"
}/v1/inboxes/{address}/waitHolds the connection open until mail arrives or the timeout expires, replacing a polling loop with a single call. A timeout is not an error: it returns 200 with message: null and timed_out: true, so you can loop again without treating it as a failure. Default 30 seconds, maximum 55. Pass since with a message id to resume from a known point. Counts as one request no matter how long it waits, which makes it cheaper than polling.
curl "https://api.best-tempmail.com/v1/inboxes/[email protected]/wait?timeout=55"{
"success": true,
"address": "[email protected]",
"message": {
"id": "a1b2c3d4e5f6a7b8",
"from": ""Service" <[email protected]>",
"subject": "Your verification code",
"date": "2026-09-08T12:00:00.000Z",
"has_attachments": false
}
}/v1/inboxes/{address}/messages/{id}/otpPaid plans Extracts the verification code so you do not have to write a parser for every sender's format. Candidates are scored on the words around them, their length and position. When nothing scores highly enough, code is null rather than a guess: a wrong code fails a test in a way that is hard to trace. Check candidates if confidence is low.
curl "https://api.best-tempmail.com/v1/inboxes/[email protected]/messages/a1b2c3d4/otp" \
-H "x-api-key: btm_sk_live_..."{
"success": true,
"message_id": "a1b2c3d4e5f6a7b8",
"code": "889231",
"confidence": "high",
"candidates": [
{ "code": "889231", "score": 8 },
{ "code": "293679", "score": 2 }
]
}/v1/inboxes/{address}/messages/{id}/attachments/{index}Pro only Returns the raw file, so curl -O and browsers save it correctly. Attachments are addressed by index, not by id, matching their order in the message's attachments array. Attachment metadata is visible on every plan; this endpoint fetches the bytes. Files above 4 MB return 413, though in practice nothing reaches that: the mail server accepts messages up to 5 MB and base64 inflates binary data by about a third.
curl -O -J "https://api.best-tempmail.com/v1/inboxes/[email protected]/messages/a1b2c3d4/attachments/0" \
-H "x-api-key: btm_sk_live_..."Binary file with:
Content-Type: application/pdf
Content-Disposition: attachment; filename="invoice.pdf"Rather than asking us for mail, have it pushed to your own server the moment it arrives. One URL per key. Registering again replaces it and issues a new signing secret, which is how you rotate that secret.
/v1/webhooksPaid plans The URL must use https and point to a public host. Private and loopback addresses are refused, since otherwise this endpoint could be used to make our servers call their own internals.
curl -X POST https://api.best-tempmail.com/v1/webhooks \
-H "x-api-key: btm_sk_live_..." \
-H "Content-Type: application/json" \
-d '{"url":"https://your-server.com/hooks/mail"}'{
"success": true,
"url": "https://your-server.com/hooks/mail",
"secret": "whsec_...",
"note": "Store this secret. It is shown once."
}Each POST carries X-BTM-Signature (as v1,<base64>) and X-BTM-Timestamp. Compute base64(HMAC_SHA256(secret, timestamp + "." + rawBody)) and compare. Use the raw body: re-serialising a parsed object changes the bytes and the signature will never match. Without this check, anyone who learns your URL could feed your application verification codes of their choosing. Both SDKs include a helper that does it correctly.
# payload posted to your URL
{
"event": "message.received",
"timestamp": 1788770115,
"address": "[email protected]",
"message": {
"id": "a1b2c3d4e5f6a7b8",
"from": ""Service" <[email protected]>",
"subject": "Your verification code",
"date": "2026-09-08T12:00:00.000Z",
"has_attachments": false
}
}/v1/webhooksPaid plans Current registration plus the last delivery attempts, so you can debug your own endpoint without asking us what we saw. Failed deliveries are retried three times with growing gaps; after repeated failures across many messages the webhook is disabled, and registering again re-enables it.
curl https://api.best-tempmail.com/v1/webhooks -H "x-api-key: btm_sk_live_..."{
"success": true,
"webhook": {
"url": "https://your-server.com/hooks/mail",
"status": "active",
"consecutive_failures": 0
},
"recent_deliveries": [
{ "attempt": 1, "status_code": 200, "error": null }
]
}/v1/webhooksPaid plans Stop sending webhooks.
curl -X DELETE https://api.best-tempmail.com/v1/webhooks -H "x-api-key: btm_sk_live_..."{ "success": true, "removed": true }Errors return a JSON body with an error message and the appropriate HTTP status.
| Status | When it happens |
|---|---|
| 400 | Bad request: malformed address, username, or domain |
| 401 | Invalid or inactive API key |
| 403 | Your IP is in a temporary automatic cooldown (abuse protection) |
| 402 | Your plan does not include this capability. The body names the plan needed and links to pricing. Retrying will not help |
| 404 | Inbox or message not found (or expired) |
| 413 | Attachment is too large to serve. The body reports its size and the ceiling |
| 429 | Rate limit exceeded: hourly quota, burst, or too many concurrent waits. Includes an upgrade link |
| 503 | Service momentarily at capacity, retry shortly |
The free tier is enough to evaluate everything. When you're ready for more, Founders unlocks 2,000 requests/hour, webhooks and OTP extraction for $19.99 a year, limited to the first 100 developers. Pro adds attachment downloads and 24-hour inboxes.
View Pricing βManage SubscriptionRefund PolicyTerms of ServicePrivacy PolicySupport
The Best-TempMail API is listed on developer directories, API catalogues, and launch platforms across the web.