inboxsink API
Scriptable disposable inboxes, so you can test signup flows without depending on a real mailbox. Five routes, one base at https://inboxsink.com, JSON in and out.
The route that changes anything is wait: it blocks until the message arrives. Without it, an end-to-end test guesses with sleep and turns flaky the moment the sending queue lags.
JavaScript client
A dependency-free package for Node 18 and above. Source on GitHub.
npm i inboxsink
import { InboxSink } from 'inboxsink'; const sink = new InboxSink(process.env.INBOXSINK_API_KEY); const inbox = await sink.createInbox(); const code = await sink.waitForOtp(inbox.id); // '204815'
waitForOtp throws rather than returning null when no code arrives: a test should fail loudly, not quietly submit an empty field.
Authentication
One Authorization header per call. Keys are created from the dashboard and start with ibsk_.
curl -H "Authorization: Bearer ibsk_…" \
https://inboxsink.com/v1/domains
The plain key is shown only once, at creation. After that only its prefix stays visible — we store nothing but its hash.
Create an inbox
Every parameter is optional: domain (a random pool domain by default), prefix (random by default), ttl_seconds (60 seconds to 30 days).
curl -X POST https://inboxsink.com/v1/inboxes \ -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \ -d '{"ttl_seconds": 900}' → 201 { "id": "42", "address": "9f2c1a@mailhusk.com", "expires_at": "2026-09-01T15:12:00Z" }
An inbox created through the API is private: only the key that created it can read it.
Wait for a message
Blocks until a message arrives, then answers immediately. timeout in milliseconds (30 000 by default, 120 000 maximum), since to only get messages after a given id.
Answers 204 with no body if the delay runs out — that is not an error, it is the normal answer to "nothing arrived".
curl -H "Authorization: Bearer $KEY" \ "https://inboxsink.com/v1/inboxes/42/wait?timeout=45000" → 200 { "message": { "id": "913", "from": "no-reply@acme.com", "subject": "…", "otp": "204815", "link": "https://acme.com/confirm/9f3a" } }
otp and link are extracted for you. A code is only reported when the message actually announces one ("code", "verification", "sign in"…) — an invoice total or a year is never mistaken for one.
List messages
Takes since and limit (50 by default, 200 maximum). Returns summaries, without message bodies.
Read a message
The whole message: text, html, headers and the attachment list.
Delete an inbox
Erases the inbox and its messages immediately. Answers 204.
Errors
| 204 | No content — for wait, the delay ran out with no message |
| 400 | Invalid parameter |
| 401 | Key missing, unknown or revoked |
| 403 | That inbox belongs to another key |
| 404 | Inbox or message gone, or already expired |
| 429 | Too many calls |
Limits and lifetime
Public pool inboxes live one hour; inboxes created through the API follow their ttl_seconds, up to thirty days. After that the inbox and its messages are deleted — there is no archive to recover afterwards.
Messages over ten megabytes are refused on arrival. Addresses on an unknown domain are rejected during the SMTP session, without generating a bounce.
These inboxes cannot send mail, and that is deliberate: a message sent from a disposable domain would not arrive anywhere.