API Reference

The Temp Mail HERE API lets you create disposable inboxes, read incoming mail, and stream new messages in real time. JSON over HTTP. Base URL is your deployment, e.g. https://api.tempmailhere.xyz (locally http://localhost:3000).

Authentication

Inboxes are anonymous. Creating one (POST /api/inbox) returns a private token. Pass it on every read for that inbox:

  • HTTP reads → header x-inbox-token: <token>
  • WebSocket → query param ?token=<token>

The inbound webhook is authenticated separately with a shared secret (x-inbound-secret).

Rate limits

Requests are rate-limited per client by plan. Anonymous clients get the Free tier (5 req/s). Exceeding it returns 429. Paid tiers raise the ceiling up to unlimited on Elite — see pricing.

GET/api/pricing

Returns branding + all plans (the pricing page is rendered from this).

curl http://localhost:3000/api/pricing

GET/api/domains

Lists the domains you can generate addresses on.

{ "domains": ["mail.tempmailhere.xyz", "inbox.tempmailhere.xyz"] }

POST/api/inbox

Creates a disposable inbox. All fields optional — omit to get a random address on the default domain.

FieldTypeDescription
domainstringOne of /api/domains. Defaults to the first.
localPartstringThe part before @. Random if omitted.
curl -X POST http://localhost:3000/api/inbox \
  -H "content-type: application/json" \
  -d '{ "localPart": "signup-test" }'

# → { "id":"…", "address":"signup-test@mail.tempmailhere.xyz",
#     "token":"…", "expiresAt": 1750000000000 }

GET/api/inbox/:id/messages

Lists messages (newest first). Requires x-inbox-token.

curl http://localhost:3000/api/inbox/INBOX_ID/messages \
  -H "x-inbox-token: TOKEN"

GET/api/messages/:id

Full message including text and html bodies. Marks it seen. Requires x-inbox-token.

DELETE/api/inbox/:id

Immediately burns an inbox and all its messages. Requires x-inbox-token.

WS/ws/:id?token=TOKEN

Streams events for an inbox. On a new email you receive:

{ "type": "message", "message": { "id":"…", "from":"…", "subject":"…", "receivedAt": … } }
const ws = new WebSocket(`wss://api.tempmailhere.xyz/ws/${id}?token=${token}`);
ws.onmessage = (e) => console.log(JSON.parse(e.data));

POST/api/inbound

Ingress for incoming mail. Your mail provider (Cloudflare Email Routing / Mailgun) posts here with header x-inbound-secret. Accepts our JSON shape or raw MIME:

// JSON shape
{ "to":"abc@mail.tempmailhere.xyz", "from":"x@svc.com",
  "subject":"Hi", "text":"…", "html":"…" }

// or raw MIME (parsed server-side)
{ "raw":"From: ...\r\nTo: ...\r\n\r\nbody" }

Cloudflare Email Routing setup

The cheapest way to actually receive mail (free, no mail server). Add your domain to Cloudflare, enable Email Routing, set a catch-all rule to a Worker, and deploy:

// worker.js — forwards every inbound email to /api/inbound
export default {
  async email(message, env) {
    const raw = await new Response(message.raw).text();
    await fetch("https://api.tempmailhere.xyz/api/inbound", {
      method: "POST",
      headers: {
        "content-type": "application/json",
        "x-inbound-secret": env.INBOUND_SECRET,
      },
      body: JSON.stringify({ to: message.to, from: message.from, raw }),
    });
  },
};

Point the domain's MX records at Cloudflare (the dashboard does this for you), and incoming mail to any address shows up via the WebSocket within a second.

Accounts

Sessions are cookie-based (signed, http-only). Sign up / log in set the cookie; subsequent requests are authenticated automatically by the browser.

POST/api/auth/signup · POST/api/auth/login

curl -X POST http://localhost:3000/api/auth/signup -c jar.txt \
  -H "content-type: application/json" \
  -d '{ "email":"you@example.com", "password":"at-least-8-chars" }'

POST/api/auth/logout · GET/api/auth/me

/api/auth/me returns your email, effective plan (a paid plan downgrades to free once it expires), planExpiresAt, and the plan limits. Creating an inbox while logged in uses your plan's retention & concurrency.

Billing

Payment is crypto only, via your PayInCrypto gateway. Crypto is one-time, so a payment buys a fixed period (30 days / 1 year); paying again before expiry extends it. Check availability with GET /api/billing/config.

POST/api/billing/checkout

FieldValues
planeco · core · elite
periodmonthly (30d) · yearly (1y)
methodcrypto · dev

Returns { url } — redirect the user to the gateway's hosted /pay/:id checkout. The dev method activates the plan instantly (only when DEV_SIMULATE=true).

Webhook

POST /api/billing/crypto/webhook — verifies PayInCrypto's x-payincrypto-signature (sha256=…) and activates the plan when the invoice for data.order_id reaches paid.

Custom domains

Every plan includes custom domains — 1 free, 3 on Eco, unlimited on Core/Elite. Bring your own domain, set the DNS records, verify, then generate inboxes on it. All routes require a logged-in session.

POST/api/domains/custom

Body { "domain": "mail.example.com" }. Returns the domain plus instructions: a TXT record (ownership) and an MX record (mail routing).

POST/api/domains/custom/:id/verify

Looks up the TXT challenge via DNS and marks the domain verified on success.

GET/api/domains/custom · DELETE/api/domains/custom/:id

API keys & firehose

For automation you don't poll each inbox — you create one API key and read all your mail from one endpoint. Combined with a catch-all custom domain (every anything@yourdomain auto-creates an inbox on arrival), this is the "one connection, all mail" path.

Keys

Create/revoke keys in your dashboard (/account). The raw key is shown once. Authenticate with Authorization: Bearer <key> or x-api-key.

POST /api/keys · GET /api/keys · DELETE /api/keys/:id (session only)

GET/api/mail

Every message across all your inboxes/domains, newest first, with full text and html bodies. Auth: session or API key.

QueryDescription
sinceOnly messages received after this epoch-ms. Pass back the previous response's now to poll incrementally.
limitMax messages (default 100, max 500).
curl -H "Authorization: Bearer $KEY" https://tempmailhere.xyz/api/mail
# → { "now": 1750…, "messages": [ { "to":"x@yourdomain", "from":"…",
#     "subject":"Your code is 123456", "text":"…", "html":"…" }, … ] }

WS/ws/account?key=<key>

Live push of every inbound message to any of your inboxes/domains — no polling. Each event: { "type":"message", "address":"x@yourdomain", "message": { … } }.

Errors

StatuserrorMeaning
400invalid_domainDomain not in your list
401unauthorizedMissing/wrong token or secret
404not_foundInbox/message gone (likely expired)
409address_takenThat address already exists
429rate_limitedOver your plan's req/s