DEVELOPER TOOLS · API REFERENCE
An inbox in your code.
One less thing to build.
Private temporary inboxes for signup tests, verification codes and throwaway workflows. Every endpoint and SDK is free.
The response tells you whether your inbox is live or sandbox. Live addresses receive email from your application or email provider; .test addresses use the sample endpoint. SDK files are available below, with no registry installation required.
Your first inbox, in a few lines.
SDKs handle private access for you.// Download /sdk/inbini.mjs into this directory.
import { Inbini } from './inbini.mjs';
const mail = new Inbini({
baseUrl: 'https://inbini.com/api/v1'
});
const inbox = await mail.inboxes.create({ expiresIn: '45m' });
try {
console.log(inbox.address);
if (inbox.data.mode === 'sandbox') await inbox.sample();
// On a live domain, trigger your application's email now.
const code = await inbox.waitForCode({ timeout: 60_000 });
console.log(code);
} finally {
await inbox.delete();
}These examples run against a locally running or publicly accessible API. An owner-private Sites preview requires browser sign-in, so external SDK requests cannot access it directly.
PICK YOUR LANGUAGE
Small SDKs. Useful defaults.
Node.js 22+ or a modern browser
Source preview availablePython 3.10+ · no dependencies
Source preview availablePrefer typed source? Download the TypeScript file. Go, PHP, Java, C# and Ruby are planned. They are not available yet.
THE RIGHT KEY FOR EACH REQUEST
No global API key to get started.
Creating an inbox on the default or a public domain needs no authentication. Each inbox is private: use its own token for every read or delete request.
| Credential | How you get it | What it allows |
|---|---|---|
INBOX_TOKEN · ib_… | Returned when creating an inbox. | Read/delete that inbox and its messages; deliver sandbox samples. |
WORKSPACE_TOKEN · wk_… | Returned when creating a workspace. | Manage private domains and create inboxes on them. It cannot read inbox contents. |
Receiver key · rx_… | Generated after proving domain ownership. | Deliver mail through a domain’s receiver endpoint. It cannot read inboxes or manage domains. |
Authenticated HTTP requests use Authorization: Bearer TOKEN. JSON requests use Content-Type: application/json. SDKs set these headers for you.
REQUEST. RESPONSE. NEXT STEP.
Examples for every request.
Open an endpoint for its parameters, a complete request in your language, and the response to expect. Examples use https://inbini.com.
Before you copy
Use your real values for INBOX_ID, INBOX_TOKEN, MESSAGE_ID, DOMAIN_ID and WORKSPACE_TOKEN when a request needs them. Set them in your shell or secret manager; never put tokens in URLs or commit them.
JavaScript examples run as .mjs files in Node.js 22+ with inbini.mjs beside them. Python examples need Python 3.10+ and inbini.py beside the script. Download either SDK above. SDK examples resume existing inboxes with an initial GET, then perform the requested action.
Responses below are illustrative. Replace the sample IDs and abbreviated tokens with the real values returned by your API. HTTP successes wrap the result in data; the SDKs unwrap it. A 204 response has no body.
Inboxes & messages
Create a private address and choose when it expires. Save the returned inbox ID and token: the token is shown only on creation.
| Parameter | Where | How to use it |
|---|---|---|
expiresIn | JSON · optional | Positive whole number + s, m, h or d. For example 45m, 2h or 7d. Defaults to 1h. Every inbox expires. |
domainId | JSON · optional | Omit for the default domain. Use an ID from /api/config for a public domain, or from your workspace for a private domain. |
curl --include --silent --show-error \
--request POST "https://inbini.com/api/v1/inboxes" \
--header 'Content-Type: application/json' \
--data "{\"expiresIn\":\"45m\"}"HTTP/1.1 201 Created
Content-Type: application/json
{
"data": {
"id": "11111111-1111-4111-8111-111111111111",
"address": "[email protected]",
"createdAt": "2026-09-17T12:00:00.000Z",
"expiresAt": "2026-09-17T12:45:00.000Z",
"domainId": null,
"mode": "live",
"token": "ib_EXAMPLE_TOKEN_SAVE_THE_REAL_VALUE"
}
}- The SDK returns an inbox object. Read its address with inbox.address and save inbox.id and inbox.token privately to resume later.
- For a public domain, no workspace key is needed. A private domain needs its owning workspace key and must be ready.
When it fails: 400 INVALID_LIFETIME for an invalid duration; 401 WORKSPACE_REQUIRED for a private domain without its key; 409 DOMAIN_NOT_READY until DNS and reception are verified.
Workspaces & domains
Service
FROM DNS TO YOUR FIRST DELIVERY
Connect a domain in order.
For an existing public domain, read GET /api/config and use its ID when creating an inbox. To connect a private domain, follow these steps or use Your domains.
- Create a workspace and save its token. Add your domain with
POST /api/v1/domains. - Publish the returned TXT proof and configure Cloudflare Email Routing for this domain or subdomain. Apply the MX records Cloudflare provides.
- Call the domain’s
/verifyendpoint. Check thatownershipVerifiedandmxVerifiedare both true. - Generate a receiver key. Download the Cloudflare receiver and follow its README to deploy the Worker and set the domain’s catch-all routing rule. Use the returned inbound path, hostname and receiver key.
- Send a real email from another provider to
testAddress. This tests the complete mail route; its contents are discarded. - Read the domain until
statusisready. Create an inbox with itsdomainIdand your workspace key. Use the newly returned inbox token to read mail.
Keep the ownership TXT record published. DNS is rechecked on active use after ten minutes, and failed checks block new creation or delivery until verification succeeds. Reissuing a receiver key requires a new connection test.
HANDLE THE UNHAPPY PATH
Know what to retry.
HTTP errors use an error object instead of data. The SDKs raise InbiniError with the status and code. Network failures may raise a native error.
HTTP/1.1 410 Gone
Content-Type: application/json
{
"error": {
"code": "INBOX_EXPIRED",
"message": "This inbox has expired. Create a new one."
}
}| Status / code | What to do |
|---|---|
400 · INVALID_LIFETIME / INVALID_FILTER | Correct the duration or filter. Repeating the same request will not fix it. |
401 · UNAUTHORIZED / WORKSPACE_REQUIRED | Check the ID and correct token type. A deleted or cleaned-up inbox also returns 401. |
403 · SANDBOX_ONLY | Send a real email to a live inbox. The sample endpoint only works for .test addresses. |
404 · MESSAGE_NOT_FOUND / DOMAIN_NOT_FOUND | Check the resource ID and ownership. It may have been deleted. |
409 · DOMAIN_NOT_READY / DOMAIN_NOT_VERIFIED | Complete DNS verification and the receiver connection test, then retry. |
410 · INBOX_EXPIRED | Create a new inbox. Resuming an inbox cannot extend its expiry. |
429 · RATE_LIMITED | Wait the Retry-After header’s number of seconds. Setup and security operations can be throttled; inbox creation, polling and message count have no fixed quotas. |
503 · DNS_UNAVAILABLE / DATABASE_UNAVAILABLE | Retry after the service or DNS lookup recovers. A failed lookup does not count as successful verification. |
408 · WAIT_TIMEOUT (SDK only) | No matching result arrived before the local polling deadline. Check filters and delivery; this is not an HTTP status returned by the inbox API. |
Poll for the message you actually need.
Create an inbox, record your test start time, trigger your application’s email, and poll with that timestamp. The example below starts a new polling window; set after to the saved test start time if the email was already triggered.
import { InbiniError } from './inbini.mjs';
// With an existing inbox object:
try {
const code = await inbox.waitForCode({
from: '[email protected]',
subject: 'verification',
after: new Date().toISOString(),
timeout: 60_000, // milliseconds
});
console.log(code);
} catch (error) {
if (error instanceof InbiniError) {
console.error(error.status, error.code, error.message);
// error.retryAfter is in seconds.
} else {
throw error;
}
}The wait helpers poll once per second and honor Retry-After when throttled. Ordinary one-shot SDK calls raise the error so your code can decide what to retry. Use waitForMessage / wait_for_message for the full message, or waitForLink / wait_for_link for its first HTTP(S) link.
Choose the expiry your workflow needs.
There are no fixed quotas for inbox creation, requests per inbox or messages per inbox. Inboxes still expire: use a positive duration such as 45m, 2h or 7d. The default is one hour, and resuming an inbox never extends it.
Message contents are plain text and are deleted on expiry or when you delete them. Operational receipt metadata is retained permanently, as described on the privacy page.