Agent Mail by Ackuna

Every page here is also markdown — add .md to the URL.

Inboxes

An inbox is a mailbox address (local_part@domain) that receives inbound mail and sends outbound replies on behalf of your organization.

The inbox object

{
  "id": "inb_01k2n9v8qf3m7d5b0y6xz4rt1c",
  "object": "inbox",
  "address": "orders-bot@agentmail.ackuna.com",
  "local_part": "orders-bot",
  "domain": "agentmail.ackuna.com",
  "display_name": "Support desk",
  "status": "active",
  "thread_count": 42,
  "created_at": "2026-08-14T09:00:00.000Z"
}

status is active or paused. A paused inbox means your agent is not processing it:

An archived inbox receives nothing; mail to its address is not delivered.

List inboxes

GET /v1/inboxes?limit=25
Authorization: Bearer ak_...
{
  "data": [
    {"id": "inb_01k2n9v8qf3m7d5b0y6xz4rt1c", "object": "inbox", "address": "orders-bot@agentmail.ackuna.com", "local_part": "orders-bot", "domain": "agentmail.ackuna.com", "display_name": null, "status": "active", "thread_count": 42, "created_at": "2026-08-14T09:00:00.000Z"}
  ],
  "next_cursor": "eyJpZCI6MTIzfQ",
  "has_more": false
}

Requires scope inboxes:read. Pass ?cursor= from a previous page's next_cursor to continue; ?limit= is 1–100, default 25.

Create an inbox

POST /v1/inboxes
Authorization: Bearer ak_...
Content-Type: application/json
Idempotency-Key: create-billing-inbox-1

{"username": "ledger-bot"}
{
  "data": {
    "id": "inb_01k2n9v8qf3m7d5b0y6xz4rt2d",
    "object": "inbox",
    "address": "ledger-bot@agentmail.ackuna.com",
    "local_part": "ledger-bot",
    "domain": "agentmail.ackuna.com",
    "display_name": null,
    "status": "active",
    "thread_count": 0,
    "created_at": "2026-08-20T14:00:00.000Z"
  }
}

Requires scope inboxes:write. Fields:

Field Required Notes
username yes Lowercased local part. [a-z0-9], ., _ or - internally, up to 64 characters.
domain no A dom_... id of an active receiving domain you own, or the shared platform domain's name (agentmail.ackuna.com). Omitted → the inbox is hosted on agentmail.ackuna.com. The earlier shared domain agents.ackuna.com can no longer be chosen for new inboxes (422 domain_not_allowed); inboxes already on it keep sending and receiving.

Failure modes specific to this endpoint: 422 address_taken if the address already exists; 422 local_part_not_allowed if the username is reserved or contains a brand, payment or sign-in term and the inbox would be on the shared platform domain (see below); 409 domain_not_ready if domain names a domain that is not yet active; 422 domain_not_allowed if domain names an older shared domain such as agents.ackuna.com, which keeps its existing inboxes but takes no new ones; 403 quota_exceeded if the organization's inbox quota is exhausted. An inbox keeps the domain it was created on.

On the shared platform domain some names are not available, because mail from agentmail.ackuna.com goes out under Ackuna's own identity. A role address is refused as the whole name (postmaster, abuse, support, billing, noreply, ...). A few role words (admin, root, postmaster, abuse, security, official, no-reply, ...) are refused anywhere in the name, as a word of their own, so security-team is refused while acme-support is not. A name that contains a brand, payment or sign-in term (paypal, invoice, login, ...) is refused, digit look-alikes such as paypa1 included. The error does not say which rule matched. On a custom domain you own, any name is allowed.

Fetch an inbox

GET /v1/inboxes/inb_01k2n9v8qf3m7d5b0y6xz4rt1c
Authorization: Bearer ak_...

Requires scope inboxes:read. Returns the inbox object, or 404 not_found for an unknown or cross-organization id.

Pause, resume, or rename an inbox

PATCH /v1/inboxes/inb_01k2n9v8qf3m7d5b0y6xz4rt1c
Authorization: Bearer ak_...
Content-Type: application/json
Idempotency-Key: pause-billing-inbox-1

{"status": "paused"}
{
  "data": {
    "id": "inb_01k2n9v8qf3m7d5b0y6xz4rt2d",
    "object": "inbox",
    "address": "ledger-bot@agentmail.ackuna.com",
    "local_part": "ledger-bot",
    "domain": "agentmail.ackuna.com",
    "display_name": null,
    "status": "paused",
    "thread_count": 0,
    "created_at": "2026-08-20T14:00:00.000Z"
  }
}

Requires scope inboxes:write. Both fields are optional and independent — send only what you want to change:

Field Notes
display_name Nullable string, up to 255 characters. It becomes the From name of the inbox's mail, so on the shared platform domain a name that contains a brand, payment or sign-in term is refused with 422 display_name_not_allowed. Role words are fine here ("Support desk"). On a custom domain any name is allowed.
status active or paused. Pausing holds inbound mail and stops sending; resuming releases the held mail's webhooks (see the inbox object).

Archive an inbox

DELETE /v1/inboxes/inb_01k2n9v8qf3m7d5b0y6xz4rt1c
Authorization: Bearer ak_...
Idempotency-Key: archive-billing-inbox-1

Responds 204 No Content. Requires scope inboxes:write.

Archiving frees the inbox's quota slot and hides it everywhere — it stops receiving mail, no longer appears in GET /v1/inboxes, and no longer resolves by id (a later GET, PATCH, or DELETE for it returns 404 not_found). Its threads, messages, and attachments follow the same retention as any other inbox: message bodies and attachments are removed after 90 days and the messages themselves after 180 days, unless your plan sets other windows.

The address is not released. The shared platform domain hosts inboxes for many organizations, so a retired address stays reserved: it can never be re-created (a later POST /v1/inboxes for the same address returns 422 address_taken), which stops a different organization from claiming it and receiving the prior owner's mail.

Returns 404 not_found for an unknown or cross-organization id.

Next: Threads group an inbox's messages into conversations, and Messages covers reading and sending.