zenix.
API

Disposable inboxes, over HTTP.

Five endpoints. Bearer-token auth, JSON in and out, no SDK required. Free, with the same limits as everything else.

Getting started

Base URL

https://zenix-tempmail.vercel.app/api/v1

Authentication

Authorization: Bearer <key>

Generate a key in Settings and it will be filled into every example on this page.

Example
curl "https://zenix-tempmail.vercel.app/api/v1/domains?limit=3" \
  -H "Authorization: Bearer YOUR_API_KEY"
Endpoints
GET/api/v1/statusno key needed

Service status

Which upstream providers are answering right now, and how many of them. The only endpoint that does not need a key.

Response

Example
{
  "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"
  }
}
GET/api/v1/domains

List 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

Example
{
  "success": true,
  "data": {
    "domains": [
      { "domain": "maildrop.cc", "service": "maildrop.cc", "status": "active" }
    ],
    "services": ["mail.tm", "maildrop.cc"],
    "totalDomains": 94,
    "nextCursor": "eyJpZCI6..."
  }
}
POST/api/v1/inboxes

Create 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

Example
{
  "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"
  }
}
GET/api/v1/messages

Read 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

Example
{
  "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"
  }
}
GET/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

Example
{
  "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"
  }
}
End to end

Create an address, then poll it until the code you are waiting for turns up.

Example
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));
}
Limits
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.

Errors

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.