Emelia Inbox API

The Emelia Inbox API lets your code or an AI agent list, search and read the emails of your mailboxes, label them, prepare drafts and send replies. Same API key as the Emelia API, its own quotas.

The Emelia Inbox API is the programmatic side of the Emelia unified inbox (the Inbox tab of the app). It lets your code or an AI agent list, search and read the emails of the mailboxes connected to Emelia, organise them with labels, AI label rules, saved views and inbox filters, prepare drafts for a human to review, send replies, and forward emails automatically.

Base URL and key

The Inbox API lives on the same host as the Emelia API, under /inbox/api/v1, and takes the same API key: the one you create in Settings, API & Webhooks.

Emelia APIEmelia Inbox API
Base URLhttps://api.emelia.iohttps://api.emelia.io/inbox/api/v1
CoversCampaigns, contacts, enrichment, LinkedInThe emails of the inbox
Errors{ "error", "code"? }{ "code", "error", "details"? }
QuotasSee Rate limitsSee Quotas below

The full contract is also available as an OpenAPI file: /openapi/inbox.json.

Authentication

Send your API key in the Authorization header on every call, as is (a Bearer prefix is accepted too). The workspace comes from the key: no path carries a workspace id, so a key only reaches the inbox of its own Emelia account.

The key can send emails

As on the rest of the Emelia API, a key has every right: it reads every email of the inbox, and it can send emails, create auto-forward rules and turn on auto-reply. Give one key to each integration, and keep it on your server.

An unknown or disabled key gets 401 INVALID_API_KEY. Disabling a key in Emelia can take up to 5 minutes to apply to the Inbox API. A workspace whose Emelia subscription ended gets 403 WORKSPACE_SUSPENDED.

List and read emails

GET/emails
curl "https://api.emelia.io/inbox/api/v1/emails?folderType=INBOX&limit=50" \
  -H "Authorization: $EMELIA_API_KEY"
  • Pagination: pass nextCursor back as cursor, and stop when hasMore is false. nextCursor is only null on an empty page, so do not stop on it. limit is 50 by default, 200 at most.
  • Folders: without folderType, every folder is listed, spam and trash included. With folderType=INBOX, the emails hidden by inbox filters are left out; filtered=only returns them instead.
  • Body: lists never include the body. Read it, with the whole conversation, with Get the body and thread.
  • Search: Search emails by keyword takes 2 to 200 characters. Known issue: a search parameter on GET /emails ignores filters and filtered; do not combine them.
  • Every read is cancelled after 10 seconds (408 QUERY_TIMEOUT).

Send a reply

POST/drafts/send
curl -X POST https://api.emelia.io/inbox/api/v1/drafts/send \
  -H "Authorization: $EMELIA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: reply-claire-2026-10-13" \
  -d '{
    "mailboxId": "cmbxacme0000000000000001",
    "to": [{ "email": "claire.fontaine@nexora.io", "name": "Claire Fontaine" }],
    "subject": "Re: Quick question about Nexora",
    "inReplyTo": "<CAF7x2y3z@mail.nexora.io>",
    "references": ["<CAF7x2y3z@mail.nexora.io>"],
    "body": { "text": "Hi Claire,\n\nTuesday 10am works for me.", "html": "<p>Hi Claire,</p><p>Tuesday 10am works for me.</p>" }
  }'

To reply in a thread: send from the mailboxId of the original email, set inReplyTo to its messageId, references to its references followed by its messageId, and prefix the subject with Re: . The signature of the mailbox is added by default. Attachments cannot be sent through the API.

Sending is irreversible

Always send an Idempotency-Key. Known issue: if the message left but a later step failed, the API answers 500 INTERNAL_ERROR and a retry sends the message again. After a 500, look in the SENT folder before retrying. For a human in the loop, create a draft instead: it waits in the inbox for review.

Organise the inbox

NeedRoutes
Mark read, star, trashMark read or starred, Move an email to the trash, Bulk update emails
Labels you apply yourselfLabels, then Apply a label to an email
Labels applied by AI from a plain language condition, with optional auto-draft and auto-replyAI label rules
Saved filters, read with GET /emails?viewId=Views
Hide emails from the main inbox without moving themInbox filters
Forward matching emails automaticallyAuto-forward rules

AI work triggered by the inbox (classification of each incoming email while an AI label rule exists, auto-drafts) is paid with Emelia credits.

Quotas

Counted per Emelia account (every key shares them), over a sliding minute and a calendar month in UTC. They are separate from the rate limits of the Emelia API:

LimitPer Emelia account
Requests per minute60
Requests per month10,000
Active webhooks1

One request costs 1 unit. POST /emails/bulk costs one unit per id, checked against the per minute limit too: send at most 60 ids per call. Units are counted when the request comes in, even if it then fails validation. Over a limit, the API answers 429 RATE_LIMIT_EXCEEDED with Retry-After, or 429 QUOTA_EXCEEDED for the month. Responses carry X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-RateLimit-Quota, X-RateLimit-Quota-Remaining and X-RateLimit-Quota-Reset.

Conventions

  • JSON in and out, bodies of 256 KB at most (413 PAYLOAD_TOO_LARGE). Dates are ISO 8601 in UTC. Ids are opaque strings.
  • Errors: { "code", "error", "details"? }. Branch on code. A resource of another workspace answers 404, never 403. An email not found answers NOT_FOUND on some routes and EMAIL_NOT_FOUND on others: treat both the same.
  • Idempotency-Key (255 characters at most) is supported on the creating POST routes. A successful response is kept 24 hours and replayed with Idempotent-Replay: true; the same key with another request answers 409 CONFLICT. Keys are scoped to the workspace, not to the API key.
  • An unknown path answers an HTML 404 page.

Webhooks

Six events can be pushed to your endpoint: email.received, email.updated, email.deleted, draft.sent, label.applied and mailbox.sync_failed. Each delivery is a POST with { "event", "createdAt", "data" }, an X-Maylee-Event header and an X-Maylee-Signature header (t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">, keyed with the webhook secret). Reject deliveries older than 300 seconds and compare signatures in constant time. A delivery succeeds on a 2xx within 10 seconds; failures are retried 4 times over about 8 hours.

Registering a webhook

Webhook subscriptions cannot be created with an API key, and Emelia has no screen for them yet. Contact contact@emelia.io if you need one.

The payload of each event is on its page, under Webhook events in this section.

On this page