Anonymous Inboxes API
Create temporary email inboxes without an account, and read them with the viewer token returned on creation. Made for AI agents and scripts that need to read one signup or login email. See Inboxes without an account for a walkthrough.
| Route | Auth | Result |
|---|---|---|
POST /api/v1/anon/inboxes | None | Create an inbox |
GET /api/v1/anon/inboxes/:id | Viewer token | Get the inbox |
GET /api/v1/anon/inboxes/:id/emails | Viewer token | List emails |
GET /api/v1/anon/inboxes/:id/emails/wait | Viewer token | Wait for the next matching email |
GET /api/v1/anon/inboxes/:id/emails/:email_id | Viewer token | Get one email |
GET /api/v1/anon/inboxes/:id/emails/:email_id/attachments/:index | Viewer token | Download an attachment |
POST /api/v1/anon/inboxes/:id/claim | API key or session | Move the inbox into your organization |
Send the viewer token as Authorization: Bearer <viewer_token>.
Create an anonymous inbox
POST /api/v1/anon/inboxes
curl -X POST https://app.hooklistener.com/api/v1/anon/inboxes \
-H "Content-Type: application/json" \
-d '{"ttl_seconds": 3600, "client": "claude-code"}'
No authentication required.
| Field | Type | Required | Description |
|---|---|---|---|
ttl_seconds | integer | No | Lifetime, from 60 to 86400. Default 3600 (1 hour) |
client | string | No | The agent or tool creating the inbox (claude-code, codex, cursor…). Only used for counting |
Response: 201 Created
{
"id": "0d6f1c2a-9b8e-4c3d-a1f2-6e5d4c3b2a19",
"expires_at": "2026-10-12T11:00:00Z",
"email_count": 0,
"max_emails": 50,
"emails_url": "https://app.hooklistener.com/api/v1/anon/inboxes/0d6f1c2a-9b8e-4c3d-a1f2-6e5d4c3b2a19/emails",
"wait_url": "https://app.hooklistener.com/api/v1/anon/inboxes/0d6f1c2a-9b8e-4c3d-a1f2-6e5d4c3b2a19/emails/wait",
"viewer_token": "Zk3qL0m9…",
"claim_token": "hkic_Q2x8…",
"claim_url": "https://app.hooklistener.com/claim/inbox/0d6f1c2a-9b8e-4c3d-a1f2-6e5d4c3b2a19?token=hkic_Q2x8…"
}
viewer_token and claim_token are returned only here. Keep them secret: the viewer token reads every email the address receives.
One IP can create 10 anonymous inboxes per hour and 30 per day. Above that the API answers 429 Too Many Requests with a Retry-After header.
Get an anonymous inbox
GET /api/v1/anon/inboxes/:id
curl https://app.hooklistener.com/api/v1/anon/inboxes/INBOX_ID \
-H "Authorization: Bearer VIEWER_TOKEN"
Returns the create response without the tokens and claim_url: id, email_address, expires_at, email_count, max_emails, emails_url and wait_url.
List emails
GET /api/v1/anon/inboxes/:id/emails
Same response, pagination (page, page_size) and filters (since, to, from, subject_contains) as List emails for inboxes in an account.
Wait for the next email
GET /api/v1/anon/inboxes/:id/emails/wait
curl -s -G https://app.hooklistener.com/api/v1/anon/inboxes/INBOX_ID/emails/wait \
-H "Authorization: Bearer VIEWER_TOKEN" \
--data-urlencode "since=2026-10-12T10:05:00Z" -d timeout=60 \
| jq -r '.data.code'
Same as Wait for the next email: 200 with the full email as soon as one matches, the oldest match after since at once, or 204 No Content after timeout seconds (default 30, max 60). The wait also ends with 204 when the inbox expires.
Get an email
GET /api/v1/anon/inboxes/:id/emails/:email_id
Returns {"data": email} with the same fields as Get an email: code, verification_link, codes, links, text, bodies, headers and attachments. Attachment download_urls point at the anonymous route below.
Download an attachment
GET /api/v1/anon/inboxes/:id/emails/:email_id/attachments/:index
Returns the attachment's bytes as a download, like Download an attachment.
Claim an anonymous inbox
POST /api/v1/anon/inboxes/:id/claim
curl -X POST https://app.hooklistener.com/api/v1/anon/inboxes/INBOX_ID/claim \
-H "Authorization: Bearer hklst_your_api_key" \
-H "Content-Type: application/json" \
-d '{"claim_token": "hkic_Q2x8…", "name": "Signup tests"}'
Authenticated with an API key or a user session; the inbox moves into that organization.
| Field | Type | Required | Description |
|---|---|---|---|
claim_token | string | Yes | The claim_token from the create response |
name | string | No | Name for the inbox in the organization |
Response: 201 Created with {"data": inbox} (the inbox object). The inbox keeps its ID, address and emails, stops expiring, and counts toward the organization's inbox limit. The viewer token stops working.
Users without an API key can claim in the browser by opening claim_url.
Errors
| Status | When |
|---|---|
400 | A malformed since or timeout |
401 | Missing or wrong viewer token |
403 | Claim: invalid claim token, or the organization's plan has no room for another inbox (the body includes an upgrade object) |
404 | Unknown inbox, email or attachment |
410 | The inbox expired or was claimed |
429 | Too many inboxes created from this IP |
Most errors have the body {"error": "…"}. A 400 for a malformed filter has {"errors": {"detail": "…"}}, like the rest of the API.
Limitations
- Lifetime of 1 hour by default, 24 hours at most
- Up to 50 emails over the inbox's lifetime; later mail is refused
- No rename, delete, clear or webhook forwards until claimed
- Anyone with the viewer token can read the inbox's mail