# InboxAgents API

- [Introduction](https://docs.theinboxagents.com/docs): Email infrastructure for AI agents — provision an inbox in one API call, then receive and read mail over a simple REST API.
- [Quickstart](https://docs.theinboxagents.com/docs/quickstart): Provision an inbox, send it a test email, receive the arrival, and read the message — the full provision → receive → read loop in REST, TypeScript, Python, and the CLI.
- [Connect an AI assistant (MCP)](https://docs.theinboxagents.com/docs/connect-ai-assistant): Give an AI assistant its own email inboxes — connect Claude or ChatGPT point-and-click, or wire InboxAgents into a coding tool with the developer setup.
- [Authentication](https://docs.theinboxagents.com/docs/authentication): Authenticate every request with a single API key — plus permissions, inbox scoping, and the whoami identity check.
- [Errors](https://docs.theinboxagents.com/docs/errors): One consistent error envelope across the whole API, with a stable machine-readable name for every condition.
- [Pagination](https://docs.theinboxagents.com/docs/pagination): Every list endpoint pages the same way — a cursor token, a consistent envelope, and newest-first ordering by default.
- [Rate limits](https://docs.theinboxagents.com/docs/rate-limits): Per-key request limits, the 429 response with Retry-After, and how to back off correctly.

- **API reference**
- Api keys
  - [Create an API key](https://docs.theinboxagents.com/docs/api-keys/createApiKey): Create a named, organization-scoped API key. With no `permissions` the
key has full access; supply a `permissions` object to restrict it to a
whitelist (only flags set `true` are granted). The raw `secret` is
returned **once** in this response and never again — store it now. A
restricted key that tries to mint a child with more permissions than
itself is forbidden, and the per-tenant key limit is enforced.
  - [Create an inbox-scoped API key](https://docs.theinboxagents.com/docs/api-keys/createInboxApiKey): Create an API key pinned to this inbox (`scope_type=inbox`). The key can
only ever operate on this one inbox. Otherwise identical to creating an
organization key: the raw `secret` is returned **once**, and the
no-escalation and key-limit rules apply. A key not permitted this inbox,
or attempting to broaden its own scope, is forbidden.
  - [Revoke an API key](https://docs.theinboxagents.com/docs/api-keys/deleteApiKey): Revoke (hard-delete) an API key by id. The revoke is effective
immediately on every surface — the key stops authenticating at once. An
unknown, already-revoked, or cross-tenant id returns not-found; a revoke
is never silently successful on a missing key.
  - [List API keys](https://docs.theinboxagents.com/docs/api-keys/listApiKeys): List the tenant's API keys, newest-first by default, with cursor
pagination. Each entry carries the name, non-secret prefix, permissions,
scope, and created/last-used timestamps — **never the secret**, which is
shown only once at creation.
- Auth
  - [Identity and scope of the calling key](https://docs.theinboxagents.com/docs/auth/whoAmI): Return the calling API key's **identity and scope** — the canonical
"is my key valid, and what can it see?" probe. Returns identity/scope
only; it never returns plan or limits (see `/metrics/usage` for usage).

`scope_type` is `organization` for a key that reaches the whole tenant,
or `inbox` for a key pinned to a single inbox. `scope_id` is the id that
scope resolves to — the tenant for an organization key, the inbox for an
inbox key. `inbox_id` is present only for an inbox-scoped key.
- Diagnostics
  - [Resolve the authenticated tenant](https://docs.theinboxagents.com/docs/diagnostics/whoami): Echoes the tenant the presented API key resolves to. Useful as an
"is my key valid?" check. Returns `401` if the key is missing/invalid.
- Inboxes
  - [Create an inbox](https://docs.theinboxagents.com/docs/inboxes/createInbox): Create an inbox and get back a live, addressable email identity. Every
field is optional: omit `username` and a readable random address is
generated on the shared domain. Supply a `client_id` for idempotency —
repeating a create with the same `client_id` returns the existing inbox
(`200`) instead of creating a duplicate.
  - [Delete an inbox](https://docs.theinboxagents.com/docs/inboxes/deleteInbox): Hard-delete an inbox and its stored mail; the address is quarantined for
a cooling-off period before it can be reused. An unknown, already-deleted,
or cross-tenant id returns not-found — a delete is never silently
successful on a missing inbox.
  - [Get an inbox](https://docs.theinboxagents.com/docs/inboxes/getInbox): Fetch a single inbox by id. An unknown id and an id belonging to another
tenant both return the same not-found error — existence is never leaked.
  - [List inboxes](https://docs.theinboxagents.com/docs/inboxes/listInboxes): List the inboxes belonging to the authenticated tenant, newest-first by
default, with cursor pagination. An account with no inboxes gets an empty
list, not an error.
  - [Update an inbox](https://docs.theinboxagents.com/docs/inboxes/updateInbox): Partially update an inbox's `display_name` and/or `metadata`. At least
one field must be supplied. Metadata merges: supplied keys are set, a key
with a `null` value is removed, and `metadata: null` clears all metadata.
The `email` address is immutable.
- Messages
  - [Get an attachment download URL](https://docs.theinboxagents.com/docs/messages/getAttachment): Returns the attachment's metadata plus a short-lived presigned
`download_url` — the client fetches the bytes from that URL. The URL
expires (`expires_at`); re-call this endpoint to mint a fresh one.
Unknown/cross-tenant ids return an indistinguishable `404`.
  - [Get a single message](https://docs.theinboxagents.com/docs/messages/getMessage): Returns the full structured message — parsed sender/recipients, `text`/
`html` bodies, the reply-history-stripped `extracted_*`, `headers`,
threading headers, and the attachment list. A `spam`-labeled message
requires the key's `label_spam_read` permission. Unknown/cross-tenant
inbox or message ids return an indistinguishable `404`.
- Metrics
  - [Cumulative usage time-series](https://docs.theinboxagents.com/docs/metrics/getUsage): Return usage as a **cumulative time-series**: for each requested
`usage_types` dimension, a list of `{ timestamp, value }` points where
`value` is the **running total** at that bucket boundary. Counts
(`inbox_count`, `message_count`, `thread_count`) accumulate over the
window; `storage_bytes` reports the current live counter at each point.

The window is `start`–`end` (ISO-8601, at most 90 days apart), bucketed by
`period` seconds. The number of buckets — `(end − start) ÷ period` — may
not exceed 500; use a larger `period` for a longer window. `limit` takes
at most that many buckets from the tail of the window, and `descending`
returns the newest bucket first.

Requires the key's `metrics_read` permission; a key without it gets `403`.
- Onboarding
  - [Sign up an agent and get a key + inbox](https://docs.theinboxagents.com/docs/onboarding/signUp): Provision a brand-new account entirely in code: this creates a tenant, a
first inbox, and a first API key, then emails a 6-digit verification code
to `human_email`. Call `verify` with that code to activate the account.

This is the one unauthenticated endpoint — you use it to obtain your
first API key, so there is no key to present yet.

The `api_key` in the response is shown **once** and is never retrievable
again — store it securely. Calling `sign_up` again with the same
`human_email` is safe and idempotent: it returns the **same** account with
a freshly **rotated** `api_key` (the previous key stops working) and
re-sends the verification code if the previous one has expired — it never
creates a duplicate account.
  - [Verify an agent account with its OTP](https://docs.theinboxagents.com/docs/onboarding/verify): Activate an account created by `sign_up` by submitting the 6-digit code
emailed to its `human_email`. On success the account is lifted off the
restricted new-account limits to its full plan.

The code expires 10 minutes after it is issued and allows 5 attempts. A
wrong or expired code fails verification; obtain a fresh code by calling
`sign_up` again with the same `human_email`.

Unauthenticated — the account is verified by possession of the code, not
by an API key.
- Threads
  - [Get a thread with its messages (fat get)](https://docs.theinboxagents.com/docs/threads/getThread): Returns the thread plus its **full** messages in chronological
(`timestamp` ascending) order — the complete conversation an agent reads
as memory. A `spam`-labeled thread requires the key's `label_spam_read`
permission. Unknown/cross-tenant inbox or thread ids return an
indistinguishable `404`.
  - [List an inbox's threads (thin list)](https://docs.theinboxagents.com/docs/threads/listThreads): Lists the inbox's threads, most-recently-active first, paginated. Each
entry is the **thin** thread (no `messages[]` — fetch those with
get-thread). Threads labeled `spam` or `unauthenticated` are excluded
unless the matching `include_*` flag is set; opting into `spam`
additionally requires the key's `label_spam_read` permission. An inbox
with no mail returns an empty list; an unknown/cross-tenant inbox is a
`404`.
- Webhooks
  - [Register a webhook scoped to an inbox](https://docs.theinboxagents.com/docs/webhooks/createInboxWebhook): Register a webhook pre-scoped to this inbox — the endpoint only receives
events for this one inbox. Otherwise identical to `POST /webhooks`: `url`
must be HTTPS, `event_types` must list at least one type, and the
response includes the one-time signing secret. Supplying `inbox_ids` in
the body overrides the path scope.
  - [Register a webhook](https://docs.theinboxagents.com/docs/webhooks/createWebhook): Register a webhook endpoint. `url` must be HTTPS and `event_types` must
list at least one event type; `inbox_ids` (max 10) optionally scopes the
endpoint to specific inboxes (omit for all of the tenant's inboxes).
Supply a `client_id` for idempotency — repeating a create with the same
`client_id` returns the existing webhook (`200`). The response includes
the endpoint's **signing secret** (`whsec_…`), returned **only** here —
store it now to verify deliveries.
  - [Delete a webhook](https://docs.theinboxagents.com/docs/webhooks/deleteWebhook): Delete a webhook by id; deliveries to it stop immediately and any
in-flight retries are abandoned. An unknown, already-deleted, or
cross-tenant id returns not-found.
  - [Get a webhook](https://docs.theinboxagents.com/docs/webhooks/getWebhook): Fetch a single webhook by id. An unknown id and an id belonging to
another tenant both return the same not-found error — existence is never
leaked. The signing secret is not included (shown only at creation).
  - [List webhooks](https://docs.theinboxagents.com/docs/webhooks/listWebhooks): List the tenant's webhooks, newest-first by default, with cursor
pagination. The signing secret is never included in a listing — it is
shown only once at creation.
  - [Update a webhook](https://docs.theinboxagents.com/docs/webhooks/updateWebhook): Partially update a webhook's `url`, `event_types`, `inbox_ids`, and/or
`enabled` flag. At least one field must be supplied. `event_types` is
**replace-not-merge** — the supplied array becomes the whole filter set.
Set `enabled: false` to pause deliveries without deleting the endpoint.

## Full text & contract

- Full docs as one file: https://docs.theinboxagents.com/llms-full.txt
- Machine-readable API contract (OpenAPI): the API reference under https://docs.theinboxagents.com/docs
  is generated from a single OpenAPI document.
