Signup Flow Testing
Automate disposable inbox creation and read confirmation emails during CI or staging signups.
Integrate Getnada temporary email into your apps — create disposable inboxes, receive OTP and verification mail, poll or stream messages, and automate temp mail testing without hosting your own mail server.
Temp mail API for open, messages, stream, and automation workflows.
The Getnada API lets developers programmatically create temporary email addresses, open disposable inboxes, and read inbound messages in real time or on a poll interval. Use temp mail for signup flow testing, OTP automation, QA environments, and privacy-first workflows.
Guest integrations can call public endpoints immediately. Verified members unlock API keys for member-tier domains, private inbox management, and higher plan limits. Premium temporary email access is arranged manually via Contact.
Automate disposable inbox creation and read confirmation emails during CI or staging signups.
Capture OTP codes and verification links sent to temp mail addresses in automated test suites.
Wire Getnada temp mail into bots, scrapers, and backend jobs that need throwaway email inboxes.
Poll or stream incoming messages to detect delivery, latency, and content in disposable inboxes.
List enabled domains and test member-tier or premium temp mail domains with API keys.
Call public endpoints and open guest-tier temporary email inboxes without signing in.
Verify your email, create API keys, unlock member-tier temp mail domains, and manage private inboxes.
Higher API limits, more temporary email domains, and premium support — arranged via Contact.
Request Premium Access →Call GET /api/public/domains — guest tiers by default; append ?api_key= for member/personal domains.
POST /api/inbox/open with { email } returns a disposable address and inbox JWT token.
Poll GET /api/inbox/messages or use SSE on /api/inbox/stream when Redis is available.
GET /api/inbox/message?id= for full body; PATCH to toggle read state when needed.
Extend with POST /api/inbox/heartbeat; close with POST /api/inbox/close when finished.
Open a guest-tier temporary email inbox (pick a domain from GET /api/public/domains; add ?api_key= for member tiers):
curl -sS -X POST "https://getnada.net/api/inbox/open" \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]"}'200 OK
{ "inboxId": "123", "token": "eyJ…", "activeUntil": "2026-06-09T12:00:00.000Z", "sessionSeq": 1, "visibility": "public", "recipient": "[email protected]", "mailSource": "local" }Upgrade to Premium Getnada temporary email for more domains, higher API ceilings, and manually arranged support.
API Reference
Step-by-step temp mail API workflows with cURL, PHP, and Node.js examples. Replace YOUR_API_KEY and YOUR_INBOX_TOKEN with values from your account and from POST /api/inbox/open.
Guests can call public endpoints and open guest-tier inboxes. To use ?api_key= on open, register, verify your email, then create a key on this page after sign-in.
Lost your password? Use Forgot password from the login page.
Confirms the app can reach the database (and optionally Redis). No API key or inbox token. Response shape: { "status": "ready", "database": "ok", "redis": "ok" } — or HTTP 503 with status: "not_ready" when MariaDB is down. Use GET /api/health for a lightweight liveness probe ({ "ok": true }, no dependency checks).
curl -sS "https://your-domain.example/api/ready"
GET /api/public/domains returns { domains, items, planMax }. Each item includes domain, partnerExternal (partner mail vs local MX), and for authenticated callers also accessTier / scope (system or personal). Guests see guest-tier hostnames only.
Verified members: append ?api_key=YOUR_API_KEY (or send the key in headers) to include member/premium system domains and active personal domains in the same response.
Guest (default)
curl -sS "https://your-domain.example/api/public/domains"
POST /api/inbox/open with JSON body { "email": "local@domain" }. Append ?api_key=YOUR_API_KEY when you need member-tier domains (verified account). Omit the query param for guest-only domains. The JSON response includes visibility (public or private) and recipient.
Public vs private: New addresses opened through this route create a public inbox row unless the address already exists as a private inbox. If the row is private, the server returns HTTP 403 unless the request is authenticated as the owner: either your browser session (signed-in, verified user — same cookies as the site) or an account API key that belongs to that same user. Guests, pending accounts, and other users’ keys cannot open someone else’s private inbox. Public inbox behavior for anonymous open is unchanged when the row is public.
JSON body uses error: "PRIVATE_INBOX_ACCESS_DENIED" for that 403 — useful for scripts; the web UI shows a friendly message instead of the raw code.
curl -sS -X POST "https://your-domain.example/api/inbox/open?api_key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]"}'Response includes token (inbox JWT), inboxId, activeUntil, sessionSeq, recipient, and mailSource (local or partner). Use token in Step 3 — it is not the same as your account API key.
GET /api/inbox/messages requires the inbox token from Step 2. Either pass ?token=… or Authorization: Bearer … (same JWT). Response: { messages: [...], cursor }. Partner domains use string message id values — poll only (no SSE).
Option A — query string
curl -sS "https://your-domain.example/api/inbox/messages?token=YOUR_INBOX_TOKEN"
Option B — Authorization header
curl -sS -H "Authorization: Bearer YOUR_INBOX_TOKEN" \ "https://your-domain.example/api/inbox/messages"
POST /api/inbox/heartbeat with JSON { "token": "…" } extends the session (browser UI does this on a timer).GET /api/inbox/stream with the same inbox token (Bearer or ?token=) when Redis is configured; partner inboxes return 403 PARTNER_POLL_ONLY — use polling instead.Heartbeat example
curl -sS -X POST "https://your-domain.example/api/inbox/heartbeat" \
-H "Content-Type: application/json" \
-d '{"token":"YOUR_INBOX_TOKEN"}'GET /api/inbox/message?id= returns full sanitized HTML body for a single message. Response: { message: { id, subject, from_addr, html_sanitized, text_plain, … } }. Local MX inboxes use numeric id from the messages list; partner inboxes use string uids.
curl -sS -H "Authorization: Bearer YOUR_INBOX_TOKEN" \ "https://your-domain.example/api/inbox/message?id=MESSAGE_ID"
PATCH /api/inbox/message with JSON { "id": "MESSAGE_ID", "read": true | false } and the inbox JWT. Returns { ok: true }. Partner inboxes accept the call but do not persist read state server-side.
curl -sS -X PATCH "https://your-domain.example/api/inbox/message" \
-H "Authorization: Bearer YOUR_INBOX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":"MESSAGE_ID","read":true}'POST /api/inbox/close ends the inbox session when your automation finishes with the temporary email address.
curl -sS -X POST "https://your-domain.example/api/inbox/close" \
-H "Content-Type: application/json" \
-d '{"token":"YOUR_INBOX_TOKEN"}'When Redis is configured, subscribe to new-mail events instead of polling Step 3. Not available for partner (partnerExternal: true) domains.
curl -sS -N -H "Authorization: Bearer YOUR_INBOX_TOKEN" \ "https://your-domain.example/api/inbox/stream"
Account API key (verified members only) — used so open can resolve member-tier domain access. Preferred for scripts: append ?api_key=… to the /api/inbox/open URL. Also supported: X-API-Key or Authorization: Bearer … on that same request.
Query parameters may be logged by proxies and browsers. For production integrations in hostile networks, prefer sending the account key in headers instead of the query string.
Inbox token — short-lived JWT returned by open (or POST /api/account/inboxes / …/inboxes/<id>/open for private create/refresh). Use it for messages, message (GET/PATCH), heartbeat, stream, and close. Pass ?token=… or Authorization: Bearer ….
Complete Getnada temporary email API surface for temp mail automation, inbox monitoring, and member account management.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/health | None | Liveness probe — process is up (no DB/Redis check). |
| GET | /api/ready | None | Readiness — { status, database, redis }. 503 when DB is down; degraded when Redis is configured but unreachable. |
| GET | /api/public/domains | None; optional api_key or session expands tiers | List domains for inbox creation. Guest tiers by default; verified session or ?api_key= adds member/premium system domains and active personal domains. Returns { domains, items, planMax }. |
| POST | /api/inbox/open | Optional api_key (member) or session | Create or reopen a temporary email inbox. Body: { email }. Returns inbox JWT plus inboxId, activeUntil, sessionSeq, visibility, recipient, mailSource. |
| GET | /api/inbox/messages | Inbox JWT (?token= or Bearer) | List messages — { messages, cursor }. Fields: id, subject, from_addr, received_at, read_at, has_attachments, attachment_count. Partner inboxes use string ids. |
| GET | /api/inbox/message?id= | Inbox JWT | Fetch one message — { message: { …, html_sanitized, text_plain } }. Local MX: numeric id; partner: string uid. |
| PATCH | /api/inbox/message | Inbox JWT | Mark read/unread. JSON body: { id, read: boolean }. Partner inboxes accept the call but do not persist read state. |
| POST | /api/inbox/heartbeat | Inbox JWT in JSON body { token } | Extend inbox session lifetime — returns { activeUntil }. |
| GET | /api/inbox/stream | Inbox JWT (Bearer or ?token=) | Server-Sent Events for near-realtime new-mail when Redis is available. Partner inboxes return 403 PARTNER_POLL_ONLY — use polling. |
| POST | /api/inbox/close | Inbox JWT in JSON body { token } | Close the inbox session — returns { ok: true }. |
| GET | /api/account/api-keys | Session cookie (verified member) | List your API keys and quota (maxActiveApiKeys, activeKeyCount). |
| POST | /api/account/api-keys | Session cookie (verified member) | Create an API key. Returns rawSecret once. Optional label in JSON body. |
| POST | /api/account/api-keys/:id/revoke | Session cookie (verified member) | Revoke an API key immediately. |
| POST | /api/account/inboxes | Session cookie (verified member) | Create a private temp mail inbox. Body: { domain, localPart? }. |
| GET | /api/account/inboxes | Session cookie (verified member) | Paginated list of private inboxes. Query: page, scope=active|archived. |
| PATCH | /api/account/inboxes/:id | Session cookie (verified member) | Archive or unarchive a private inbox. Body: { action: "archive" | "unarchive" }. |
| GET | /api/account/inboxes/suggest?domain= | Session cookie (verified member) | Batch of human-style local-part suggestions for private inbox creation. |
| POST | /api/account/inboxes/:id/open | Session cookie (verified member) | Refresh inbox JWT for an owned private inbox by numeric id. |
| GET | /api/account/domains | Session cookie (verified member) | List personal custom domains, DNS status, and inboxEligibleDomains (browser session only). |
| Code | HTTP | Meaning |
|---|---|---|
| EMAIL_REQUIRED | 400 | Missing email in open request body. |
| EMAIL_NOT_ALLOWED | 400 | Email format or domain not permitted. |
| DOMAIN_REQUIRED | 400 | Missing domain query param on suggest route. |
| INVALID_JSON | 400 | Request body is not valid JSON. |
| INVALID_BODY | 400 | PATCH message body is not a JSON object. |
| INVALID_READ_FLAG | 400 | PATCH message requires read: boolean. |
| INVALID_MESSAGE_ID | 400 | Message id missing or wrong shape for inbox type. |
| INVALID_INBOX_ID | 400 | Account inbox route id is not numeric. |
| INVALID_ACTION | 400 | PATCH account inbox action must be archive or unarchive. |
| TOKEN_REQUIRED | 401 | Inbox JWT missing on message/stream routes. |
| UNAUTHORIZED | 401 | Session cookie missing on account routes. |
| INVALID_TOKEN | 401 | Inbox JWT expired or invalid. |
| DOMAIN_NOT_ALLOWED | 403 | Domain not enabled or above your plan tier on open. |
| PRIVATE_INBOX_ACCESS_DENIED | 403 | Cannot open another user's private inbox. |
| PRIVATE_INBOX_ARCHIVED | 403 | Private inbox is archived — unarchive first. |
| INBOX_UNAVAILABLE | 403 | Inbox session invalid, archived, or session mismatch. |
| GUEST_PARTNER_INBOX_LIMIT | 403 | Guest limit for partner-domain inboxes reached. |
| PERSONAL_DOMAIN_OWNER_REQUIRED | 403 | Personal domain requires owner session or API key. |
| PERSONAL_DOMAIN_NOT_ACTIVE | 403 | Personal domain DNS not active yet. |
| NOT_ACTIVE | 403 | Account not verified — API keys unavailable. |
| NOT_FOUND | 404 | Message or private inbox not found. |
| ALREADY_ARCHIVED | 409 | Private inbox is already archived. |
| NOT_ARCHIVED | 409 | Unarchive called on an active private inbox. |
| UNARCHIVE_BLOCKED_AT_LIMIT | 409 | Active private inbox quota full — archive another first. |
| LIMIT | 409 | Plan quota reached (API keys). |
| PRIVATE_INBOX_LIMIT | 409 | Active private inbox quota reached. |
| SUGGESTION_EXHAUSTED | 409 | Could not allocate a unique local part after retries. |
| SESSION_MISMATCH | 409 | Inbox JWT session no longer matches server state. |
| RATE_LIMITED | 429 | Too many requests — retry after backoff. |
| SERVICE_UNAVAILABLE | 503 | Database or dependency unreachable. |
| PARTNER_INBOX_NOT_CONFIGURED | 503 | Partner mail integration not configured. |
| PARTNER_INBOX_TIMEOUT | 504 | Partner inbox activation exceeded deadline. |
Key storage, issuance, and HTTP errors: docs/PART_2_API_KEYS.md. Auth and activation: docs/PART_2_AUTH_PLAN.md.
Not built here: Swagger portal, org sharing, admin key console, usage analytics dashboards, or automated key rotation wizards.