Up to 30 days
Developer messages expire from the moment they arrive. Reading a message never resets its clock.
Create an inbox, receive messages, and stream verification codes. A straightforward API for your next integration.
API access is included with the Developer website plan.
Manage your keys and scopes in account settings.
Send your key in the authorization header.
Authorization: Bearer YOUR_API_KEYCreate first, then send. Only mail received while an inbox is active is stored. Other mail to a valid receiving domain is accepted and discarded.
One request creates an address, ready to receive mail.
usernameoptionaldomain_idoptionalGET /v1/domains, or let us select one: custom first, then
premium, then free.Premium and custom inboxes are private. Free-domain inboxes are shared and public.
Random names use 3–5 alternating consonant/vowel letters plus 3–5 digits, such as bav472 or tavid20485. Developer allows up to 50 total inboxes.
curl --request POST \
"$TMB_API_ORIGIN/v1/inboxes" \
--header "Authorization: Bearer $TMB_API_KEY" \
--header "Content-Type: application/json" \
--data '{"username":"your-name"}' TMB_API_ORIGIN to your API origin (locally http://localhost:3000) and TMB_API_KEY to your account API key.Create and manage inboxes, read messages, and subscribe to incoming mail.
Download the original email with GET /v1/inboxes/:id/messages/:messageId/source. It returns an .eml file with the original headers, MIME bodies and
attachments. Message details include source_download_url. Downloads share the
attachment rate limit and normal message expiration.
To star a message, send PATCH /v1/inboxes/:id/messages/:messageId/star with starred set to true (or false). Lists and message details include your personal starred status. Stars expire with the message.
| Endpoint | Purpose |
|---|---|
GET /v1/domains | Active domains and expiry warnings |
POST /v1/inboxes | Create an inbox on an eligible domain |
DELETE /v1/inboxes/:id | Delete an inbox, its messages and attachments |
DELETE /v1/inboxes/:id/messages/:messageId | Delete a message and its attachments |
GET /v1/inboxes/:id/messages | Paginated received mail |
GET /v1/inboxes/:id/messages/:messageId | Plain text, sanitized HTML, attachment metadata |
GET /v1/inboxes/:id/messages/:messageId/attachments/:attachmentId | Download the original attachment bytes |
GET /v1/inboxes/:id/events | Server-sent events with resumable cursor |
GET /v1/inboxes/:id/otp/events | Developer-only OTP stream for an owned private inbox; closes after 60 seconds |
POST /v1/abuse-reports | Report unsafe content |
Watch an inbox for verification codes as mail arrives. One request opens a 60-second window.
/v1/inboxes/:id/otp/eventsmessages:readRun this request with your API key and inbox ID.
curl --no-buffer --max-time 70 \
-H "Authorization: Bearer $TMB_API_KEY" \
-H "Accept: text/event-stream" \
"$TMB_API_ORIGIN/v1/inboxes/$INBOX_ID/otp/events"Set TMB_API_ORIGIN to your API origin (locally, http://localhost:3000) and INBOX_ID to the inbox UUID. --no-buffer displays events immediately.
The response streams Server-Sent Events as they happen.
{
"inbox_id": "INBOX_ID",
"message_id": "MESSAGE_ID",
"sender": "[email protected]",
"subject": "Your verification code",
"received_at": "2026-10-14T12:00:01.000Z",
"expires_at": "2026-11-13T12:00:01.000Z",
"code": "001234",
"source": "text",
"confidence": "high",
"confidence_score": 95,
"signals": [
"explicit_otp_label",
"numeric_code"
],
"reliability": {
"method": "heuristic",
"verified": false
}
}otp.found includes the candidate code, message metadata, and confidence signals. Codes remain strings to preserve leading zeroes.
Existing messages are excluded. The connection stays open after a match and closes after 60 seconds, even if no codes arrive. Each connection uses one API request.
Scores come from extraction rules, not verified accuracy. The service does not authenticate the sender or check a code with its issuer.
Use a Developer account API key with messages:read. The inbox must belong
to that key’s account. Public inboxes, RevenueCat mobile inboxes, and website session
cookies do not authorize this endpoint.
The response uses text/event-stream. Older deliveries are excluded even if
parsed after connection; new mail must finish parsing before the stream closes.
Heartbeat comments keep the connection active while waiting.
Start a new request for another window. Query parameters and Last-Event-ID replay
are not supported. The cURL client timeout of 70 seconds allows time for the server’s 60-second
window.
A stream.error event means access or service failure interrupted the stream;
start a new request after resolving the cause.
code is a string, preserving leading zeroes. Each candidate includes inbox_id, message_id, sender, subject, received_at, and expires_at. The timestamps describe the
message’s server receipt and retention deadline; they do not establish when the OTP
itself expires. Sender and subject metadata are limited to 1,024 characters each.
confidence is high for an explicit nearby OTP label or medium for a generic code/PIN label or an OTP subject with a code near the
start of the body. confidence_score is an uncalibrated rule score, not a
probability or percentage accuracy. signals explains the match, and source identifies subject, text, or html. The service does not
verify the sender or validate the code with its issuer; reliability.verified is always false.
Extraction supports labelled 4–8 digit codes, including grouped six-digit codes, and mixed uppercase-letter/digit codes of 6–10 characters. It scans the subject and the first 128 KiB of plain text, with a fallback for HTML-only messages. Attachments are not scanned. Codes repeated within one message are deduplicated, with at most 16 candidates per message. False positives and missed codes are possible.
Each connection consumes one API request; streamed candidates do not consume extra
requests. Concurrency is limited across the account’s keys. Cancellation, revoked
access, inbox deletion, service failure, or a slow consumer can end the stream early. A complete event with reason: timeout is normal, including when codes_found is zero.
Before streaming starts, HTTP 401 indicates a missing, invalid, or revoked key; HTTP 403 indicates a missing scope or unavailable plan feature; HTTP 404 means the inbox is unavailable or not owned by the account. HTTP 422 rejects invalid parameters or a replay cursor, and HTTP 429 indicates a request or stream limit.
Each event has an event: line and a single-line JSON data: value,
separated from the next event by a blank line. The panel above formats the decoded JSON for
readability.
event: ready
data: {"inbox_id":"INBOX_ID","started_at":"2026-10-14T12:00:00.000Z","deadline":"2026-10-14T12:01:00.000Z","extraction_version":"otp-heuristic-v1"}
event: otp.found
data: {"inbox_id":"INBOX_ID","message_id":"MESSAGE_ID","sender":"[email protected]","subject":"Your verification code","received_at":"2026-10-14T12:00:01.000Z","expires_at":"2026-11-13T12:00:01.000Z","code":"001234","source":"text","confidence":"high","confidence_score":95,"signals":["explicit_otp_label","numeric_code"],"reliability":{"method":"heuristic","verified":false}}
event: complete
data: {"reason":"timeout","codes_found":1,"finished_at":"2026-10-14T12:01:00.000Z"}The limits and lifetimes to build around.
Developer messages expire from the moment they arrive. Reading a message never resets its clock.
Public inbox activity and retention follow the creator’s plan. Private addresses receive while their owner’s paid entitlement is active.
Use the returned next_cursor to fetch the next page. Keep going until the cursor
is empty.
429 Respect Retry-After before trying again.
503 A required service is unavailable. Retry with backoff.