LumboxLumbox Docs

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_here

The inbound webhook uses a separate secret:

Authorization: Bearer {INBOUND_SECRET}

Organizations

Create Organization

POST /v1/orgs

Body:

{ "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/me

Response (200):

{
  "id": "org_abc123",
  "name": "my-org",
  "inbox_count": 5,
  "domain_count": 1,
  "api_key_count": 2,
  "created_at": "2026-02-27T10:00:00Z"
}
POST /v1/orgs/me/claim

Requires a full organization API key with wildcard scope. Project keys, inbox-restricted keys, OAuth tokens, and internal service credentials are refused. Organizations must be active and have no owner. The link is single use and expires after 15 minutes. An account that already owns an organization cannot claim another one.

Response (201):

{
  "org_id": "org_abc123",
  "claim_url": "https://app.lumbox.co/claim/start?token=...",
  "expires_at": "2026-10-02T10:15:00.000Z"
}

Open the URL, sign in or sign up, and confirm the organization. Successful claims continue to billing. Do not share claim URLs publicly.

Create API Key

POST /v1/orgs/me/api-keys

Body:

{ "name": "production", "scopes": ["inboxes:read", "inboxes:write"] }

Response (201):

{
  "id": "ak_id_abc",
  "key_prefix": "ak_live_abc...",
  "api_key": "ak_live_full_key_here",
  "name": "production",
  "scopes": ["inboxes:read", "inboxes:write"]
}

Inboxes

Create Inbox

POST /v1/inboxes

Body:

{
  "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/inboxes

Response (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/:id

Delete Inbox

DELETE /v1/inboxes/:id

Permanently deletes the inbox and all its emails.

List Emails in Inbox

GET /v1/inboxes/:id/emails

Query params:

ParamTypeDescription
limitnumberMax results (default: 20, max: 100)
cursorstringPagination cursor
fromstringFilter by sender (substring match)
categorystringFilter by category
sincestringISO timestamp - only emails after this
unreadbooleanOnly unread emails

Response (200):

{
  "data": [/* email objects */],
  "cursor": "next_cursor_value",
  "has_more": true
}

Get Email

GET /v1/inboxes/:id/emails/:emailId

Returns full email with attachments.

Wait for Email

GET /v1/inboxes/:id/wait

Long-polls until a matching email arrives. Polls DB every 1 second.

Query params:

ParamTypeDescription
timeoutnumberMax seconds to wait (default: 30, max: 120)
fromstringFilter by sender
subjectstringFilter by subject keyword
categorystringFilter by category
has_otpbooleanOnly emails with OTP codes
sincestringISO timestamp

Response (200): Full email object

Response (408): Timeout - no matching email arrived

Get OTP

GET /v1/inboxes/:id/otp

Long-polls for the latest verification code. The simplest way to get an OTP.

Query params:

ParamTypeDescription
timeoutnumberMax seconds (default: 30, max: 120)
fromstringFilter by sender
sincestringISO timestamp (default: 5 minutes before the request)

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"
}

Response (408): No OTP arrived before the timeout. For concurrent logins, see Parallel login runs.


Emails

Get Email (by ID)

GET /v1/emails/:id

Update Email

PATCH /v1/emails/:id

Body:

{ "is_read": true }

Delete Email

DELETE /v1/emails/:id

Search Emails

GET /v1/emails

Search across all inboxes in your organization.

Query params:

ParamTypeDescription
qstringSearch subject, body, summary
fromstringFilter by sender (substring)
categorystringFilter by category
inbox_idstringLimit to specific inbox
sincestringISO timestamp
limitnumberMax results (default: 20, max: 100)

Send / Reply / Forward

Send Email

POST /v1/inboxes/:id/send

Body:

{
  "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/reply

Body:

{
  "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/forward

Body:

{
  "email_id": "eml_abc123",
  "to": "someone@example.com",
  "comment": "FYI - see below"
}

Threads

List Threads

GET /v1/threads

Query params:

ParamTypeDescription
inbox_idstringFilter by inbox
limitnumberMax 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/:threadId

Returns 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/assign

Body:

{
  "agent_id": "support-bot",
  "role": "OWNER"
}

Roles: OWNER, PARTICIPANT, OBSERVER (default: PARTICIPANT)

Upsert - re-assigning updates the role.

Unassign Agent

POST /v1/threads/:id/unassign

Body:

{ "agent_id": "support-bot" }

List Thread Agents

GET /v1/threads/:id/agents

Domains

Add Domain

POST /v1/domains

Body:

{ "domain": "mycompany.com" }

Response (201):

{
  "id": "dom_abc123",
  "domain": "mycompany.com",
  "status": "PENDING",
  "dns_records": {
    "verification": { "type": "TXT", "name": "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/verify

Checks 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/domains

Delete Domain

DELETE /v1/domains/:id

SMTP Configs (BYOS)

Bring Your Own SMTP - configure custom outbound email providers.

Create Config

POST /v1/smtp-configs

Body:

{
  "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-configs

Passwords and API keys are masked in the response.

Delete Config

DELETE /v1/smtp-configs/:id

Test Config

POST /v1/smtp-configs/:id/test

Body:

{ "to": "test@example.com" }

Set Default

PATCH /v1/smtp-configs/:id/default

Routing Rules

Auto-assign agents to threads based on email properties.

Create Rule

POST /v1/routing-rules

Body:

{
  "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-rules

Update Rule

PATCH /v1/routing-rules/:id

Delete Rule

DELETE /v1/routing-rules/:id

Webhooks

Create Webhook

POST /v1/webhooks

Body:

{
  "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/webhooks

Update Webhook

PATCH /v1/webhooks/:id

Delete Webhook

DELETE /v1/webhooks/:id

Test Webhook

POST /v1/webhooks/:id/test

List Deliveries

GET /v1/webhooks/:id/deliveries

Credentials (Vault)

Encrypted credential storage for AI agents. Values are never returned in API responses.

Store Credential

POST /v1/credentials

Body:

{
  "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.com

Returns service, identifier, type, label - never the values.

Delete Credential

DELETE /v1/credentials/:id

Use Credential (Internal)

POST /v1/credentials/use

Decrypts 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=50

Returns 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" }
StatusMeaning
400Bad request (missing/invalid fields)
401Invalid API key or inbound secret
403Forbidden (resource belongs to another org)
404Resource not found
408Timeout (wait/otp endpoints)
409Conflict (duplicate address, etc.)
500Internal server error
503Inbox is paused

Health Check

GET /health
{ "status": "ok" }