{"openapi":"3.1.0","info":{"title":"Mails.ai API","version":"0.2.0","description":"The Mails.ai API gives AI agents a real email identity: send and receive\ntransactional email, with every inbound message run through an intent + prompt-injection classifier\nand delivered to you as a typed event.\n\n## Authentication\nAll endpoints take a Bearer API key:\n\n```\nAuthorization: Bearer mk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n```\n\nKeys carry one or more scopes — `send`, `read`, `manage` — and a mode: **live** (`mk_live_…`) or\n**test** (`mk_test_…`).\n\n## Test mode\nA `mk_test_` key exercises the entire API — real validation, persisted resources, real\n`message.sent`/`*.received` events and webhooks — without sending real email or incurring cost. Build and\ntest your whole integration on a test key, then flip one character to `mk_live_` to go live.\n`POST /v1/test/inbound` (test key only) lets you simulate inbound mail end-to-end.\n\n## Idempotency\nSend endpoints accept an `Idempotency-Key` header; a repeated key replays the stored response instead of\nsending twice.\n\n## Pagination\nList endpoints are cursor-paginated: pass `limit` (1–100) and the `next_cursor` from the previous page.\n\n## Errors\nErrors use a stable envelope: `{ \"error\": { \"type\", \"code\", \"message\", \"param\", \"request_id\" } }`. Every\nresponse carries an `X-Request-Id` header for support correlation.","contact":{"name":"Mails.ai Support","url":"https://mails.ai","email":"support@mails.ai"},"license":{"name":"Proprietary","identifier":"LicenseRef-Proprietary"}},"servers":[{"url":"https://api.mails.ai","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Messages","description":"Send, list, retrieve, reply, forward, schedule, and cancel email."},{"name":"Inbound","description":"Received messages and the test-key inbound simulator."},{"name":"Drafts","description":"Compose, edit, schedule, and send drafts."},{"name":"Threads","description":"Conversation threads grouping inbound + outbound messages."},{"name":"Events","description":"Typed events (incl. classifier output) and the SSE live stream."},{"name":"Agents","description":"Per-agent email identities and their sending policy."},{"name":"Domains","description":"Bring-your-own custom sending domains (records-only DNS verification)."},{"name":"Webhooks","description":"Endpoint registration, delivery history, test, and replay."},{"name":"Suppression","description":"Suppression lookups and the consent allowlist."},{"name":"Reputation","description":"Workspace- and agent-level deliverability reputation."},{"name":"API Keys","description":"Create, list, and revoke API keys."},{"name":"Billing","description":"Usage metering and the Stripe billing portal."},{"name":"Logs","description":"Audit trail of state-changing operations."},{"name":"Account","description":"Identify the current API key."},{"name":"Public","description":"Unauthenticated endpoints (health, unsubscribe link targets)."}],"paths":{"/v1/messages":{"post":{"tags":["Messages"],"summary":"Send a message","operationId":"sendMessage","description":"**Requires scope:** `send`. Sends an email from one of your agents. With a `mk_test_` key the message is stored and its `message.sent` event reaches your webhooks (marked `test_mode: true`), but no email is sent and nothing is billed. Quota, suppression and rate-limit refusals are skipped, and a message the cold-email firewall would refuse comes back 201 with `classifier_warning` instead.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Replays the stored response for a repeated key, so a retried request never double-sends."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"},"example":{"agent":"support","to":"jordan@example.com","subject":"Your order #10473 has shipped","body_html":"<p>Hi Jordan,</p><p>Your order <strong>#10473</strong> is on its way and should arrive in 2–3 business days. You can track it any time from your account.</p>","body_text":"Hi Jordan,\n\nYour order #10473 is on its way and should arrive in 2–3 business days. You can track it any time from your account.","tags":[{"name":"category","value":"shipping"}]}}}},"responses":{"201":{"description":"Message accepted (sent or scheduled).","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests permitted in the current window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the rate-limit window resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentMessage"},"example":{"id":"msg_01JZX8K3M9Q4P7VN2YB6RTDC0E","agent_id":"agt_01JZ9F8H7KQ2M3N4P5R6S7T8U9","thread_id":"thrd_01JZX8K3M9Q4P7VN2YB6RTDC11","to":["jordan@example.com"],"subject":"Your order #10473 has shipped","classifier_score":0.02,"status":"sent","cost_usd":0.0004,"tags":[{"name":"category","value":"shipping"}],"test_mode":false,"created_at":"2026-06-24T17:32:08.421Z"}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required / feature not enabled on the current plan. The error object carries `upgrade_url` — the dashboard page where the plan can be changed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict — duplicate resource or an in-progress idempotent request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Unprocessable — agent paused/archived, recipient suppressed, or abuse guard.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate or quota limit exceeded. Honor the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Upstream (email transport) failure.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"send"},"get":{"tags":["Messages"],"summary":"List sent messages","operationId":"listMessages","description":"**Requires scope:** `read`.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size (1–100)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a previous page's `next_cursor`."},{"name":"agent_id","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by agent id or name."},{"name":"thread_id","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by thread id."}],"responses":{"200":{"description":"A page of sent messages.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SentMessage"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","description":"Pass as `cursor` to fetch the next page. Absent on the last page."}},"required":["data","has_more"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/messages/batch":{"post":{"tags":["Messages"],"summary":"Send a batch of messages","operationId":"batchSendMessages","description":"**Requires scope:** `send`. Sends up to 100 messages in one request. Per-message failures are returned inline in `data[]` and do not fail the batch; the HTTP status is still 201.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Replays the stored response for a repeated key, so a retried request never double-sends."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchSendRequest"},"example":[{"agent":"support","to":"jordan@example.com","subject":"Your receipt for order #10473","body_text":"Thanks for your purchase — your receipt is attached below."},{"agent":"support","to":"alex@example.com","subject":"Your receipt for order #10474","body_text":"Thanks for your purchase — your receipt is attached below."}]}}},"responses":{"201":{"description":"Per-message results (success or error objects) plus the submitted batch size.","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests permitted in the current window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the rate-limit window resets."}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"oneOf":[{"$ref":"#/components/schemas/SentMessage"},{"$ref":"#/components/schemas/Error"}]}},"batch_size":{"type":"integer"}},"required":["data","batch_size"]},"example":{"data":[{"id":"msg_01JZX8K3M9Q4P7VN2YB6RTDC0E","agent_id":"agt_01JZ9F8H7KQ2M3N4P5R6S7T8U9","thread_id":"thrd_01JZX8K3M9Q4P7VN2YB6RTDC11","to":["jordan@example.com"],"subject":"Your receipt for order #10473","classifier_score":0.01,"status":"sent","cost_usd":0.0004,"test_mode":false,"created_at":"2026-06-24T17:32:08.421Z"},{"error":{"type":"abuse_error","code":"recipient_suppressed","message":"Recipient alex@example.com is suppressed (hard_bounce, global).","param":"to","request_id":"req_01JZX8K3M9Q4P7VN2YB6RTDC22"}}],"batch_size":2}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict — duplicate resource or an in-progress idempotent request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"send"}},"/v1/messages/appeal":{"post":{"tags":["Messages"],"summary":"Appeal a cold-firewall refusal","operationId":"appealMessage","description":"**Requires scope:** `send`. Requests a second, independent review of content refused with `cold_email_prohibited`. Submit the SAME subject and body the refused send used. An independent reviewer re-judges it under the identical policy: `overturned` clears exactly that content for 24 hours (the identical send then goes through on the isolated pool); `upheld` means the refusal stands; `not_appealable` means the block is deterministic policy (prohibited content, bulk list language, multi-signal cold pitches) and no review exists; `not_blocked` means the content is not refused at all. Identical content replays its stored outcome — an appeal is never a re-roll. Limit: 10 appeals per workspace per 24 hours.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agent":{"type":"string","description":"Agent name or id the refused send used. Optional — omitted, the workspace's single agent is assumed (the refused send itself created one if none existed)."},"subject":{"type":"string","description":"The refused message's subject, verbatim."},"body_text":{"type":"string","description":"The refused message's body_text, verbatim."},"body_html":{"type":"string","description":"The refused message's body_html, verbatim."}}}}}},"responses":{"200":{"description":"The review outcome.","content":{"application/json":{"schema":{"type":"object","properties":{"outcome":{"type":"string","enum":["overturned","upheld","not_appealable","not_blocked"]},"message":{"type":"string","description":"Human-readable explanation of the outcome and what to do next."},"review_score":{"type":"number","description":"The second reviewer's cold score (0 = clearly transactional, 1 = clearly cold). Absent for not_appealable/not_blocked."},"reason":{"type":"string","description":"The reviewer's one-line reason, when a review ran."},"replayed":{"type":"boolean","description":"True when this outcome was served from a prior appeal of identical content."}},"required":["outcome","message"]}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate or quota limit exceeded. Honor the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"send"}},"/v1/messages/{id}":{"get":{"tags":["Messages"],"summary":"Retrieve a sent message","operationId":"getMessage","description":"**Requires scope:** `read`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Sent message id (`msg_…`)."}],"responses":{"200":{"description":"The message, including full body and delivery timestamps.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentMessage"},"example":{"id":"msg_01JZX8K3M9Q4P7VN2YB6RTDC0E","agent_id":"agt_01JZ9F8H7KQ2M3N4P5R6S7T8U9","thread_id":"thrd_01JZX8K3M9Q4P7VN2YB6RTDC11","to":["jordan@example.com"],"cc":[],"subject":"Your order #10473 has shipped","body_text":"Hi Jordan,\n\nYour order #10473 is on its way and should arrive in 2–3 business days.","body_html":"<p>Hi Jordan,</p><p>Your order <strong>#10473</strong> is on its way and should arrive in 2–3 business days.</p>","classifier_score":0.02,"status":"sent","cost_usd":0.0004,"ses_message_id":"0100018f9c2a7b3d-2a1c4e6f-8b0d-4f2a-9c3e-1d5a7b9c0e2f-000000","attachments":[],"references":[],"metadata":{},"tags":[{"name":"category","value":"shipping"}],"sent_at":"2026-06-24T17:32:09.002Z","delivered_at":"2026-06-24T17:32:11.880Z","created_at":"2026-06-24T17:32:08.421Z","test_mode":false}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"},"patch":{"tags":["Messages"],"summary":"Reschedule a scheduled message","operationId":"rescheduleMessage","description":"**Requires scope:** `manage`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Sent message id with status `scheduled`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RescheduleMessageRequest"},"example":{"scheduled_at":"2026-06-25T14:00:00.000Z"}}}},"responses":{"200":{"description":"The updated schedule.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"scheduled_at":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["scheduled"]}},"required":["id","status"]}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"}},"/v1/messages/{id}/reply":{"post":{"tags":["Messages"],"summary":"Reply to a message","operationId":"replyMessage","description":"**Requires scope:** `send`. Replies in-thread to a sent or received message. Sets In-Reply-To, References, and a `Re:` subject server-side.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The message being replied to (`msg_…` or `rcv_…`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplyMessageRequest"},"example":{"body_text":"Thanks for the update — that delivery window works for us.","reply_all":false}}}},"responses":{"201":{"description":"The reply message.","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests permitted in the current window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the rate-limit window resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentMessage"},"example":{"id":"msg_01JZXC1A3B5C7D9E1F3G5H7J9K","agent_id":"agt_01JZ9F8H7KQ2M3N4P5R6S7T8U9","thread_id":"thrd_01JZX8K3M9Q4P7VN2YB6RTDC11","in_reply_to_message_id":"rcv_01JZXA2B4C6D8E0F2G4H6J8K0M","to":["jordan@example.com"],"cc":[],"subject":"Re: Your order #10473 has shipped","status":"sent","cost_usd":0.0004,"created_at":"2026-06-24T18:04:55.120Z"}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Unprocessable — agent paused/archived, recipient suppressed, or abuse guard.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate or quota limit exceeded. Honor the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Upstream (email transport) failure.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"send"}},"/v1/messages/{id}/forward":{"post":{"tags":["Messages"],"summary":"Forward a message","operationId":"forwardMessage","description":"**Requires scope:** `send`. Forwards a sent or received message to new recipients with a quoted body and `Fwd:` subject. Always sends immediately.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The message being forwarded (`msg_…` or `rcv_…`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForwardMessageRequest"},"example":{"to":"warehouse@example.com","body_text":"Forwarding the shipping confirmation below for your records."}}}},"responses":{"201":{"description":"The forwarded message.","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests permitted in the current window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the rate-limit window resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentMessage"},"example":{"id":"msg_01JZXD2B4C6D8E0F2G4H6J8K1N","agent_id":"agt_01JZ9F8H7KQ2M3N4P5R6S7T8U9","thread_id":"thrd_01JZX8K3M9Q4P7VN2YB6RTDC11","to":["warehouse@example.com"],"subject":"Fwd: Your order #10473 has shipped","status":"sent","cost_usd":0.0004,"created_at":"2026-06-24T18:10:02.340Z","forwarded_from":"msg_01JZX8K3M9Q4P7VN2YB6RTDC0E"}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Unprocessable — agent paused/archived, recipient suppressed, or abuse guard.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate or quota limit exceeded. Honor the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Upstream (email transport) failure.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"send"}},"/v1/messages/{id}/cancel":{"post":{"tags":["Messages"],"summary":"Cancel a scheduled message","operationId":"cancelMessage","description":"**Requires scope:** `manage`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Sent message id with status `scheduled`."}],"responses":{"200":{"description":"The canceled message.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["canceled"]},"canceled_at":{"type":"string","format":"date-time"}},"required":["id","status","canceled_at"]}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"}},"/v1/messages/{id}/raw":{"get":{"tags":["Messages"],"summary":"Download raw RFC822 (.eml)","operationId":"getMessageRaw","description":"**Requires scope:** `read`. Returns a synthetic RFC822 message assembled from stored fields, served as a downloadable `.eml` attachment.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Sent (`msg_…`) or received (`rcv_…`) message id."}],"responses":{"200":{"description":"The raw message. `Content-Disposition: attachment; filename=\"{id}.eml\"`.","content":{"message/rfc822":{"schema":{"type":"string"}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/messages/received":{"get":{"tags":["Inbound"],"summary":"List received messages","operationId":"listReceivedMessages","description":"**Requires scope:** `read`.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size (1–100)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a previous page's `next_cursor`."},{"name":"agent_id","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by agent id or name."},{"name":"thread_id","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by thread id."}],"responses":{"200":{"description":"A page of received messages (excerpts only; fetch one for full body).","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReceivedMessage"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","description":"Pass as `cursor` to fetch the next page. Absent on the last page."}},"required":["data","has_more"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/messages/received/{id}":{"get":{"tags":["Inbound"],"summary":"Retrieve a received message","operationId":"getReceivedMessage","description":"**Requires scope:** `read`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Received message id (`rcv_…`)."}],"responses":{"200":{"description":"The received message, including full body and `raw_url`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceivedMessage"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/test/inbound":{"post":{"tags":["Inbound"],"summary":"Simulate an inbound email (test key)","operationId":"simulateInbound","description":"**Requires scope:** `send`. **Test key only** (`mk_test_…`). Drives the receive/classify half of the product with a hand-supplied envelope: runs the real classifier, threads the message, persists a received row, and emits the same typed event + webhook a real inbound would. Set `in_reply_to_message_id` to a prior test-send id to simulate a `reply.received`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestInboundRequest"},"example":{"agent":"support","from":"jordan@example.com","from_name":"Jordan Lee","subject":"Where is my order #10473?","body_text":"Hi — I haven't received order #10473 yet. Can you check the status?"}}}},"responses":{"201":{"description":"The simulated inbound message and its classification.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestInboundResult"},"example":{"message_id":"rcv_01JZXA2B4C6D8E0F2G4H6J8K0M","thread_id":"thrd_01JZX8K3M9Q4P7VN2YB6RTDC11","event_id":"evt_01JZXA2B4C6D8E0F2G4H6J8K2P","event_type":"message.received","quarantined":false,"test_mode":true,"classification":{"intent":"unclassified","entities":{},"urgency":0.5,"injection_score":0.02,"injection_categories":[],"sender_reputation":0.7,"classifier_model":"injection-scan-only"}}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"send","x-test-key-only":true}},"/v1/agents":{"post":{"tags":["Agents"],"summary":"Create an agent","operationId":"createAgent","description":"**Requires scope:** `manage`. Creates an agent (a send/receive identity) at `name@<workspace>.mails.ai` or a verified custom domain.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAgentRequest"},"example":{"name":"support","daily_send_limit":5000,"classify_inbound":true}}}},"responses":{"201":{"description":"The created agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Agent"},"example":{"id":"agt_01JZ9F8H7KQ2M3N4P5R6S7T8U9","name":"support","email":"support@acme.mails.ai","domain":"acme.mails.ai","workspace_id":"wsk_01JZ8A1B2C3D4E5F6G7H8J9K0M","status":"active","created_at":"2026-06-01T09:12:44.000Z"}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required / feature not enabled on the current plan. The error object carries `upgrade_url` — the dashboard page where the plan can be changed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"},"get":{"tags":["Agents"],"summary":"List agents","operationId":"listAgents","description":"**Requires scope:** `read`.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size (1–100)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a previous page's `next_cursor`."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["live","all","active","paused","archived"],"default":"live"},"description":"Which agents to list. Defaults to `live` — everything except archived — because an archived agent cannot send, so listing tombstones by default answers a different question than the one you asked. Use `all` to include them, or filter to one exact status."}],"responses":{"200":{"description":"A page of agents.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Agent"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","description":"Pass as `cursor` to fetch the next page. Absent on the last page."}},"required":["data","has_more"]}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/agents/{id}":{"get":{"tags":["Agents"],"summary":"Retrieve an agent","operationId":"getAgent","description":"**Requires scope:** `read`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Agent id or name."}],"responses":{"200":{"description":"The agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Agent"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"},"patch":{"tags":["Agents"],"summary":"Update an agent","operationId":"updateAgent","description":"**Requires scope:** `manage`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Agent id or name."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAgentRequest"},"example":{"status":"paused"}}}},"responses":{"200":{"description":"The updated agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Agent"}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required / feature not enabled on the current plan. The error object carries `upgrade_url` — the dashboard page where the plan can be changed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"},"delete":{"tags":["Agents"],"summary":"Archive an agent","operationId":"archiveAgent","description":"**Requires scope:** `manage`. Soft-deletes the agent (sets status to `archived`). The address is retained and cannot be reused.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Agent id or name."}],"responses":{"200":{"description":"The archived agent.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["archived"]},"archived_at":{"type":"string","format":"date-time"}},"required":["id","status","archived_at"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"}},"/v1/api-keys":{"post":{"tags":["API Keys"],"summary":"Create an API key","operationId":"createApiKey","description":"**Requires scope:** `manage`. Creates a new API key. The plaintext `key` is returned ONCE in this response and never again.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"},"example":{"name":"Production server","scopes":["send","read"],"mode":"live"}}}},"responses":{"201":{"description":"The created key, including the one-time plaintext value.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreated"},"example":{"id":"key_01JZXD7R9T1V3X5Z7B9D1F3H5K","key":"mk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8","prefix":"mk_live_a1b","mode":"live","scopes":["send","read"],"agent_id":null,"name":"Production server","expires_at":null,"created_at":"2026-06-24T17:20:00.000Z"}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"},"get":{"tags":["API Keys"],"summary":"List API keys","operationId":"listApiKeys","description":"**Requires scope:** `read`.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size (1–100)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a previous page's `next_cursor`."}],"responses":{"200":{"description":"A page of API keys (plaintext never included).","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","description":"Pass as `cursor` to fetch the next page. Absent on the last page."}},"required":["data","has_more"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/api-keys/{id}":{"delete":{"tags":["API Keys"],"summary":"Revoke an API key","operationId":"revokeApiKey","description":"**Requires scope:** `manage`. Revokes a key immediately. Idempotent — revoking an already-revoked key returns its existing `revoked_at`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"API key id."}],"responses":{"200":{"description":"The revoked key.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"revoked_at":{"type":"string","format":"date-time"}},"required":["id","revoked_at"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"}},"/v1/me":{"get":{"tags":["Account"],"summary":"Identify the current key","operationId":"getMe","description":"Returns the authenticating API key, its workspace, and its bound agent (if any). Any valid key works — no scope required.","responses":{"200":{"description":"The current key, workspace, and agent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"},"example":{"api_key":{"id":"key_01JZXD7R9T1V3X5Z7B9D1F3H5K","prefix":"mk_live_a1b","name":"Production server","mode":"live","scopes":["send","read"],"agent_id":null,"last_used_at":"2026-06-24T17:30:00.000Z","created_at":"2026-06-01T09:12:44.000Z"},"workspace":{"id":"wsk_01JZ8A1B2C3D4E5F6G7H8J9K0M","slug":"acme","display_name":"Acme, Inc.","tier":"pro","tier_status":"active"},"agent":null}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/drafts":{"post":{"tags":["Drafts"],"summary":"Create a draft","operationId":"createDraft","description":"**Requires scope:** `send`. Creates a draft, or a scheduled draft if `send_at` is in the future.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDraftRequest"},"example":{"agent":"support","to":"jordan@example.com","subject":"Following up on order #10473","body_text":"Hi Jordan, just confirming your order arrived safely. Let us know if anything's off."}}}},"responses":{"201":{"description":"The created draft.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Draft"},"example":{"id":"dft_01JZXB5N7P9R1T3V5X7Z9A1C3E","agent_id":"agt_01JZ9F8H7KQ2M3N4P5R6S7T8U9","to":["jordan@example.com"],"subject":"Following up on order #10473","body_text":"Hi Jordan, just confirming your order arrived safely. Let us know if anything's off.","status":"draft","created_at":"2026-06-24T19:00:00.000Z","updated_at":"2026-06-24T19:00:00.000Z"}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"send"},"get":{"tags":["Drafts"],"summary":"List drafts","operationId":"listDrafts","description":"**Requires scope:** `read`.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size (1–100)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a previous page's `next_cursor`."},{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by draft status."}],"responses":{"200":{"description":"A page of drafts.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Draft"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","description":"Pass as `cursor` to fetch the next page. Absent on the last page."}},"required":["data","has_more"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/drafts/{id}":{"get":{"tags":["Drafts"],"summary":"Retrieve a draft","operationId":"getDraft","description":"**Requires scope:** `read`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Draft id (`dft_…`)."}],"responses":{"200":{"description":"The draft.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Draft"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"},"patch":{"tags":["Drafts"],"summary":"Update a draft","operationId":"updateDraft","description":"**Requires scope:** `manage`. Edits a draft or scheduled draft. Setting a future `send_at` schedules it; clearing it returns to `draft`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Draft id."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDraftRequest"},"example":{"subject":"Quick follow-up on your order #10473"}}}},"responses":{"200":{"description":"The updated draft.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Draft"}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"},"delete":{"tags":["Drafts"],"summary":"Delete a draft","operationId":"deleteDraft","description":"**Requires scope:** `manage`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Draft id."}],"responses":{"200":{"description":"The deleted draft id.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"deleted_at":{"type":"string","format":"date-time"}},"required":["id","deleted_at"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"}},"/v1/drafts/{id}/send":{"post":{"tags":["Drafts"],"summary":"Send a draft","operationId":"sendDraft","description":"**Requires scope:** `send`. Sends a draft immediately, or schedules it when the request body supplies a future `send_at`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Draft id."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendDraftRequest"},"example":{"send_at":"2026-06-25T15:30:00.000Z"}}}},"responses":{"200":{"description":"Either the scheduled draft or the sent message.","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests permitted in the current window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the rate-limit window resets."}},"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["scheduled"]},"send_at":{"type":"string","format":"date-time"}},"required":["id","status","send_at"]},{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["sent"]},"message_id":{"type":"string"},"thread_id":{"type":"string"},"sent_at":{"type":"string","format":"date-time"}},"required":["id","status","message_id"]}]}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict — duplicate resource or an in-progress idempotent request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Unprocessable — agent paused/archived, recipient suppressed, or abuse guard.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Upstream (email transport) failure.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"send"}},"/v1/threads":{"get":{"tags":["Threads"],"summary":"List threads","operationId":"listThreads","description":"**Requires scope:** `read`.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size (1–100)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a previous page's `next_cursor`."},{"name":"agent_id","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by agent id or name."},{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by thread status (open|closed|archived)."}],"responses":{"200":{"description":"A page of threads (most-recent activity first).","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Thread"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","description":"Pass as `cursor` to fetch the next page. Absent on the last page."}},"required":["data","has_more"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/threads/{id}":{"get":{"tags":["Threads"],"summary":"Retrieve a thread with messages","operationId":"getThread","description":"**Requires scope:** `read`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Thread id (`thrd_…`)."}],"responses":{"200":{"description":"The thread plus its inbound + outbound messages.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadWithMessages"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"},"patch":{"tags":["Threads"],"summary":"Update a thread","operationId":"updateThread","description":"**Requires scope:** `manage`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Thread id."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateThreadRequest"},"example":{"status":"closed","labels":["resolved","shipping"]}}}},"responses":{"200":{"description":"The updated thread (no messages array).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Thread"}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"}},"/v1/events":{"get":{"tags":["Events"],"summary":"List events","operationId":"listEvents","description":"**Requires scope:** `read`.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size (1–100)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a previous page's `next_cursor`."},{"name":"event_type","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by exact event type."},{"name":"agent_id","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by agent id or name."},{"name":"since","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Only events created at or after this timestamp."}],"responses":{"200":{"description":"A page of typed events.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","description":"Pass as `cursor` to fetch the next page. Absent on the last page."}},"required":["data","has_more"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/events/{id}":{"get":{"tags":["Events"],"summary":"Retrieve an event","operationId":"getEvent","description":"**Requires scope:** `read`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Event id (`evt_…`)."}],"responses":{"200":{"description":"The event, including full classifier detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/events/{id}/redeliver":{"post":{"tags":["Events"],"summary":"Redeliver an event","operationId":"redeliverEvent","description":"**Requires scope:** `manage`. Re-dispatches a stored event to all matching webhook endpoints.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Event id."}],"responses":{"202":{"description":"Redelivery scheduled.","content":{"application/json":{"schema":{"type":"object","properties":{"event_id":{"type":"string"},"webhook_endpoint_ids":{"type":"array","items":{"type":"string"}},"scheduled_at":{"type":"string","format":"date-time"}},"required":["event_id","webhook_endpoint_ids"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"}},"/v1/events/stream":{"get":{"tags":["Events"],"summary":"Stream events (SSE)","operationId":"streamEvents","description":"**Requires scope:** `read`. Server-Sent Events live tail. Each frame is `id: <event_id>`, `event: <type>`, `data: <json>`. Reconnect with `?since=<last event id>` or the `Last-Event-ID` header. The connection self-closes after ~50s; reconnect to continue.","parameters":[{"name":"since","in":"query","required":false,"schema":{"type":"string"},"description":"Resume after this event id (falls back to the Last-Event-ID header)."},{"name":"event_types","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated event-type filter. `*` for all."}],"responses":{"200":{"description":"An SSE stream (`text/event-stream`).","content":{"text/event-stream":{"schema":{"type":"string","description":"SSE frames; the `data:` line is a JSON event payload."}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/logs":{"get":{"tags":["Logs"],"summary":"List audit logs","operationId":"listLogs","description":"**Requires scope:** `read`. Read-only audit trail of state-changing operations.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size (1–100)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a previous page's `next_cursor`."},{"name":"category","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by audit category."},{"name":"action","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by audit action."}],"responses":{"200":{"description":"A page of audit log entries.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"category":{"type":"string"},"action":{"type":"string"},"target_resource_id":{"type":"string"},"metadata":{"type":"object","additionalProperties":true},"ip_address":{"type":"string"},"user_agent":{"type":"string"},"created_at":{"type":"string","format":"date-time"}},"required":["id","category","action","created_at"]}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","description":"Pass as `cursor` to fetch the next page. Absent on the last page."}},"required":["data","has_more"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/webhooks":{"post":{"tags":["Webhooks"],"summary":"Create a webhook endpoint","operationId":"createWebhook","description":"**Requires scope:** `manage`. Registers an HTTPS endpoint to receive events. The `signing_secret` is returned ONCE — use it to verify signatures.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequest"},"example":{"url":"https://api.acme.com/webhooks/mails","event_types":["message.delivered","reply.received"],"description":"Production receiver"}}}},"responses":{"201":{"description":"The created endpoint, including the one-time signing secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreated"},"example":{"id":"whe_01JZXC6Q8S0U2W4Y6A8C0E2G4J","url":"https://api.acme.com/webhooks/mails","signing_secret":"whsec_8f3a1c5e7b9d2f4a6c8e0b2d4f6a8c0e","event_types":["message.delivered","reply.received"],"description":"Production receiver","active":true,"created_at":"2026-06-24T17:40:00.000Z"}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"},"get":{"tags":["Webhooks"],"summary":"List webhook endpoints","operationId":"listWebhooks","description":"**Requires scope:** `read`.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size (1–100)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a previous page's `next_cursor`."}],"responses":{"200":{"description":"A page of webhook endpoints.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","description":"Pass as `cursor` to fetch the next page. Absent on the last page."}},"required":["data","has_more"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/webhooks/{id}":{"patch":{"tags":["Webhooks"],"summary":"Update a webhook endpoint","operationId":"updateWebhook","description":"**Requires scope:** `manage`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Webhook endpoint id (`whe_…`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequest"},"example":{"active":false}}}},"responses":{"200":{"description":"The updated endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook endpoint","operationId":"deleteWebhook","description":"**Requires scope:** `manage`. Deletes the endpoint and its delivery history.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Webhook endpoint id."}],"responses":{"200":{"description":"The deleted endpoint id.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"deleted_at":{"type":"string","format":"date-time"}},"required":["id","deleted_at"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"}},"/v1/webhooks/{id}/deliveries":{"get":{"tags":["Webhooks"],"summary":"List delivery attempts","operationId":"listWebhookDeliveries","description":"**Requires scope:** `read`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Webhook endpoint id."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size (1–100)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a previous page's `next_cursor`."}],"responses":{"200":{"description":"A page of delivery attempts for this endpoint.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","description":"Pass as `cursor` to fetch the next page. Absent on the last page."}},"required":["data","has_more"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/webhooks/{id}/test":{"post":{"tags":["Webhooks"],"summary":"Send a test event","operationId":"testWebhook","description":"**Requires scope:** `manage`. Fires a synthetic `webhook.test` event at the endpoint and reports the delivery result.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Webhook endpoint id."}],"responses":{"200":{"description":"The test delivery result.","content":{"application/json":{"schema":{"type":"object","properties":{"webhook_endpoint_id":{"type":"string"},"event_id":{"type":"string"},"delivery_id":{"type":"string"},"ok":{"type":"boolean"},"http_status":{"type":["integer","null"]},"response_excerpt":{"type":"string"}},"required":["webhook_endpoint_id","event_id","delivery_id","ok"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"}},"/v1/webhook-deliveries/{id}/replay":{"post":{"tags":["Webhooks"],"summary":"Replay a delivery","operationId":"replayWebhookDelivery","description":"**Requires scope:** `manage`. Re-sends the event behind a previous delivery attempt to that delivery's endpoint only. Other endpoints subscribed to the event are not sent it again; to re-send an event to every subscribed endpoint, use `POST /v1/events/{id}/redeliver`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Webhook delivery id (`whd_…`)."}],"responses":{"202":{"description":"Replay scheduled.","content":{"application/json":{"schema":{"type":"object","properties":{"delivery_id":{"type":"string"},"event_id":{"type":"string"},"scheduled":{"type":"array","items":{"type":"string"},"description":"The endpoint the replay went to: one id, or empty when that endpoint is paused or no longer subscribed to the event type."},"scheduled_at":{"type":["string","null"]}},"required":["delivery_id","event_id","scheduled"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"}},"/v1/suppression":{"get":{"tags":["Suppression"],"summary":"List allowlist or look up an address","operationId":"listSuppression","description":"**Requires scope:** `read`. With `?address=`, returns the suppression status for that address. With `?view=suppressed`, lists which of your own recent recipients are suppressed for you, and why (addresses are stored hashed, so the list itself cannot be browsed). With neither, returns the workspace allowlist (paginated).","parameters":[{"name":"address","in":"query","required":false,"schema":{"type":"string","format":"email"},"description":"Look up suppression status for this address instead of listing the allowlist."},{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["suppressed"]},"description":"`suppressed`: list which of your own recent recipients are suppressed for you, and why."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Page size (1–100)."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a previous page's `next_cursor`."}],"responses":{"200":{"description":"A suppression lookup (when `address` is set), your suppressed recipients (when `view=suppressed`), or a page of allowlist entries.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/SuppressionLookup"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string","format":"email"},"type":{"type":"string","enum":["hard_bounce","complaint","unsubscribe"]},"scope":{"type":"string","description":"`global`, or `workspace:<your id>` for an unsubscribe from your mail."},"detail":{"type":"string"},"suppressed_at":{"type":"string","format":"date-time"}},"required":["address","type","scope","suppressed_at"]}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","description":"Pass as `cursor` to fetch the next page. Absent on the last page."}},"required":["data","has_more"]},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SuppressionEntry"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","description":"Pass as `cursor` to fetch the next page. Absent on the last page."}},"required":["data","has_more"]}]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/suppression/allow":{"post":{"tags":["Suppression"],"summary":"Add an allowlist entry","operationId":"allowSuppression","description":"**Requires scope:** `manage`. Attests that a recipient consents, overriding non-hard-bounce suppression for that address.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AllowSuppressionRequest"},"example":{"address":"jordan@example.com","attestation":"Customer reconfirmed opt-in via account settings on 2026-06-20 (support ticket #4821)."}}}},"responses":{"201":{"description":"The created allowlist entry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuppressionEntry"}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"}},"/v1/suppression/allow/{id}":{"delete":{"tags":["Suppression"],"summary":"Revoke an allowlist entry","operationId":"revokeSuppressionAllow","description":"**Requires scope:** `manage`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Allowlist entry id (`sup_…`)."}],"responses":{"200":{"description":"The revoked entry.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"revoked_at":{"type":"string","format":"date-time"}},"required":["id","revoked_at"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"}},"/v1/domains":{"post":{"tags":["Domains"],"summary":"Add a custom send domain","operationId":"createDomain","description":"**Requires scope:** `manage`. Registers a bring-your-own sending domain (paid plans). Returns the DNS records to create at your registrar — records-only verification, no nameserver changes. Agents whose address is on a VERIFIED custom domain send under their own identity instead of the shared workspace subdomain.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainRequest"},"example":{"domain":"mail.acme.com"}}}},"responses":{"201":{"description":"The registered domain with the DNS records to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"},"example":{"id":"dom_01JZXE8S0U2W4Y6A8C0E2G4J6L","domain":"mail.acme.com","status":"pending","provider":"ownmetal","dns_records":[{"type":"TXT","host":"mail.acme.com","value":"v=spf1 ip4:15.204.67.226 ~all","purpose":"spf","required":true,"verified":false},{"type":"TXT","host":"dkim._domainkey.mail.acme.com","value":"v=DKIM1; k=rsa; p=MIIBIjANBgkq…","purpose":"dkim","required":true,"verified":false},{"type":"TXT","host":"_dmarc.mail.acme.com","value":"v=DMARC1; p=quarantine; rua=mailto:dmarc@mail.acme.com","purpose":"dmarc","required":false,"verified":false}],"fail_reason":null,"last_check_at":null,"verified_at":null,"created_at":"2026-07-24T10:30:00.000Z"}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required / feature not enabled on the current plan. The error object carries `upgrade_url` — the dashboard page where the plan can be changed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict — duplicate resource or an in-progress idempotent request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"},"get":{"tags":["Domains"],"summary":"List custom domains","operationId":"listDomains","description":"**Requires scope:** `read`.","responses":{"200":{"description":"This workspace's custom domains.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Domain"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","description":"Pass as `cursor` to fetch the next page. Absent on the last page."}},"required":["data","has_more"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/domains/{id}":{"get":{"tags":["Domains"],"summary":"Get a domain","operationId":"getDomain","description":"**Requires scope:** `read`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Domain id (`dom_…`)."}],"responses":{"200":{"description":"Domain status + the DNS records to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"},"example":{"id":"dom_01JZXE8S0U2W4Y6A8C0E2G4J6L","domain":"mail.acme.com","status":"pending","provider":"ownmetal","dns_records":[{"type":"TXT","host":"mail.acme.com","value":"v=spf1 ip4:15.204.67.226 ~all","purpose":"spf","required":true,"verified":false},{"type":"TXT","host":"dkim._domainkey.mail.acme.com","value":"v=DKIM1; k=rsa; p=MIIBIjANBgkq…","purpose":"dkim","required":true,"verified":false},{"type":"TXT","host":"_dmarc.mail.acme.com","value":"v=DMARC1; p=quarantine; rua=mailto:dmarc@mail.acme.com","purpose":"dmarc","required":false,"verified":false}],"fail_reason":null,"last_check_at":null,"verified_at":null,"created_at":"2026-07-24T10:30:00.000Z"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"},"delete":{"tags":["Domains"],"summary":"Remove a domain","operationId":"deleteDomain","description":"**Requires scope:** `manage`. Agents on this domain fall back to the shared workspace subdomain.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Domain id (`dom_…`)."}],"responses":{"200":{"description":"Deletion confirmation.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean"}},"required":["id","deleted"]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"}},"/v1/domains/{id}/verify":{"post":{"tags":["Domains"],"summary":"Verify a domain now","operationId":"verifyDomain","description":"**Requires scope:** `manage`. Re-checks every DNS record and updates per-record + overall status. Idempotent — poll after creating the records (propagation usually takes minutes).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Domain id (`dom_…`)."}],"responses":{"200":{"description":"The domain with refreshed per-record verification state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"}},"/v1/reputation":{"get":{"tags":["Reputation"],"summary":"Get reputation","operationId":"getReputation","description":"**Requires scope:** `read`. Workspace-wide reputation when called without `agent_id`, or per-agent stats when an agent id/name is supplied.","parameters":[{"name":"agent_id","in":"query","required":false,"schema":{"type":"string"},"description":"Agent id or name. Omit for the workspace aggregate."}],"responses":{"200":{"description":"Workspace aggregate or per-agent reputation.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ReputationWorkspace"},{"$ref":"#/components/schemas/ReputationAgent"}]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/billing/usage":{"get":{"tags":["Billing"],"summary":"Get current usage","operationId":"getBillingUsage","description":"**Requires scope:** `read`. Returns metered usage for the current billing period plus the workspace's tier caps.","responses":{"200":{"description":"Current-period usage and caps.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingUsage"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"read"}},"/v1/billing/portal":{"post":{"tags":["Billing"],"summary":"Open billing portal or checkout","operationId":"openBillingPortal","description":"**Requires scope:** `manage`. Returns a Stripe Billing Portal URL when already subscribed, otherwise a Checkout URL to subscribe.","requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingPortalRequest"},"example":{"return_url":"https://app.acme.com/settings/billing"}}}},"responses":{"201":{"description":"A redirect URL.","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"mock":{"type":"boolean"}},"required":["url"]}}}},"400":{"description":"Invalid request — malformed JSON or a field failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-required-scope":"manage"}},"/v1/unsubscribe":{"get":{"tags":["Public"],"summary":"Unsubscribe landing page","operationId":"unsubscribe","description":"Public List-Unsubscribe link target (human click). Authorized by the signed `t` token, not an API key. Always returns an HTML confirmation page (200) regardless of token validity.","parameters":[{"name":"t","in":"query","required":false,"schema":{"type":"string"},"description":"Signed unsubscribe token embedded in the email."}],"responses":{"200":{"description":"An HTML confirmation page.","content":{"text/html":{"schema":{"type":"string"}}}}},"security":[]},"post":{"tags":["Public"],"summary":"One-click unsubscribe (RFC 8058)","operationId":"unsubscribeOneClick","description":"RFC 8058 one-click unsubscribe POST from a mail client. Authorized by the signed `t` query token. Returns an empty 200.","parameters":[{"name":"t","in":"query","required":false,"schema":{"type":"string"},"description":"Signed unsubscribe token."}],"responses":{"200":{"description":"Processed (empty body)."}},"security":[]}},"/api/health":{"get":{"tags":["Public"],"summary":"Health check","operationId":"getHealth","description":"Liveness probe. Without authentication it returns `status` (`healthy` when the database answers and accepts writes, else `degraded`) and `timestamp`. The dependency detail (database, sender, classifier) is returned only to internal callers.","responses":{"200":{"description":"Service health.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}}},"security":[]}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"mk_live_<32 hex> or mk_test_<32 hex>","description":"A Mails.ai API key. Scopes (`send`/`read`/`manage`) are noted per operation via `x-required-scope`."}},"schemas":{"SendMessageRequest":{"type":"object","properties":{"agent":{"type":"string","minLength":1,"maxLength":64,"description":"Which agent sends this — its name or `agt_` id. Optional: omit it and we use the workspace's single agent, or provision one named from `from`. Required only when the workspace has several agents and no `from` names one of them."},"from":{"type":"string","maxLength":320,"description":"The sender you want, as a handle or address — `billing`, `billing@acme.com` and `Acme <billing@acme.com>` all mean the agent called `billing`. It SELECTS that agent: resolved if it exists, created if it doesn't, and refused with 402 `plan_limit_exceeded` if your plan has no room for it. An address at a domain you have verified is matched whole: `billing@yourdomain.com` means the agent at exactly that address, created on your domain if it doesn't exist yet. It is never resolved to a different agent, and it cannot spoof a sender — the wire From is always derived from the agent's own identity. The address that actually sent comes back as `from` on the response."},"to":{"anyOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}]},"cc":{"type":"array","items":{"type":"string","format":"email"},"maxItems":50},"bcc":{"type":"array","items":{"type":"string","format":"email"},"maxItems":50},"subject":{"type":"string","minLength":1,"maxLength":998},"body_text":{"type":"string","maxLength":1000000},"body_html":{"type":"string","maxLength":1000000},"html":{"type":"string","maxLength":1000000},"text":{"type":"string","maxLength":1000000},"reply_to":{"type":"string","format":"email"},"in_reply_to_message_id":{"type":"string"},"references":{"type":"array","items":{"type":"string"}},"attachments":{"type":"array","items":{"type":"object","properties":{"filename":{"type":"string","minLength":1,"maxLength":255},"content_base64":{"type":"string"},"content_type":{"type":"string","minLength":1,"maxLength":127}},"required":["filename","content_base64","content_type"],"additionalProperties":false},"maxItems":10,"description":"Up to 10 files, 25 MB in total. Not accepted with a future `scheduled_at`: a scheduled send cannot carry attachments yet, so that combination is refused with 400 `invalid_field`."},"metadata":{"type":"object","additionalProperties":{"type":"string","maxLength":500},"propertyNames":{"maxLength":64}},"scheduled_at":{"type":"string","format":"date-time","description":"Send at this time (ISO 8601) instead of now. A time in the past sends at once. A future time cannot be combined with `attachments`."},"tags":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":256,"pattern":"^[a-zA-Z0-9_-]+$"},"value":{"type":"string","maxLength":256}},"required":["name","value"],"additionalProperties":false},"maxItems":10},"list_unsubscribe":{"type":"boolean","description":"Opt in to RFC 8058 one-click unsubscribe: the message carries `List-Unsubscribe` and `List-Unsubscribe-Post: List-Unsubscribe=One-Click` headers, so the recipient's mail app shows an Unsubscribe button. One click suppresses the address for your whole workspace: every later send to it from any of your agents is refused with `recipient_suppressed` until you allowlist it (`POST /v1/suppression/allow`). Turn it on for newsletters, digests and other recurring mail. Leave it off (the default) for password resets, sign-in links, receipts and anything else the recipient must keep receiving. Needs exactly one `to` recipient and no `cc` or `bcc`."}},"required":["to","subject"],"additionalProperties":false,"description":"Provide at least one of `body_text` or `body_html`. Total decoded attachment size must be ≤ 25 MB."},"BatchSendRequest":{"type":"array","items":{"type":"object","properties":{"agent":{"type":"string","minLength":1,"maxLength":64},"to":{"anyOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}]},"cc":{"type":"array","items":{"type":"string","format":"email"},"maxItems":50},"bcc":{"type":"array","items":{"type":"string","format":"email"},"maxItems":50},"subject":{"type":"string","minLength":1,"maxLength":998},"body_text":{"type":"string","maxLength":1000000},"body_html":{"type":"string","maxLength":1000000},"html":{"type":"string","maxLength":1000000},"text":{"type":"string","maxLength":1000000},"reply_to":{"type":"string","format":"email"},"in_reply_to_message_id":{"type":"string"},"metadata":{"type":"object","additionalProperties":{"type":"string","maxLength":500},"propertyNames":{"maxLength":64}},"scheduled_at":{"type":"string","format":"date-time"},"tags":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":256},"value":{"type":"string","maxLength":256}},"required":["name","value"],"additionalProperties":false},"maxItems":10},"list_unsubscribe":{"type":"boolean","description":"Opt in to RFC 8058 one-click unsubscribe: the message carries `List-Unsubscribe` and `List-Unsubscribe-Post: List-Unsubscribe=One-Click` headers, so the recipient's mail app shows an Unsubscribe button. One click suppresses the address for your whole workspace: every later send to it from any of your agents is refused with `recipient_suppressed` until you allowlist it (`POST /v1/suppression/allow`). Turn it on for newsletters, digests and other recurring mail. Leave it off (the default) for password resets, sign-in links, receipts and anything else the recipient must keep receiving. Needs exactly one `to` recipient and no `cc` or `bcc`."}},"required":["agent","to","subject"],"additionalProperties":false},"minItems":1,"maxItems":100},"ReplyMessageRequest":{"type":"object","properties":{"body_text":{"type":"string","maxLength":1000000},"body_html":{"type":"string","maxLength":1000000},"html":{"type":"string","maxLength":1000000},"text":{"type":"string","maxLength":1000000},"reply_all":{"type":"boolean","default":false},"cc":{"type":"array","items":{"type":"string","format":"email"},"maxItems":50},"bcc":{"type":"array","items":{"type":"string","format":"email"},"maxItems":50},"tags":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":256},"value":{"type":"string","maxLength":256}},"required":["name","value"],"additionalProperties":false},"maxItems":10},"scheduled_at":{"type":"string","format":"date-time"},"list_unsubscribe":{"type":"boolean","description":"Opt in to RFC 8058 one-click unsubscribe: the message carries `List-Unsubscribe` and `List-Unsubscribe-Post: List-Unsubscribe=One-Click` headers, so the recipient's mail app shows an Unsubscribe button. One click suppresses the address for your whole workspace: every later send to it from any of your agents is refused with `recipient_suppressed` until you allowlist it (`POST /v1/suppression/allow`). Turn it on for newsletters, digests and other recurring mail. Leave it off (the default) for password resets, sign-in links, receipts and anything else the recipient must keep receiving. Needs exactly one `to` recipient and no `cc` or `bcc`."}},"additionalProperties":false},"ForwardMessageRequest":{"type":"object","properties":{"to":{"anyOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}]},"cc":{"type":"array","items":{"type":"string","format":"email"},"maxItems":50},"bcc":{"type":"array","items":{"type":"string","format":"email"},"maxItems":50},"subject":{"type":"string","minLength":1,"maxLength":998},"body_text":{"type":"string","maxLength":1000000},"body_html":{"type":"string","maxLength":1000000},"html":{"type":"string","maxLength":1000000},"text":{"type":"string","maxLength":1000000},"list_unsubscribe":{"type":"boolean","description":"Opt in to RFC 8058 one-click unsubscribe: the message carries `List-Unsubscribe` and `List-Unsubscribe-Post: List-Unsubscribe=One-Click` headers, so the recipient's mail app shows an Unsubscribe button. One click suppresses the address for your whole workspace: every later send to it from any of your agents is refused with `recipient_suppressed` until you allowlist it (`POST /v1/suppression/allow`). Turn it on for newsletters, digests and other recurring mail. Leave it off (the default) for password resets, sign-in links, receipts and anything else the recipient must keep receiving. Needs exactly one `to` recipient and no `cc` or `bcc`."}},"required":["to"],"additionalProperties":false},"RescheduleMessageRequest":{"type":"object","properties":{"scheduled_at":{"type":"string","format":"date-time"}},"additionalProperties":false},"CreateDraftRequest":{"type":"object","properties":{"agent":{"type":"string","minLength":1,"maxLength":64},"to":{"anyOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":50}]},"cc":{"type":"array","items":{"type":"string","format":"email"},"maxItems":50},"bcc":{"type":"array","items":{"type":"string","format":"email"},"maxItems":50},"subject":{"type":"string","minLength":1,"maxLength":998},"body_text":{"type":"string","maxLength":1000000},"body_html":{"type":"string","maxLength":1000000},"reply_to":{"type":"string","format":"email"},"in_reply_to_message_id":{"type":"string"},"send_at":{"type":"string","format":"date-time"},"tags":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":256},"value":{"type":"string","maxLength":256}},"required":["name","value"],"additionalProperties":false},"maxItems":10},"list_unsubscribe":{"type":"boolean","description":"Opt in to RFC 8058 one-click unsubscribe: the message carries `List-Unsubscribe` and `List-Unsubscribe-Post: List-Unsubscribe=One-Click` headers, so the recipient's mail app shows an Unsubscribe button. One click suppresses the address for your whole workspace: every later send to it from any of your agents is refused with `recipient_suppressed` until you allowlist it (`POST /v1/suppression/allow`). Turn it on for newsletters, digests and other recurring mail. Leave it off (the default) for password resets, sign-in links, receipts and anything else the recipient must keep receiving. Needs exactly one `to` recipient and no `cc` or `bcc`."}},"required":["to"],"additionalProperties":false},"UpdateDraftRequest":{"type":"object","properties":{"to":{"anyOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"maxItems":50}]},"cc":{"type":"array","items":{"type":"string","format":"email"},"maxItems":50},"bcc":{"type":"array","items":{"type":"string","format":"email"},"maxItems":50},"subject":{"type":"string","minLength":1,"maxLength":998},"body_text":{"type":"string","maxLength":1000000},"body_html":{"type":"string","maxLength":1000000},"send_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"list_unsubscribe":{"type":"boolean","description":"Opt in to RFC 8058 one-click unsubscribe: the message carries `List-Unsubscribe` and `List-Unsubscribe-Post: List-Unsubscribe=One-Click` headers, so the recipient's mail app shows an Unsubscribe button. One click suppresses the address for your whole workspace: every later send to it from any of your agents is refused with `recipient_suppressed` until you allowlist it (`POST /v1/suppression/allow`). Turn it on for newsletters, digests and other recurring mail. Leave it off (the default) for password resets, sign-in links, receipts and anything else the recipient must keep receiving. Needs exactly one `to` recipient and no `cc` or `bcc`."}},"additionalProperties":false},"SendDraftRequest":{"type":"object","properties":{"send_at":{"type":"string","format":"date-time"}},"additionalProperties":false},"UpdateThreadRequest":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string","maxLength":64},"maxItems":50},"status":{"type":"string","enum":["open","closed","archived"]}},"additionalProperties":false},"CreateAgentRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":32,"pattern":"^[a-z0-9._-]+$"},"domain":{"type":"string","maxLength":253},"allowlist_domains":{"type":"array","items":{"type":"string","maxLength":253},"maxItems":100,"description":"When set, this agent sends only to these domains and their subdomains (`acme.com` covers `mail.acme.com`). A recipient in `to`, `cc` or `bcc` outside the list refuses the whole send with 422 `recipient_not_allowed`, in test mode too. A leading `@` is ignored."},"blocklist_domains":{"type":"array","items":{"type":"string","maxLength":253},"maxItems":100,"description":"This agent never sends to these domains or their subdomains. A recipient in `to`, `cc` or `bcc` on the list refuses the whole send with 422 `recipient_not_allowed`, in test mode too."},"daily_send_limit":{"type":"integer","exclusiveMinimum":0,"maximum":1000000,"description":"This agent's own cap on live sends in any 24 hours, on top of your plan's cap. Past it a send is refused with 429 `daily_limit_exceeded` and a `Retry-After` header. Test-mode sends are neither counted nor refused. Leave it out to use only your plan's cap."},"hourly_send_limit":{"type":"integer","exclusiveMinimum":0,"maximum":100000,"description":"This agent's own cap on live sends in any hour, on top of your plan's cap. Past it a send is refused with 429 `hourly_limit_exceeded` and a `Retry-After` header. Test-mode sends are neither counted nor refused. Leave it out to use only your plan's cap."},"classify_inbound":{"type":"boolean"}},"required":["name"],"additionalProperties":false},"UpdateAgentRequest":{"type":"object","properties":{"status":{"type":"string","enum":["active","paused"]},"allowlist_domains":{"type":"array","items":{"type":"string","maxLength":253},"maxItems":100,"description":"When set, this agent sends only to these domains and their subdomains (`acme.com` covers `mail.acme.com`). A recipient in `to`, `cc` or `bcc` outside the list refuses the whole send with 422 `recipient_not_allowed`, in test mode too. A leading `@` is ignored."},"blocklist_domains":{"type":"array","items":{"type":"string","maxLength":253},"maxItems":100,"description":"This agent never sends to these domains or their subdomains. A recipient in `to`, `cc` or `bcc` on the list refuses the whole send with 422 `recipient_not_allowed`, in test mode too."},"daily_send_limit":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":1000000},{"type":"null"}],"description":"This agent's own cap on live sends in any 24 hours, on top of your plan's cap. Past it a send is refused with 429 `daily_limit_exceeded` and a `Retry-After` header. Test-mode sends are neither counted nor refused. `null` removes it, leaving only your plan's cap."},"hourly_send_limit":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":100000},{"type":"null"}],"description":"This agent's own cap on live sends in any hour, on top of your plan's cap. Past it a send is refused with 429 `hourly_limit_exceeded` and a `Retry-After` header. Test-mode sends are neither counted nor refused. `null` removes it, leaving only your plan's cap."},"classify_inbound":{"type":"boolean"}},"additionalProperties":false},"CreateApiKeyRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"agent_id":{"type":"string","maxLength":48},"scopes":{"type":"array","items":{"type":"string","enum":["send","read","manage"]},"minItems":1,"default":["send","read"]},"mode":{"type":"string","enum":["live","test"],"default":"live"},"expires_at":{"type":"string","format":"date-time"}},"additionalProperties":false},"CreateWebhookRequest":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"event_types":{"type":"array","items":{"type":"string","maxLength":64},"maxItems":50,"default":["*"]},"description":{"type":"string","maxLength":255}},"required":["url"],"additionalProperties":false},"UpdateWebhookRequest":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"event_types":{"type":"array","items":{"type":"string","maxLength":64},"maxItems":50},"description":{"type":"string","maxLength":255},"active":{"type":"boolean"}},"additionalProperties":false},"AllowSuppressionRequest":{"type":"object","properties":{"address":{"type":"string","format":"email"},"attestation":{"type":"string","minLength":20,"maxLength":2000}},"required":["address","attestation"],"additionalProperties":false},"BillingPortalRequest":{"type":"object","properties":{"return_url":{"type":"string","format":"uri"},"price_lookup_key":{"type":"string","minLength":1,"maxLength":64}},"additionalProperties":false},"TestInboundRequest":{"type":"object","properties":{"agent":{"type":"string","minLength":1,"maxLength":64},"from":{"type":"string","format":"email"},"from_name":{"type":"string","maxLength":256},"subject":{"type":"string","maxLength":2000},"body_text":{"type":"string","minLength":1,"maxLength":1000000},"in_reply_to_message_id":{"type":"string","maxLength":512},"spf":{"type":"string","enum":["pass","fail","unknown"]},"dkim":{"type":"string","enum":["pass","fail","unknown"]}},"required":["agent","from","body_text"],"additionalProperties":false},"CreateDomainRequest":{"type":"object","properties":{"domain":{"type":"string","minLength":4,"maxLength":253}},"required":["domain"],"additionalProperties":false},"FieldError":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_field","missing_field","missing_param","invalid_param_value","method_not_allowed","invalid_idempotency_key","duplicate_resource","slug_invalid","slug_reserved","slug_taken","agent_name_conflict","body_too_large","missing_authorization","missing_api_key","invalid_api_key","expired_api_key","revoked_api_key","email_not_verified","insufficient_scope","workspace_mismatch","agent_not_owned","rate_limit_exceeded","daily_limit_exceeded","hourly_limit_exceeded","monthly_limit_exceeded","agent_not_found","agent_paused","agent_archived","resource_not_found","recipient_suppressed","recipient_not_allowed","domain_not_verified","payment_required","payment_method_failed","subscription_canceled","billing_state_inconsistent","free_tier_exceeded","plan_limit_exceeded","cold_email_prohibited","agent_suspended","new_workspace_fanout_exceeded","resource_cap_exceeded","workspace_cap_exceeded","feature_not_enabled","test_mode_required","workspace_not_approved","spam_pattern_detected","classifier_rejected","high_injection_score","complaint_threshold_exceeded","bounce_threshold_exceeded","internal_error","internal_server_error","upstream_error","upstream_unavailable","service_unavailable"],"description":"Stable machine-readable code for this field."},"message":{"type":"string","description":"Human-readable explanation for this field."},"param":{"type":["string","null"],"description":"The offending request field (dot-path), or null."}},"required":["code","message","param"]},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["invalid_request_error","authentication_error","permission_error","rate_limit_error","resource_error","payment_error","abuse_error","api_error"],"description":"High-level error category."},"code":{"type":"string","enum":["invalid_field","missing_field","missing_param","invalid_param_value","method_not_allowed","invalid_idempotency_key","duplicate_resource","slug_invalid","slug_reserved","slug_taken","agent_name_conflict","body_too_large","missing_authorization","missing_api_key","invalid_api_key","expired_api_key","revoked_api_key","email_not_verified","insufficient_scope","workspace_mismatch","agent_not_owned","rate_limit_exceeded","daily_limit_exceeded","hourly_limit_exceeded","monthly_limit_exceeded","agent_not_found","agent_paused","agent_archived","resource_not_found","recipient_suppressed","recipient_not_allowed","domain_not_verified","payment_required","payment_method_failed","subscription_canceled","billing_state_inconsistent","free_tier_exceeded","plan_limit_exceeded","cold_email_prohibited","agent_suspended","new_workspace_fanout_exceeded","resource_cap_exceeded","workspace_cap_exceeded","feature_not_enabled","test_mode_required","workspace_not_approved","spam_pattern_detected","classifier_rejected","high_injection_score","complaint_threshold_exceeded","bounce_threshold_exceeded","internal_error","internal_server_error","upstream_error","upstream_unavailable","service_unavailable"],"description":"Stable machine-readable error code."},"message":{"type":"string","description":"Human-readable explanation."},"param":{"type":["string","null"],"description":"The offending request field, when applicable."},"request_id":{"type":"string","description":"Echo of the X-Request-Id header for support correlation."},"errors":{"type":"array","items":{"$ref":"#/components/schemas/FieldError"},"description":"On a validation failure, EVERY offending field (not just the first). The top-level code/message/param mirror errors[0] for backward compatibility."}},"required":["type","code","message"]}},"required":["error"]},"Tag":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"}},"required":["name","value"]},"AttachmentMeta":{"type":"object","properties":{"filename":{"type":"string"},"content_type":{"type":"string"},"size_bytes":{"type":"integer"}},"required":["filename","content_type","size_bytes"]},"SentMessage":{"type":"object","properties":{"id":{"type":"string"},"agent_id":{"type":"string"},"from":{"type":"string","format":"email","description":"The agent address this was sent as — the resolved `from`. Read it back when you pass `from` as a naming hint instead of an explicit `agent`: it is the receipt for which identity the API picked. On a verified custom domain the message goes out from this exact address. On the shared mails.ai domain it goes out from `<name>.<workspace>@send.mails.ai`, and replies come back through `<name>.<workspace>@in.mails.ai`."},"thread_id":{"type":"string"},"in_reply_to_message_id":{"type":"string"},"to":{"type":"array","items":{"type":"string","format":"email"}},"cc":{"type":"array","items":{"type":"string","format":"email"}},"bcc":{"type":"array","items":{"type":"string","format":"email"}},"subject":{"type":"string"},"body_text":{"type":"string"},"body_html":{"type":"string"},"classifier_score":{"type":"number"},"status":{"type":"string","enum":["scheduled","sending","sent","delivered","bounced","complained","rejected","canceled"],"description":"`sent` once handed off; `delivered`, `bounced` or `complained` when the receiving side reports it (with several recipients the latest report wins). `sending` only while a scheduled send is going out; `rejected` when the send failed, or a scheduled send was refused when it came due; `canceled` when a scheduled send was stopped."},"cost_usd":{"type":"number","description":"USD cost of the send. 0 for scheduled or test-mode sends."},"ses_message_id":{"type":"string"},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/AttachmentMeta"}},"references":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","properties":{},"additionalProperties":{"type":"string"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/Tag"}},"sent_at":{"type":"string","format":"date-time"},"delivered_at":{"type":"string","format":"date-time"},"scheduled_at":{"type":"string","format":"date-time"},"canceled_at":{"type":"string","format":"date-time"},"bounced_at":{"type":"string","format":"date-time"},"complained_at":{"type":"string","format":"date-time"},"forwarded_from":{"type":"string","description":"Source message id (forward responses only)."},"test_mode":{"type":"boolean"},"classifier_warning":{"type":"object","properties":{"code":{"type":"string","enum":["cold_email_prohibited"]},"message":{"type":"string"},"score":{"type":"number"},"reason":{"type":"string"}},"required":["code","message","score","reason"],"description":"Present only on a test-mode send that a live key would refuse: the cold-email firewall's verdict, reported instead of thrown. Nothing was transmitted."},"created_at":{"type":"string","format":"date-time"}},"required":["id","status"]},"ReceivedMessage":{"type":"object","properties":{"id":{"type":"string"},"agent_id":{"type":"string"},"thread_id":{"type":"string"},"from":{"type":"object","properties":{"address":{"type":"string","format":"email"},"name":{"type":["string","null"]}},"required":["address"]},"to":{"type":"string","format":"email","description":"The receiving agent address (single string, not an array)."},"subject":{"type":"string"},"is_thread_reply":{"type":"boolean"},"in_reply_to_message_id":{"type":"string"},"thread_root_message_id":{"type":"string"},"body_text":{"type":"string","description":"Full body — single-message GET only."},"body_html":{"type":"string","description":"Full body — single-message GET only."},"body_text_excerpt":{"type":"string"},"extracted_text":{"type":"string","description":"Reply text with quoted history stripped."},"extracted_html":{"type":"string"},"spf_pass":{"type":"boolean"},"dkim_pass":{"type":"boolean"},"parse_status":{"type":"string","enum":["parsed","quarantined","pending","failed"]},"received_at":{"type":"string","format":"date-time"},"raw_url":{"type":"string","description":"Path to the synthetic .eml — single-message GET only."},"created_at":{"type":"string","format":"date-time"}},"required":["id","agent_id","from","to","parse_status","received_at"]},"Agent":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string","format":"email"},"domain":{"type":"string"},"workspace_id":{"type":"string"},"status":{"type":"string","enum":["active","paused","archived"]},"pause_reason":{"type":"string"},"daily_send_limit":{"type":"integer","description":"This agent's own cap on live sends in any 24 hours, on top of your plan's cap; past it a send gets 429 `daily_limit_exceeded`. Absent when unset."},"hourly_send_limit":{"type":"integer","description":"This agent's own cap on live sends in any hour, on top of your plan's cap; past it a send gets 429 `hourly_limit_exceeded`. Absent when unset."},"allowlist_domains":{"type":"array","items":{"type":"string"},"description":"When present, this agent sends only to these domains and their subdomains; any other recipient in `to`, `cc` or `bcc` gets 422 `recipient_not_allowed`."},"blocklist_domains":{"type":"array","items":{"type":"string"},"description":"Domains (and their subdomains) this agent never sends to; a recipient on the list gets 422 `recipient_not_allowed`."},"classify_inbound":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","name","email","domain","workspace_id","status"]},"ApiKey":{"type":"object","properties":{"id":{"type":"string"},"prefix":{"type":"string","description":"First 12 chars (e.g. `mk_live_a1b`) — the only part ever shown after creation."},"name":{"type":["string","null"]},"mode":{"type":"string","enum":["live","test"]},"scopes":{"type":"array","items":{"type":"string","enum":["send","read","manage","*"]}},"agent_id":{"type":["string","null"]},"last_used_at":{"type":["string","null"]},"expires_at":{"type":["string","null"]},"revoked_at":{"type":["string","null"]},"created_at":{"type":"string"}},"required":["id","prefix","mode","scopes","created_at"]},"ApiKeyCreated":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string","description":"The full plaintext API key. SHOWN ONCE — store it now; it cannot be retrieved again."},"prefix":{"type":"string"},"mode":{"type":"string","enum":["live","test"]},"scopes":{"type":"array","items":{"type":"string","enum":["send","read","manage","*"]}},"agent_id":{"type":["string","null"]},"name":{"type":["string","null"]},"expires_at":{"type":["string","null"]},"created_at":{"type":"string"}},"required":["id","key","prefix","mode","scopes","created_at"]},"Webhook":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"event_types":{"type":"array","items":{"type":"string"}},"description":{"type":["string","null"]},"active":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","url","event_types","active","created_at"]},"WebhookCreated":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"signing_secret":{"type":"string","description":"HMAC secret for verifying webhook signatures. SHOWN ONCE."},"event_types":{"type":"array","items":{"type":"string"}},"description":{"type":["string","null"]},"active":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","url","signing_secret","event_types","active","created_at"]},"WebhookDelivery":{"type":"object","properties":{"id":{"type":"string"},"webhook_endpoint_id":{"type":"string"},"event_id":{"type":"string"},"attempt_number":{"type":"integer"},"status":{"type":"string","enum":["pending","succeeded","failed"]},"http_status":{"type":"integer"},"response_body_excerpt":{"type":"string"},"next_retry_at":{"type":"string","format":"date-time"},"delivered_at":{"type":"string","format":"date-time"},"created_at":{"type":"string"}},"required":["id","webhook_endpoint_id","event_id","attempt_number","status","created_at"]},"Event":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","description":"Event type, e.g. message.sent, reply.received, message.received."},"workspace_id":{"type":"string"},"agent_id":{"type":"string"},"source_message_id":{"type":"string"},"intent":{"type":"string"},"urgency":{"type":"number","description":"Urgency score 0–1 (higher = more time-sensitive)."},"injection_score":{"type":"number"},"sender_reputation":{"type":"number"},"entities":{"type":"object","additionalProperties":true,"description":"Extracted entities as key→value pairs (object) — present when intent classification ran."},"injection_categories":{"type":"array","items":{"type":"string"},"description":"Prompt-injection categories flagged — single-event GET only."},"classifier_model":{"type":"string","description":"Model used by the classifier — single-event GET only."},"test_mode":{"type":"boolean"},"data":{"type":"object","additionalProperties":true,"description":"Full typed-event payload (shape varies by type)."},"created_at":{"type":"string","format":"date-time"}},"required":["id","type","workspace_id","test_mode","created_at"]},"Thread":{"type":"object","properties":{"id":{"type":"string"},"agent_id":{"type":"string"},"subject":{"type":"string"},"root_message_id":{"type":"string"},"last_message_id":{"type":"string"},"last_message_at":{"type":"string","format":"date-time"},"message_count":{"type":"integer"},"participants":{"type":"array","items":{"type":"string","format":"email"}},"labels":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["open","closed","archived"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","agent_id","status","message_count","created_at"]},"ThreadMessageOutbound":{"type":"object","properties":{"id":{"type":"string"},"direction":{"type":"string","enum":["outbound"]},"to":{"type":"array","items":{"type":"string","format":"email"}},"subject":{"type":["string","null"]},"body_text":{"type":"string"},"snippet":{"type":"string"},"status":{"type":"string"},"sent_at":{"type":"string","format":"date-time"},"scheduled_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"}},"required":["id","direction","snippet"]},"ThreadMessageInbound":{"type":"object","properties":{"id":{"type":"string"},"direction":{"type":"string","enum":["inbound"]},"from":{"type":"string","format":"email"},"to":{"type":"string","format":"email"},"subject":{"type":"string"},"extracted_text":{"type":"string"},"body_text_excerpt":{"type":"string"},"snippet":{"type":"string"},"received_at":{"type":"string","format":"date-time"},"is_thread_reply":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}},"required":["id","direction","from","to","snippet"]},"ThreadWithMessages":{"allOf":[{"$ref":"#/components/schemas/Thread"},{"type":"object","properties":{"messages":{"type":"array","items":{"oneOf":[{"$ref":"#/components/schemas/ThreadMessageOutbound"},{"$ref":"#/components/schemas/ThreadMessageInbound"}],"discriminator":{"propertyName":"direction"}}}},"required":["messages"]}]},"Draft":{"type":"object","properties":{"id":{"type":"string"},"agent_id":{"type":"string"},"to":{"type":"array","items":{"type":"string","format":"email"}},"cc":{"type":"array","items":{"type":"string","format":"email"}},"bcc":{"type":"array","items":{"type":"string","format":"email"}},"subject":{"type":"string"},"body_text":{"type":"string"},"body_html":{"type":"string"},"reply_to":{"type":"string","format":"email"},"in_reply_to_message_id":{"type":"string"},"thread_id":{"type":"string"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/Tag"}},"send_at":{"type":"string","format":"date-time"},"list_unsubscribe":{"type":"boolean","description":"Whether the draft is sent with RFC 8058 one-click unsubscribe headers (`list_unsubscribe` on create or update; off by default). One click suppresses the recipient for the whole workspace."},"status":{"type":"string","enum":["draft","scheduled","sending","sent","failed","canceled"]},"sent_message_id":{"type":"string"},"error_message":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","agent_id","status","created_at","updated_at"]},"SuppressionEntry":{"type":"object","properties":{"id":{"type":"string"},"address":{"type":"string","format":"email"},"attestation":{"type":"string"},"revoked_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"}},"required":["id","address","attestation","created_at"]},"SuppressionLookup":{"type":"object","properties":{"suppressed":{"type":"boolean"},"type":{"type":"string","enum":["hard_bounce","complaint","unsubscribe"],"description":"Present only when suppressed."},"scope":{"type":"string","description":"`global` (hard bounces and complaints, for every sender) or `workspace:<your id>` (an unsubscribe from your mail). Present only when suppressed."},"since":{"type":"string","format":"date-time","description":"When suppression began. Present only when suppressed."},"allowed":{"type":"object","properties":{"id":{"type":"string"},"attestation":{"type":"string"},"created_at":{"type":"string"}},"required":["id"],"description":"Present when an allowlist attestation overrides the suppression."}},"required":["suppressed"]},"ReputationWorkspace":{"type":"object","properties":{"workspace_id":{"type":"string"},"reputation":{"type":"number","description":"Aggregate reputation 0–1."},"agents_count":{"type":"integer"},"last_computed_at":{"type":["string","null"]}},"required":["workspace_id","reputation","agents_count"]},"ReputationAgent":{"type":"object","properties":{"agent_id":{"type":"string"},"reputation":{"type":"number"},"send_count_30d":{"type":"integer"},"bounce_count_30d":{"type":"integer"},"complaint_count_30d":{"type":"integer"},"reply_count_30d":{"type":"integer"}},"required":["agent_id","reputation"]},"BillingUsage":{"type":"object","properties":{"workspace_id":{"type":"string"},"tier":{"type":"string"},"tier_status":{"type":"string"},"period_start":{"type":"string","format":"date-time"},"period_end":{"type":"string","format":"date-time"},"usage":{"type":"object","properties":{"sends":{"type":"integer"},"parses":{"type":"integer"},"inbound_skipped":{"type":"integer"},"webhook_deliveries":{"type":"integer"},"sends_cost_usd":{"type":"number"},"parses_cost_usd":{"type":"number"}},"required":["sends","parses","webhook_deliveries"]},"caps":{"type":"object","properties":{"monthly_sends":{"type":"integer"},"monthly_parses":{"type":"integer"},"agents":{"type":"integer"},"hourly":{"type":"integer"},"daily":{"type":"integer"},"hourly_inbound":{"type":"integer"},"daily_inbound":{"type":"integer"}},"required":["monthly_sends","monthly_parses","agents"]}},"required":["workspace_id","tier","usage","caps"]},"Me":{"type":"object","properties":{"api_key":{"type":"object","properties":{"id":{"type":"string"},"prefix":{"type":"string"},"name":{"type":["string","null"]},"mode":{"type":"string","enum":["live","test"]},"scopes":{"type":"array","items":{"type":"string"}},"agent_id":{"type":["string","null"]},"last_used_at":{"type":["string","null"]},"created_at":{"type":["string","null"]}},"required":["id","mode","scopes"]},"workspace":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"display_name":{"type":"string"},"tier":{"type":"string"},"tier_status":{"type":"string"}},"required":["id","slug"]},{"type":"null"}]},"agent":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string","format":"email"}},"required":["id","name","email"]},{"type":"null"}]}},"required":["api_key"]},"Classification":{"type":"object","properties":{"intent":{"type":"string"},"entities":{"type":"object","additionalProperties":true,"description":"Extracted entities as key→value pairs (object) — present when intent classification ran."},"urgency":{"type":"number","description":"Urgency score 0–1 (higher = more time-sensitive)."},"injection_score":{"type":"number"},"injection_categories":{"type":"array","items":{"type":"string"}},"sender_reputation":{"type":"number"},"classifier_model":{"type":"string"}},"required":["injection_score"]},"TestInboundResult":{"type":"object","properties":{"message_id":{"type":"string"},"thread_id":{"type":"string"},"event_id":{"type":"string"},"event_type":{"type":"string","enum":["message.received","reply.received","message.received.unauthenticated"]},"quarantined":{"type":"boolean"},"test_mode":{"type":"boolean"},"classification":{"$ref":"#/components/schemas/Classification"}},"required":["message_id","thread_id","event_id","event_type","quarantined","test_mode","classification"]},"Health":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded"]},"version":{"type":"string"},"db":{"type":"object","properties":{"status":{"type":"string","enum":["ok","error"]},"error":{"type":"string"}},"required":["status"]},"ses":{"type":"object","properties":{"mocked":{"type":"boolean"},"region":{"type":"string"}},"required":["mocked","region"]},"classifier":{"type":"object","properties":{"mocked":{"type":"boolean"},"model":{"type":"string"}},"required":["mocked","model"]},"schemas":{"type":"integer"},"timestamp":{"type":"string","format":"date-time"}},"required":["status","timestamp"]},"DnsRecord":{"type":"object","properties":{"type":{"type":"string","enum":["TXT","CNAME","MX"],"description":"DNS record type to create."},"host":{"type":"string","description":"Fully-qualified record host/name to create at your DNS provider."},"value":{"type":"string","description":"Exact record value. Copy verbatim."},"purpose":{"type":"string","enum":["spf","dkim","dmarc","return_path","tracking","ownership"]},"required":{"type":"boolean","description":"Required records gate verification; optional ones improve deliverability/reporting."},"verified":{"type":"boolean","description":"Whether the record was observed in DNS on the last check."}},"required":["type","host","value","purpose","required","verified"]},"Domain":{"type":"object","properties":{"id":{"type":"string","description":"Domain id (`dom_…`)."},"domain":{"type":"string","description":"The custom sending domain, lowercased."},"status":{"type":"string","enum":["pending","verifying","verified","failed"],"description":"pending → records issued; verifying → checks in progress; verified → agents on this domain send under their own identity; failed → too many failed checks (re-verify to retry)."},"provider":{"type":"string","description":"Backing sending infrastructure for this domain."},"dns_records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecord"}},"fail_reason":{"type":["string","null"],"description":"Why the last verification did not pass, when it didn't."},"last_check_at":{"type":["string","null"],"format":"date-time"},"verified_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"}},"required":["id","domain","status","dns_records","created_at"]}}}}