For products you build · temporarymail.ai

address_for(site). wait_for_code(site). Done.

Your test suites and the agents inside your product stall at verification emails. Give them a deterministic inbox: the same site always maps to the same address, nothing exists until mail arrives, and the code comes back as text. No inbox IDs, no sending, no per-inbox pricing.

Built for flows you own or were asked to run: QA of your signup, your product's own onboarding, an agent acting for a person who approved it. Not a tool for bulk account creation: rate limits, a daily cap per key, per-site approvals for personal agents, and our acceptable-use policy enforce that, and mail is sealed to its owner's key at rest.

Free to start: 100 codes a month with a developer key. Unlimited addresses on every tier. Billing by codes received.
One verification, end to endJSON
POST https://api.singleusemail.com/v1/agent/addresses
Authorization: Bearer ak_…
{ "site": "acme-app.com" }

→ { "site": "acme-app.com",
    "address": "k7m3q2xa.h4@niirii.com",
    "index": 0 }

GET https://api.singleusemail.com/v1/agent/codes?site=acme-app.com&wait=30

→ { "status": "ok", "code": "482913",
    "from": "no-reply@acme-app.com",
    "subject": "Your verification code",
    "remaining": 19 }
Derived, not createdaddress = HMAC(key, site, index) on a pool domain. Same key, same site, same address, forever. Creating an address costs nothing, so we do not charge for it.
Codes as textThe engine extracts the verification code or the link from each email on arrival, in English and Arabic, and hands it back as a string. The body is available too, if the key's rules allow it.
Keys that scopeOne master key per tenant; agent keys derived from it per agent, with rules (codes only, approval before new sites, monthly caps). Revoke an agent without touching the tenant.
Quickstart

Three calls with curl

The fastest path is a developer key: open Your agents in the web app, connect an agent with This key is for a product I build switched on, and copy its key. Developer keys skip approvals and are metered on the developer tier (100 codes a month free). Then:

1. Ask for an address
curl -X POST https://api.singleusemail.com/v1/agent/addresses \
  -H "Authorization: Bearer ak_YOUR_AGENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"site":"acme-app.com"}'
2. Use it on the site, then wait for the code
curl "https://api.singleusemail.com/v1/agent/codes?site=acme-app.com&wait=30" \
  -H "Authorization: Bearer ak_YOUR_AGENT_KEY"
3. Blocked domain? Bump the index
curl -X POST https://api.singleusemail.com/v1/agent/addresses \
  -H "Authorization: Bearer ak_YOUR_AGENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"site":"acme-app.com","new_domain":true}'
Response statuses from /v1/agent/codes
200 okcode and/or link, sender, subject, remaining allowance
200 waitingnothing yet after wait seconds (max 60); call again
202 awaiting_approvalthe key's owner must approve this site first
402 limitallowance used; the body carries upgrade, a link to buy a pack or raise the tier
403 denied / agent_pausedthe owner denied or paused this agent
Only new mail countsEach code is returned once. Pass since (epoch ms) to ignore anything older than your request. A returned code is metered; waiting is free.
MCP server

Four tools any agent can call

Streamable HTTP, JSON-RPC 2.0, protocol 2025-06-18. No OAuth dance: the agent key is the URL, or a Bearer header on POST https://api.singleusemail.com/mcp.

ToolArgumentsReturns
address_forsite, optional new_domainthe address for this site
wait_for_codesite, optional wait (≤60 s)code and/or link, or a status to act on
get_linksitethe newest verification link for this site
list_addressesnonethe addresses this agent has made
Connect from a config file
{
  "mcpServers": {
    "singleusemail": {
      "type": "http",
      "url": "https://api.singleusemail.com/mcp/ak_YOUR_AGENT_KEY"
    }
  }
}
Claude, Cursor, Codex and most MCP clients accept a remote HTTP server this way. Where a client asks for a Bearer token instead, send ak_… as the token against https://api.singleusemail.com/mcp.
API reference

Two principals, one base URL

Base URL https://api.singleusemail.com. JSON in, JSON out. Errors are { "error": "snake_case", "message": "…" } with a fitting status. CORS is open, so browsers can call it directly.

Agent endpoints — Authorization: Bearer ak_<agent key>

Method and pathBody or queryWhat it does
POST /v1/agent/addressessite, new_domain?Derive and register the agent's address for a site (idempotent).
GET /v1/agent/codessite, wait?, since?Long-poll for the newest unread code or link. Metered.
GET /v1/agent/addresses—List this agent's sites and addresses.

Owner endpoints — Authorization: Bearer <auth token>

The auth token is base64url(HMAC-SHA256(key, "sum:auth:v1")). The server keeps SHA-256(token) as the fingerprint that owns addresses and agents; it never sees the key.

Method and pathBody or queryWhat it does
GET /v1/domainspublicThe pool domains that currently issue addresses. Derive against this list.
POST /v1/addressesaddress, site_hash, index?, label_enc?Register a derived address so mail to it is accepted. 201 new, 200 existing, 409 if another key holds it, 429 over the hourly limit. First registration may require a Turnstile token in X-Turnstile.
GET /v1/addresses—Your addresses with counts, last activity and encrypted labels.
PATCH /v1/addresses/:addresslabel_encStore or clear an encrypted label (ciphertext only; you hold the key).
DELETE /v1/addresses/:address—Retire: stops receiving, deletes its mail now.
GET /v1/codesaddress, since?, wait?Long-poll for the newest message on one address (code, link, sender, subject).
GET /v1/messagesaddress?Recent messages (metadata, code, link, DKIM/SPF result).
GET /v1/messages/:id—One message with text and sanitised HTML.
GET /v1/messages/:id/raw—The original .eml.
DELETE /v1/messages/:id—Delete a message and its raw copy.
GET /v1/plan—Plan and retention for this key.
POST /v1/agentsagent_id, agent_hash, name?, codes_only?, ask_new_sites?, monthly_limit?Register an agent key by its hash with its rules. Upsert.
GET /v1/agents—Agents, pending approvals, and the record (last 100 events).
PATCH /v1/agents/:idpaused?, codes_only?, ask_new_sites?, monthly_limit?, name?Change rules or pause.
DELETE /v1/agents/:id—Void the agent key. Its addresses stay with you.
POST /v1/approvals/:iddecision: allowed_once | always | deniedAnswer an agent's request for a new site. Deny pauses the agent.
POST /v1/abusetarget, category, details?, email?Public. Report an address or message.

Derivation, so you can do it in any language

key        = 32 random bytes
           formatted "sum1-" + base32(key) in groups of 4

authToken  = HMAC-SHA256(key, "sum:auth:v1")
agentKey   = HMAC-SHA256(key, "sum:agent:v1:" + agent_id)
agent_hash = hex(SHA-256(agentKey))         # what you register

site       = lowercase host, no scheme/www/path/port
tag        = base32(HMAC(secret, "sum:tag:v1"))[0:2]
local      = base32(HMAC(secret, "sum:addr:v1:" + site + ":" + index))[0:8] + "." + tag
domain     = pool[ uint32be(HMAC(secret, "sum:dom:v1:" + site + ":" + index)[0:4]) % len(pool) ]
address    = local + "@" + domain
site_hash  = base32(HMAC(secret, "sum:site:v1:" + site))[0:16]

# secret = key for your own addresses, agentKey for an agent's
# base32 = RFC 4648 alphabet, lowercase, no padding
Why site_hashThe server never learns which site an address is for; it stores the keyed hash so a new device can find "the address for acme-app.com" without telling us the name. Labels are AES-GCM ciphertext under a key derived from yours.
Pool changesFetch /v1/domains before deriving a new address. Existing registered addresses keep receiving even if their domain leaves the issuing pool; clients should prefer the registered address for a site over a fresh derivation.
Reference implementationThe @sum/core TypeScript package in the open repository is the source of truth, with tests for every constant above.
Pricing

Per code. Never per inbox.

Every tier has unlimited address creation and unlimited developer keys. You pay for verification emails you actually read through the API: the monthly allowance first, then prepaid packs, which never expire. Buy packs or upgrade from the developer card in the app; all developer keys of one key holder share the tier.

Free
$0
  • 100 codes / month
  • 1-hour retention
  • Shared pool domains
  • MCP and REST
Pay as you go
$9 / 1,000 codes
  • No monthly fee
  • 7-day retention
  • Shared pool domains
  • Card on file
Pro
$29 / month
  • 5,000 codes included, then $7 / 1,000
  • 30-day retention
  • 1 private domain
  • Tenant keys
Scale
$99 / month
  • 30,000 codes included, then $5 / 1,000
  • 90-day retention
  • 5 private domains, SLA
  • White-label and DPA on request

Sold through Polar (polar.sh), our merchant of record. Prices in USD; local taxes may apply. A tier that lapses falls back to pay as you go; prepaid codes stay. Private domains and tenant keys on Pro and Scale are set up by hand for now: write to us.

Limits and uptime

What we promise, and what we do not yet

Receive-only. No sending, replying or forwarding, on any plan, ever.
Message size. Up to 10 MB per email is stored; larger messages are refused at SMTP.
Registration. 30 new addresses per key per hour on free. Agents register on demand inside that limit.
Long-poll. wait is capped at 60 seconds per request.
Uptime. The service runs on Cloudflare's edge and email routing. Live health and incidents are on the status page; there is no SLA below Scale.
Retention. Emails are purged on schedule by plan. Raw copies go with them. Addresses never expire.
Abuse. Reports can disable an address or a key. We refuse phone-number services outright.
Changes. The v1 API is additive; anything removed gets 90 days' notice by email to keys with a paid plan.
Questions

Before you integrate

Where do keys come from?

From you. A key is 32 random bytes; nothing is issued by the server. Make one in the web app (Your key) or in code, derive the auth token and agent keys locally, and register addresses as you derive them. The server stores only one-way hashes.

Why register addresses at all if they are derived?

So mail to an address nobody derived is refused at the door and never stored. Registration is idempotent and free: one POST per address, or let the agent tools do it for you.

Can I use my own domain?

On Pro and Scale: point one MX record at us and your tenant's addresses come out on your domain. On the shared pool, a site that blocks one domain is handled by index bumping (new_domain).

Is there sending?

No, and there never will be. Receive-only keeps the pool clean, the price low and the abuse surface small. Export raw .eml if you need the message elsewhere.

How fast is delivery?

The email worker parses the message and writes it before the SMTP session closes; wait_for_code long-polls the store. In our tests the code is readable within a few seconds of the sending server handing it off. We do not publish a latency guarantee yet.

What about rate limits?

Address registration is limited per key per hour (30 on free). Agent codes are metered per month. Abuse reports can disable an address or a key. Contact us before running load tests.

For people

Looking for a single-use address for yourself?

Same engine, friendlier door: singleusemail.com gives you an address in one click, no key handling needed.