Disposable email,
in your code.
Generate temporary inboxes and get the full email pushed to your app the instant it arrives. Real-time webhooks, free. Pay only for the requests you make.
Free real-time webhooks
The full email lands at your endpoint the instant it arrives: sender, subject, HTML and text body. No credit cost, no polling.
Simple auth
One Bearer token. Generate as many keys as you need on the dashboard.
Pay-as-you-go
Credits never expire. No subscriptions. Top up only when you run out.
Built for testing
Long-poll endpoint, custom usernames, 5 domains, instant inbox generation.
Simple credit packs
One credit = one billable request. Generating inboxes is free.
Every account gets 10 free credits to try the API. No card required.
API reference
Everything you need to integrate the API. Copy-paste ready.
Base URL & authentication
All endpoints live under:
https://vanishinbox.com/api/v1Authenticate every request with a Bearer token from your API keys page:
Authorization: Bearer vib_live_YOUR_KEYCode samples, issue tracking, and anything we ship for the API (like the upcoming n8n node) live on GitHub.
Pricing & metering
One credit equals one billable API request. Generating addresses, listing domains, account info, and clearing inboxes are free. Fetching email contents costs one credit per call.
Every response includes the current balance in headers:
X-Credits-Remaining: 9842
X-Credits-Used: 1If you run out of credits, requests return 402 Payment Required. Top up on the billing page. Credits never expire.
Rate limits
Each API key is limited to 120 requests per minute across all endpoints. The limit is per key, so if you need higher throughput you can create additional keys on the keys page.
Every response includes your current limit state:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 1748419260When you exceed the limit, requests return 429 Too Many Requests with a Retry-After header telling you how many seconds to wait. Tight polling loops should use the /wait endpoint instead. It's the same cost, but counts once against the limit.
Endpoints
/meFreeReturns the authenticated account's credit balance and key metadata. Use this to verify your key works.
curl https://vanishinbox.com/api/v1/me \
-H "Authorization: Bearer vib_live_YOUR_KEY"{
"credits": 9842,
"key": {
"id": "2cfdd221-0515-472e-8ed1-9e83d9a4e1ac",
"name": "Production",
"prefix": "vib_live_Jo4"
}
}/inbox/generateFreeGenerates a fresh disposable inbox address. The address is reserved as soon as the first email arrives and lives for 10 minutes from then. All body fields are optional.
{
"domain": "fommie.com" | "random", // optional, default 'random'
"username": "my-test-flow" // optional, auto-generated if omitted
}curl -X POST https://vanishinbox.com/api/v1/inbox/generate \
-H "Authorization: Bearer vib_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"domain": "random"}'{
"address": "[email protected]",
"username": "leanmink654",
"domain": "fommie.com",
"expires_in_seconds": 600,
"webhook_eligible": true
}/domainsFreeLists all domains available through the API. Use this to avoid hardcoding the domain list; we may add or rotate domains over time.
curl https://vanishinbox.com/api/v1/domains \
-H "Authorization: Bearer vib_live_YOUR_KEY"{
"domains": [
{ "name": "fommie.com" },
{ "name": "whoopza.org" },
{ "name": "fommie.online" },
{ "name": "fommie.store" },
{ "name": "whoopza.store" }
]
}/inbox/{address}1 creditFetches all emails received at the address. Returns an empty array if nothing has arrived yet. The 10-minute expiry timer starts when the first email arrives.
curl https://vanishinbox.com/api/v1/inbox/[email protected] \
-H "Authorization: Bearer vib_live_YOUR_KEY"{
"address": "[email protected]",
"emails": [
{
"id": "...",
"from": "[email protected]",
"subject": "Verify your email",
"html": "<p>Click here...</p>",
"text": "Click here...",
"receivedAt": "2026-05-21T08:15:00.000Z"
}
],
"expires_in_seconds": 580
}/inbox/{address}/wait1 creditLong-polls for new emails. Returns immediately if emails already exist, otherwise blocks up to 30 seconds waiting for one. Use this instead of tight polling: same cost, far less traffic.
timeout=30 // optional, max 60curl "https://vanishinbox.com/api/v1/inbox/[email protected]/wait?timeout=30" \
-H "Authorization: Bearer vib_live_YOUR_KEY"{
"address": "[email protected]",
"emails": [...],
"timed_out": false,
"expires_in_seconds": 580
}/inbox/{address}FreeClears the inbox and expires the address.
curl -X DELETE https://vanishinbox.com/api/v1/inbox/[email protected] \
-H "Authorization: Bearer vib_live_YOUR_KEY"{
"address": "[email protected]",
"cleared": true
}Webhooks
How webhooks work
Register a webhook and we POST to your URL the moment an email arrives, usually within a second of delivery. No polling required.
Eligibility: only addresses generated without a custom username are webhook-eligible. Check the webhook_eligible field on the generate response. Custom usernames are free and guessable, so allowing webhooks on them would let anyone pre-claim an address before a real person types the same string into the free web tool. Auto-generated addresses don't have that problem, so they're always eligible.
One webhook per address. Registering a new one replaces any existing subscription. Subscriptions expire with the address, 10 minutes, same as the inbox itself.
Deliveries carry the full email: sender, subject, HTML and plain-text body, timestamp. You won't need a follow-up call to GET /inbox/{address} to read what arrived. The body goes to whatever URL you register, so point target_url only at an endpoint you trust.
Verifying deliveries
Every delivery includes a signature header. Verify it before trusting the payload:
X-Webhook-Signature: t=1748419260000,v1=<hmac_sha256_hex>const crypto = require('crypto')
function verify(secret, timestamp, rawBody, signatureHeader) {
const [, v1] = signatureHeader.split(',')
const expected = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`)
.digest('hex')
return expected === v1.split('=')[1]
}secret comes back once, at registration. Store it yourself; we can't show it again. If you lose it, register a new webhook for a fresh one.
/inbox/{address}/webhooksFreeRegisters a webhook for the address. Requires the address to be webhook_eligible (auto-generated, owned by this key). Replaces any existing webhook on the same address.
{
"target_url": "https://your-app.example.com/hooks/vanishinbox" // required, https only
}curl -X POST https://vanishinbox.com/api/v1/inbox/[email protected]/webhooks \
-H "Authorization: Bearer vib_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"target_url": "https://your-app.example.com/hooks/vanishinbox"}'{
"id": "9e2b1a3c-...",
"address": "[email protected]",
"target_url": "https://your-app.example.com/hooks/vanishinbox",
"secret": "whsec_9f2c...",
"created_at": "2026-05-21T08:10:00.000Z"
}/inbox/{address}/webhooksFreeFetches metadata for the registered webhook. The secret is never returned again after creation.
curl https://vanishinbox.com/api/v1/inbox/[email protected]/webhooks \
-H "Authorization: Bearer vib_live_YOUR_KEY"{
"id": "9e2b1a3c-...",
"address": "[email protected]",
"target_url": "https://your-app.example.com/hooks/vanishinbox",
"created_at": "2026-05-21T08:10:00.000Z"
}/inbox/{address}/webhooksFreeRemoves the webhook subscription for the address.
curl -X DELETE https://vanishinbox.com/api/v1/inbox/[email protected]/webhooks \
-H "Authorization: Bearer vib_live_YOUR_KEY"{
"address": "[email protected]",
"deleted": true
}Custom usernames
Pass username in the generate request to pick your own local part. Useful when you want a predictable address for test fixtures.
curl -X POST https://vanishinbox.com/api/v1/inbox/generate \
-H "Authorization: Bearer vib_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"username": "signup-test-42", "domain": "fommie.com"}'
# → [email protected]Rules:
- 3 to 64 characters
- Lowercase letters, digits, dot, hyphen, underscore
- Must start and end with a letter or digit
- No consecutive dots
Usernames aren't reserved. If two people generate the same address, they share the inbox. For test isolation, include a unique component (timestamp, UUID fragment) in your username.
Addresses with a custom username aren't webhook-eligible; see the Webhooks section above for why. If you need both a predictable address and a webhook, that combination isn't supported yet.
Errors
Errors come back as JSON with a type and message:
{
"error": {
"type": "insufficient_credits",
"message": "You have no credits remaining. Top up your balance to continue.",
"topup_url": "https://vanishinbox.com/dashboard/billing"
}
}invalid_requestmalformed inputunauthorizedmissing or invalid API keyinsufficient_creditsout of creditsnot_eligibleaddress isn't webhook-eligible or isn't yoursnot_foundno webhook registered for this addressrate_limit_exceededtoo many requests; honour Retry-Afterinternal_errorserver failure; credit is refunded automaticallyEnd-to-end example
A complete signup-verification flow in Node.js:
const API_KEY = process.env.VANISHINBOX_KEY
const BASE = 'https://vanishinbox.com/api/v1'
const headers = { Authorization: `Bearer ${API_KEY}` }
// 1. Generate a fresh inbox
const { address } = await fetch(`${BASE}/inbox/generate`, {
method: 'POST',
headers,
}).then(r => r.json())
// 2. Use it to sign up wherever
await signupOnSomeService({ email: address })
// 3. Wait for the verification email
const { emails } = await fetch(
`${BASE}/inbox/${address}/wait?timeout=30`,
{ headers }
).then(r => r.json())
// 4. Extract the verification link
const verifyLink = emails[0].html.match(/href="([^"]+verify[^"]*)"/)[1]
console.log('Click here:', verifyLink)Ready to start?
Sign up with just an email. No credit card. 10 free credits on the house.
Get my API key