Disposable inboxes, over HTTP.
Five endpoints. Bearer-token auth, JSON in and out, no SDK required. Free, with the same limits as everything else.
Base URL
https://zenix-tempmail.vercel.app/api/v1Authentication
Authorization: Bearer <key>Generate a key in Settings and it will be filled into every example on this page.
curl "https://zenix-tempmail.vercel.app/api/v1/domains?limit=3" \
-H "Authorization: Bearer YOUR_API_KEY"/api/v1/statusno key neededService status
Which upstream providers are answering right now, and how many of them. The only endpoint that does not need a key.
Response
{
"success": true,
"data": {
"services": {
"mail.tm": { "id": "mail.tm", "isAvailable": true },
"maildrop.cc": { "id": "maildrop.cc", "isAvailable": true }
},
"availableServices": 7,
"totalServices": 11,
"uptime": "3d 4h 12m"
}
}/api/v1/domainsList domains
Every domain your key can use, including any private domain you own. Paginated by cursor.
Query
servicestring- Only domains backed by this provider, e.g. mail.tm.
statusstring- Filter by provider status, e.g. active.
limitnumber- Page size.
cursorstring- nextCursor from the previous page.
Response
{
"success": true,
"data": {
"domains": [
{ "domain": "maildrop.cc", "service": "maildrop.cc", "status": "active" }
],
"services": ["mail.tm", "maildrop.cc"],
"totalDomains": 94,
"nextCursor": "eyJpZCI6..."
}
}/api/v1/inboxesCreate an inbox
Mint an address. Send an empty body and one is chosen for you; name the parts you care about and the rest is filled in.
Body
usernamestring- 3–64 chars, starting alphanumeric. Random if omitted.
domainstring- A domain from the list endpoint. Chosen for you if omitted.
servicestring- Pin the provider instead of the domain.
Response
{
"success": true,
"data": {
"email": "o5su1l2h8i@maildrop.cc",
"username": "o5su1l2h8i",
"domain": "maildrop.cc",
"service": "maildrop.cc",
"created": "2026-09-07T15:21:17.387Z",
"expires": "2026-09-08T15:21:17.387Z"
}
}/api/v1/messagesRead an inbox
Everything sitting in an address. Poll this; there are no webhooks yet.
Query
emailstringrequired- The full address to read.
passwordstring- Only for providers that issue one at creation.
Response
{
"success": true,
"service": "maildrop.cc",
"data": {
"messages": [
{
"id": "msg_01H...",
"from": "noreply@example.com",
"subject": "Your verification code",
"date": "2026-09-07T15:24:02.000Z"
}
],
"count": 1,
"email": "o5su1l2h8i@maildrop.cc"
}
}/api/v1/messages/{id}Read one message
The full body of a single message, including any extracted verification code.
Query
emailstringrequired- The address the message belongs to.
Response
{
"success": true,
"data": {
"id": "msg_01H...",
"from": "noreply@example.com",
"subject": "Your verification code",
"body": "Your code is 481920",
"html": "<p>Your code is <b>481920</b></p>",
"verificationCode": "481920"
}
}Create an address, then poll it until the code you are waiting for turns up.
const KEY = "YOUR_API_KEY";
const headers = { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" };
// 1. Mint an address.
const created = await fetch("https://zenix-tempmail.vercel.app/api/v1/inboxes", {
method: "POST", headers, body: "{}",
}).then((r) => r.json());
const email = created.data.email;
// 2. Poll it. There are no webhooks yet, so this is the shape of it.
for (let attempt = 0; attempt < 30; attempt++) {
const inbox = await fetch(
`https://zenix-tempmail.vercel.app/api/v1/messages?email=${encodeURIComponent(email)}`,
{ headers },
).then((r) => r.json());
const [first] = inbox.data.messages;
if (first) {
const full = await fetch(
`https://zenix-tempmail.vercel.app/api/v1/messages/${first.id}?email=${encodeURIComponent(email)}`,
{ headers },
).then((r) => r.json());
console.log(full.data.verificationCode ?? full.data.body);
break;
}
await new Promise((r) => setTimeout(r, 2000));
}- Reading mail
- 300 requests per minute, per key. Enough to poll several inboxes a second.
- Listing domains
- 600 requests per 10 minutes, per key. The list changes rarely — cache it.
- Address lifetime
- Set by the provider behind the domain, from about 10 minutes to 24 hours.
- Cost
- None. No metering, no overage, no card.
Rate limits are counted per key rather than per IP, so rotating egress addresses does not widen them. A limited response carries Retry-After.
Failures return a JSON body with an error string and, where it helps, a stable code.
- 400
- The request was missing something, or a field failed validation.
- 401
- No key, or a key that is not valid. Send `Authorization: Bearer <key>`.
- 404
- No such message, or the inbox has already expired.
- 429
- Rate limited. `Retry-After` says how long to wait.
- 502
- The upstream provider failed. Usually worth retrying.
Something missing or wrong? Tell us.