API Reference
Full REST API documentation.
API Reference
Base URL: http://localhost:3000 (dev) or https://api.lumbox.co (production)
Authentication
All endpoints (except /v1/orgs and /v1/inbound) require an API key:
X-API-Key: ak_your_key_hereThe inbound webhook uses a separate secret:
Authorization: Bearer {INBOUND_SECRET}Organizations
Create Organization
POST /v1/orgsBody:
{ "name": "my-org" }Response (201):
{
"id": "org_abc123",
"name": "my-org",
"api_key": "ak_live_...",
"message": "Save your API key — it won't be shown again",
"created_at": "2026-02-27T10:00:00Z"
}Get Current Organization
GET /v1/orgs/meResponse (200):
{
"id": "org_abc123",
"name": "my-org",
"inbox_count": 5,
"domain_count": 1,
"api_key_count": 2,
"created_at": "2026-02-27T10:00:00Z"
}Create API Key
POST /v1/orgs/me/api-keysBody:
{ "name": "production", "scopes": ["inbox:read", "inbox:write"] }Response (201):
{
"id": "ak_id_abc",
"key_prefix": "ak_live_abc...",
"api_key": "ak_live_full_key_here",
"name": "production",
"scopes": ["inbox:read", "inbox:write"]
}Inboxes
Create Inbox
POST /v1/inboxesBody:
{
"name": "github-signup-bot",
"domain": "mycompany.com",
"local_part": "github-bot"
}All fields optional. Auto-generates address if local_part not set.
Response (201):
{
"id": "inb_abc123",
"address": "github-bot@mycompany.com",
"name": "github-signup-bot",
"status": "ACTIVE",
"created_at": "2026-02-27T10:00:00Z"
}List Inboxes
GET /v1/inboxesResponse (200):
{
"data": [
{
"id": "inb_abc123",
"address": "github-bot@lumbox.co",
"name": "github-signup-bot",
"status": "ACTIVE",
"email_count": 12,
"created_at": "2026-02-27T10:00:00Z"
}
]
}Get Inbox
GET /v1/inboxes/:idDelete Inbox
DELETE /v1/inboxes/:idPermanently deletes the inbox and all its emails.
List Emails in Inbox
GET /v1/inboxes/:id/emailsQuery params:
| Param | Type | Description |
|---|---|---|
limit | number | Max results (default: 20, max: 100) |
cursor | string | Pagination cursor |
from | string | Filter by sender (substring match) |
category | string | Filter by category |
since | string | ISO timestamp — only emails after this |
unread | boolean | Only unread emails |
Response (200):
{
"data": [/* email objects */],
"cursor": "next_cursor_value",
"has_more": true
}Get Email
GET /v1/inboxes/:id/emails/:emailIdReturns full email with attachments.
Wait for Email
GET /v1/inboxes/:id/waitLong-polls until a matching email arrives. Polls DB every 1 second.
Query params:
| Param | Type | Description |
|---|---|---|
timeout | number | Max seconds to wait (default: 30, max: 120) |
from | string | Filter by sender |
subject | string | Filter by subject keyword |
category | string | Filter by category |
has_otp | boolean | Only emails with OTP codes |
since | string | ISO timestamp |
Response (200): Full email object
Response (408): Timeout — no matching email arrived
Get OTP
GET /v1/inboxes/:id/otpLong-polls for the latest verification code. The simplest way to get an OTP.
Query params:
| Param | Type | Description |
|---|---|---|
timeout | number | Max seconds (default: 30, max: 120) |
from | string | Filter by sender |
since | string | ISO timestamp |
Response (200):
{
"code": "847291",
"all_codes": ["847291"],
"from": "noreply@github.com",
"subject": "Your verification code",
"expires": "2026-02-27T10:05:00Z",
"email_id": "eml_abc123"
}Emails
Get Email (by ID)
GET /v1/emails/:idUpdate Email
PATCH /v1/emails/:idBody:
{ "is_read": true }Delete Email
DELETE /v1/emails/:idSearch Emails
GET /v1/emailsSearch across all inboxes in your organization.
Query params:
| Param | Type | Description |
|---|---|---|
q | string | Search subject, body, summary |
from | string | Filter by sender (substring) |
category | string | Filter by category |
inbox_id | string | Limit to specific inbox |
since | string | ISO timestamp |
limit | number | Max results (default: 20, max: 100) |
Send / Reply / Forward
Send Email
POST /v1/inboxes/:id/sendBody:
{
"to": ["recipient@example.com"],
"subject": "Hello from my agent",
"text": "Plain text body",
"html": "<h1>HTML body</h1>",
"cc": ["cc@example.com"]
}to and cc accept a string or array of strings.
Response (201):
{
"ok": true,
"email_id": "eml_abc123",
"message_id": "<msg_abc@lumbox.co>",
"provider_message_id": "ses-id",
"provider": "SES"
}Reply to Email
POST /v1/inboxes/:id/replyBody:
{
"email_id": "eml_abc123",
"text": "Thanks for the info!",
"reply_all": false
}Automatically handles In-Reply-To and References headers for threading.
Forward Email
POST /v1/inboxes/:id/forwardBody:
{
"email_id": "eml_abc123",
"to": "someone@example.com",
"comment": "FYI — see below"
}Threads
List Threads
GET /v1/threadsQuery params:
| Param | Type | Description |
|---|---|---|
inbox_id | string | Filter by inbox |
limit | number | Max results (default: 20) |
Response (200):
{
"data": [
{
"thread_id": "thr_abc123",
"subject": "Your order has shipped",
"last_from": "noreply@amazon.com",
"last_at": "2026-02-27T10:00:00Z",
"inbox_id": "inb_abc123",
"category": "transactional",
"message_count": 3
}
]
}Get Thread
GET /v1/threads/:threadIdReturns all emails in the thread plus assigned agents.
Response (200):
{
"thread_id": "thr_abc123",
"subject": "Your order has shipped",
"message_count": 3,
"agents": [
{ "id": "ta_abc", "agent_id": "support-bot", "role": "OWNER", "assigned_at": "..." }
],
"messages": [/* email objects */]
}Thread Agents
Assign Agent
POST /v1/threads/:id/assignBody:
{
"agent_id": "support-bot",
"role": "OWNER"
}Roles: OWNER, PARTICIPANT, OBSERVER (default: PARTICIPANT)
Upsert — re-assigning updates the role.
Unassign Agent
POST /v1/threads/:id/unassignBody:
{ "agent_id": "support-bot" }List Thread Agents
GET /v1/threads/:id/agentsDomains
Add Domain
POST /v1/domainsBody:
{ "domain": "mycompany.com" }Response (201):
{
"id": "dom_abc123",
"domain": "mycompany.com",
"status": "PENDING",
"dns_records": {
"verification": { "type": "TXT", "name": "_lumbox.mycompany.com", "value": "lumbox-verify=token" },
"mx": [
{ "type": "MX", "name": "mycompany.com", "value": "mx1.lumbox.co", "priority": 10 },
{ "type": "MX", "name": "mycompany.com", "value": "mx2.lumbox.co", "priority": 20 }
],
"spf": { "type": "TXT", "name": "mycompany.com", "value": "v=spf1 include:spf.lumbox.co ~all" },
"dkim": { "type": "CNAME", "name": "lumbox._domainkey.mycompany.com", "value": "dkim.lumbox.co" },
"dmarc": { "type": "TXT", "name": "_dmarc.mycompany.com", "value": "v=DMARC1; p=none; rua=mailto:dmarc@lumbox.co" }
}
}Verify Domain
POST /v1/domains/:id/verifyChecks DNS via Cloudflare DNS-over-HTTPS. Returns per-record status.
Response (200):
{
"id": "dom_abc123",
"domain": "mycompany.com",
"status": "ACTIVE",
"checks": {
"verification": true,
"mx": true,
"spf": true,
"dkim": true,
"dmarc": true
}
}List Domains
GET /v1/domainsDelete Domain
DELETE /v1/domains/:idSMTP Configs (BYOS)
Bring Your Own SMTP — configure custom outbound email providers.
Create Config
POST /v1/smtp-configsBody:
{
"provider": "SES",
"name": "production-ses",
"username": "AKIA...",
"password": "secret...",
"region": "us-east-1",
"from_email": "noreply@mycompany.com",
"is_default": true
}Providers: SMTP, SES, SENDGRID, POSTMARK, RESEND
List Configs
GET /v1/smtp-configsPasswords and API keys are masked in the response.
Delete Config
DELETE /v1/smtp-configs/:idTest Config
POST /v1/smtp-configs/:id/testBody:
{ "to": "test@example.com" }Set Default
PATCH /v1/smtp-configs/:id/defaultRouting Rules
Auto-assign agents to threads based on email properties.
Create Rule
POST /v1/routing-rulesBody:
{
"name": "Route billing emails",
"conditions": {
"category": "financial",
"from_pattern": "*@stripe.com",
"subject_pattern": "*invoice*"
},
"target_agent_id": "billing-agent",
"priority": 10
}At least one of target_agent_id or target_inbox_id required.
List Rules
GET /v1/routing-rulesUpdate Rule
PATCH /v1/routing-rules/:idDelete Rule
DELETE /v1/routing-rules/:idWebhooks
Create Webhook
POST /v1/webhooksBody:
{
"url": "https://myapp.com/webhook",
"events": ["email.received"]
}URL must use HTTPS. The secret is returned only once at creation.
Response (201):
{
"id": "wh_abc123",
"url": "https://myapp.com/webhook",
"events": ["email.received"],
"secret": "whsec_...",
"active": true
}Webhook Payload
{
"event": "email.received",
"timestamp": "2026-02-27T10:00:00Z",
"data": {
"email_id": "eml_abc123",
"inbox_id": "inb_abc123",
"from": "sender@example.com",
"subject": "Verification code",
"category": "verification",
"otp_codes": ["847291"],
"summary": "Contains a verification code"
}
}Signature header: X-Lumbox-Signature (HMAC-SHA256 hex)
List Webhooks
GET /v1/webhooksUpdate Webhook
PATCH /v1/webhooks/:idDelete Webhook
DELETE /v1/webhooks/:idTest Webhook
POST /v1/webhooks/:id/testList Deliveries
GET /v1/webhooks/:id/deliveriesCredentials (Vault)
Encrypted credential storage for AI agents. Values are never returned in API responses.
Store Credential
POST /v1/credentialsBody:
{
"service": "github.com",
"identifier": "bot@example.com",
"value": "MyS3cr3tP@ss!",
"credential_type": "password",
"label": "GitHub bot account",
"expires_at": "2027-01-01T00:00:00Z"
}Types: password, api_key, totp_secret, oauth_token, cookie, other
Response (201):
{
"id": "cred_abc123",
"service": "github.com",
"identifier": "bot@example.com",
"credential_type": "PASSWORD",
"stored": true,
"message": "Credential stored securely. Use 'use_credential_in_browser' to fill it into forms."
}List Credentials
GET /v1/credentials
GET /v1/credentials?service=github.comReturns service, identifier, type, label — never the values.
Delete Credential
DELETE /v1/credentials/:idUse Credential (Internal)
POST /v1/credentials/useDecrypts a credential for browser injection. Called by the MCP server's use_credential_in_browser tool. The plaintext is sent to the browser and never returned to the agent.
Audit Log
GET /v1/credentials/audit?limit=50Returns access logs for all credential operations.
Inbound Email (Internal)
Used by the mail server to deliver emails to the API.
POST /v1/inbound
Authorization: Bearer {INBOUND_SECRET}Body:
{
"from": "sender@example.com",
"to": ["inbox@lumbox.co"],
"subject": "Your verification code",
"text": "Your code is 847291",
"html": "<p>Your code is <b>847291</b></p>",
"headers": { "Message-ID": "<abc@example.com>" },
"attachments": [
{
"filename": "doc.pdf",
"content_type": "application/pdf",
"size": 12345,
"content": "base64..."
}
]
}Email Object
All email responses include:
{
"id": "eml_abc123",
"inbox_id": "inb_abc123",
"message_id": "<msg@domain>",
"thread_id": "thr_abc123",
"from_address": "sender@example.com",
"from_name": "Sender Name",
"to_addresses": [{ "name": null, "address": "inbox@lumbox.co" }],
"cc_addresses": [],
"subject": "Your verification code",
"text_body": "Your code is 847291",
"html_body": "<p>...</p>",
"stripped_text": "Your code is 847291",
"category": "verification",
"summary": "Verification email with OTP code",
"otp_codes": ["847291"],
"verification_links": [],
"magic_links": [],
"backup_codes": [],
"code_expiry": "2026-02-27T10:05:00Z",
"is_read": false,
"has_attachments": false,
"received_at": "2026-02-27T10:00:00Z"
}Error Responses
{ "error": "Description of the error" }| Status | Meaning |
|---|---|
| 400 | Bad request (missing/invalid fields) |
| 401 | Invalid API key or inbound secret |
| 403 | Forbidden (resource belongs to another org) |
| 404 | Resource not found |
| 408 | Timeout (wait/otp endpoints) |
| 409 | Conflict (duplicate address, etc.) |
| 500 | Internal server error |
| 503 | Inbox is paused |
Health Check
GET /health{ "status": "ok" }