Emails
Read emails, wait for new ones, extract OTPs.
Emails
List Emails
GET /v1/inboxes/:id/emailsReturns all emails in an inbox, newest first.
Messages forwarded from a phone appear with channel: "sms" and are receive-only. Their authentication codes are available through the same /otp and /wait?has_otp=true endpoints as email codes. See Forward SMS codes for setup and payload details.
{
"emails": [
{
"id": "eml_xyz789",
"inbox_id": "inb_abc123",
"from": "noreply@github.com",
"to": ["github-bot@lumbox.co"],
"subject": "Your verification code",
"text_body": "Your code is 847291",
"parsed": {
"otp_codes": ["847291"],
"verification_links": [],
"category": "verification"
},
"received_at": "2025-01-01T00:01:00.000Z"
}
]
}Wait for Email
GET /v1/inboxes/:id/wait?timeout=60Long-polls until a matching email arrives and returns the full parsed email. Use it when you need the whole message, for example a magic link in parsed.magic_links. If nothing matches before the timeout, the response is 408.
| Param | Type | Default | Description |
|---|---|---|---|
timeout | number | 30 | Seconds to wait, 1 to 120 |
from | string | - | Sender contains this string |
subject | string | - | Subject contains this string |
category | string | - | Parsed category, such as verification |
has_otp | boolean | false | Only return an email with an extracted code |
since | ISO 8601 | time of the request | Only match emails received at or after this time |
Get OTP
GET /v1/inboxes/:id/otp?timeout=60Long-polls until a verification or security email with a code arrives, then returns the code. Use it when the code is all you need.
| Param | Type | Default | Description |
|---|---|---|---|
timeout | number | 30 | Seconds to wait, 1 to 120 |
from | string | - | Sender contains this string. A forwarded email also matches on its original sender. |
since | ISO 8601 | 5 minutes before the request | Only match emails received at or after this time |
{
"code": "847291",
"all_codes": ["847291"],
"from": "noreply@github.com",
"subject": "Your verification code",
"expires": null,
"email_id": "eml_xyz789"
}If no code arrives in time, the response is 408 with { "error": "No OTP found", "timeout": 60 }. Without since, the newest code from the previous five minutes is returned, and that can belong to an earlier login.
Parallel login runs
When several logins run at the same time, or one inbox serves each customer of a portal, each run needs to get its own code back:
- One inbox per run or per customer. A shared inbox with a sender filter cannot tell two simultaneous codes from the same service apart. Create a per-run inbox with
POST /v1/inboxesand remove it withDELETE /v1/inboxes/:idwhen the run ends. - A
sincetimestamp captured just before the run triggers the verification email, so an older code is never returned. - The expected sender in
from, and an explicit408branch that retries the login step. - An inbox-scoped key for a worker that should only reach one customer's inbox.
const API = "https://api.lumbox.co/v1";
const headers = { Authorization: `Bearer ${process.env.LUMBOX_API_KEY}` };
const since = new Date().toISOString();
await triggerLogin(inbox.address);
const res = await fetch(
`${API}/inboxes/${inbox.id}/otp?` +
new URLSearchParams({ since, from: "accounts.example.com", timeout: "90" }),
{ headers },
);
if (res.status === 408) throw new Error("No code arrived, retry the login");
const { code } = await res.json();The Node SDK's waitForOtp accepts from and timeout but not since, so SDK users should give each run a fresh inbox.
SMS codes are in early access: a customer forwards login texts from their own phone with an iOS Shortcut or an Android forwarder, and the code lands in the same inbox for the same /otp call.
Get Email
GET /v1/emails/:idDelete Email
DELETE /v1/emails/:idSearch Emails
GET /v1/emails/search?q=github&inbox_id=inb_abc123Search across emails by keyword, sender, or category.