POST /api/v1/addresses
Creates an address, optionally on a specific domain or with a chosen local part. Returns the full address record. Without a local part, the server picks a random twelve-character name. Premium domains require a paid plan.
For developers
Create addresses programmatically, wait for real mail over a live stream, and read the verification code out of a field instead of a regular expression you wrote at midnight.
# 1. Tạo địa chỉ
curl -X POST https://9inbox.io/api/v1/addresses \
-H "Authorization: Bearer mgw_live_xxx" \
-H "Content-Type: application/json" \
-d '{"domain": "9inbox.io"}'
# 2. Đọc thư đã tới
curl "https://9inbox.io/api/v1/messages?address_id=<uuid>&limit=50" \
-H "Authorization: Bearer mgw_live_xxx"const headers = { Authorization: `Bearer ${process.env.NINEINBOX_KEY}` };
const res = await fetch("https://9inbox.io/api/v1/addresses", {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({}),
});
const { data } = await res.json();
console.log(data.address.address); // [email protected]// Thư đến đẩy thẳng về, không cần polling.
const stream = new EventSource(
`https://9inbox.io/api/v1/messages/stream?address_id=${id}`,
);
stream.addEventListener("message", (event) => {
const msg = JSON.parse(event.data);
// otp_code đã được server trích sẵn — không phải tự regex thân thư.
console.log(msg.subject, msg.otp_code);
});Why an API
Testing a registration flow end to end means testing the part where a real email arrives. Teams usually work around this in one of three ways, and all three are unsatisfying: they stub the mail step and stop testing it, they route everything to a shared mailbox and fight over who owns which message, or they create real mailboxes by hand and quietly stop running the test after a few months.
An address that can be created in one request and read in another removes the workaround. Your test creates an address, drives the signup form with it, waits on the stream until the confirmation arrives, and reads the code from the response body. There is no shared state between test runs, because every run invents its own addresses, and no cleanup script, because the addresses expire on their own.
The part worth pointing out is the otp_code field. Verification codes are extracted from the message on our side and returned on the message summary. That means your test does not carry a regular expression that has to be updated every time a vendor changes their email template — which is, in practice, the thing that breaks these tests most often.
Endpoints
Creates an address, optionally on a specific domain or with a chosen local part. Returns the full address record. Without a local part, the server picks a random twelve-character name. Premium domains require a paid plan.
Lists messages for one address, or across every address you own if address_id is omitted. Cursor paginated — there is no OFFSET anywhere in this API.
Returns the full message, including the sanitised HTML body, the plain text body and attachment metadata. Fetching a message marks it read.
The original .eml file, for when you need to inspect headers, DKIM results, or the exact MIME structure a sender produced.
A server-sent events stream. Emits a ready event with the address IDs being watched, a message event carrying a full message summary for each new mail, and a ping every 25 seconds to keep proxies from closing the connection.
The domains available to your plan, including whether each is premium and whether it is currently accepting new addresses.
Limits
Authentication is a bearer token: send your API key in the Authorization header. Keys are shown once at creation and stored only as a hash, so a leaked key is revoked rather than recovered. Each key carries scopes, and you should issue a separate key per environment so that revoking a compromised CI key does not take production with it.
Rate limits are per key and per minute: sixty requests per minute on Pro, six hundred on Business, and sixty per hour on the free account tier. Exceeding the limit returns HTTP 429 with a Retry-After header measured in seconds — respect it rather than retrying immediately, because a tight retry loop will keep you rate limited indefinitely.
Two properties of the stream are worth designing around. It does not replay: a message that arrives during a reconnection produces no event, so a test that must not miss mail should reconcile with a list call after connecting rather than trusting the stream alone. And the hub drops events for clients that fall behind, so a slow consumer loses events rather than blocking every other client on the same instance.
Webhooks are available on Pro and Business. Payloads are signed with an HMAC secret in the X-MailGW-Signature header and retried five times with backoff. Verify the signature before you parse the body, and make your handler idempotent — a retry after a timeout will deliver the same event twice.
The things that come up during integration.
Yes. A free registered account includes API access at sixty requests per hour, which is enough to build against and enough for a small nightly test run. The guest tier has no API access at all, because there is no key to authenticate with.
Yes, on the Business plan. You point the MX record of a domain you own at 9inbox, verify ownership with a TXT record, and every address under that domain is delivered to your account as a catch-all. Your tests can then invent addresses freely without creating them first.
It is reliable enough to drive a test but not a guaranteed delivery channel. There is no event ID and therefore no replay, so a message arriving during a reconnect will not produce an event. If your test cannot tolerate a missed message, list messages once after the ready event and treat the stream as an optimisation rather than the source of truth.
Attachment metadata — filename, MIME type and size — is returned with the message detail, and the content is downloadable. Size limits follow your plan: 5 MB on free, 25 MB on Pro and 50 MB on Business. Attachments are scanned before they are made available.
They are deleted along with their messages by a scheduled cleanup job, and mail sent to them afterwards is rejected at the SMTP level. On Pro and Business addresses do not expire at all, so an address your test suite created a year ago still works.
Nothing to install, nothing to fill in. Scroll back up, press Copy, and paste it wherever you were being asked for an email.