Automated OTP & MFA Extraction
Two-factor codes stop AI agents at the login screen. Lumbox parses the verification email and returns the OTP through the API.
Regex-Powered Parsing
We automatically scan incoming emails for standard OTP formats (4 digits, 6 digits, alphanumeric codes, magic links) and return the structured string to your agent. No more feeding entire HTML blobs into LLM context windows just to find a code.
Zero-Loop Polling
Trigger the action that sends the email, then call /otp. The request stays open until a verification email with a code arrives and returns the code, its sender and the email ID, or a 408 when the timeout passes. Call /wait instead when you need the whole message, such as a magic link.
// the agent reaches the 2FA screen
const { code } = await fetch(
`${API}/inboxes/${inbox.id}/otp?timeout=60&from=github.com`,
{ headers },
).then((r) => r.json());
await page.fill("#otp", code);
await page.click("#submit");Parallel logins and customer portals
For parallel login runs, give each run its own inbox, or each customer their own inbox when a portal logs in on their behalf. A shared inbox with a sender filter cannot tell two simultaneous codes from the same service apart. Capture a timestamp just before triggering the verification email and pass it as since, because without it /otp looks back five minutes and can return an earlier login's code. Pass the expected sender as from, treat a 408 as a signal to retry the login step, and give a worker that serves one customer an inbox-scoped API key.
const since = new Date().toISOString();
await page.click("#send-code");
const res = await fetch(
`${API}/inboxes/${customer.inboxId}/otp?` +
new URLSearchParams({ since, from: "portal.example.com", timeout: "90" }),
{ headers },
);
if (res.status === 408) throw new Error("No code arrived, retry the login");
const { code } = await res.json();
await page.fill("#otp", code);SMS codes are in early access: the customer forwards login texts from their own phone with an iOS Shortcut or an Android forwarder, and the same /otp call returns them. Full parameters are in the OTP docs.