{"components":{"parameters":{"Addr":{"description":"The full inbox address, URL-encoded (e.g. `agent7%40extrovertmail.com`).","in":"path","name":"addr","required":true,"schema":{"type":"string"}},"AttachmentID":{"description":"Opaque attachment id locating one MIME part of the message.","in":"path","name":"attId","required":true,"schema":{"type":"string"}},"Cursor":{"description":"Opaque pagination cursor echoed back from a prior `next_cursor`. Treat it as an opaque token; pass it back verbatim as `?cursor` to fetch the next page.\n","in":"query","name":"cursor","required":false,"schema":{"type":"string"}},"Domain":{"description":"The fully-qualified domain name (e.g. `mail.acme.com`).","in":"path","name":"domain","required":true,"schema":{"type":"string"}},"Folder":{"description":"IMAP folder to read (default INBOX).","in":"query","name":"folder","required":false,"schema":{"type":"string"}},"IdempotencyKey":{"description":"Optional client-supplied key making a CREATE exactly-once. A retry with the same key returns the ORIGINAL response (same status + body) instead of creating a duplicate; the same key with a different request body returns 409. The body field `client_id` is honored as an alias when this header is absent. The key is scoped per tenant (and per agent on the agent plane), so keys never collide across callers.\n","in":"header","name":"Idempotency-Key","required":false,"schema":{"type":"string"}},"InboxID":{"description":"Opaque inbox id (the canonical path key). The inbox's email address is also accepted here as a within-project alias. Treat the id as opaque.\n","in":"path","name":"inbox_id","required":true,"schema":{"type":"string"}},"Include":{"description":"Comma-separated relation expansions (e.g. `?include=agent,domain`). Each relation is validated against a per-resource allowlist (depth \u003c= 2); a join re-applies the same ceiling/ownership filter as a direct read. A disallowed or too-deep path is a 400 `bad_request`.\n","in":"query","name":"include","required":false,"schema":{"type":"string"}},"LastEventID":{"description":"SSE resume token. On reconnect, set this to the `id` of the last event you received and the server replays every event after it. EventSource sets this header automatically; non-browser clients may instead pass the `last_event_id` query parameter.\n","in":"header","name":"Last-Event-ID","required":false,"schema":{"type":"string"}},"LastEventIDQuery":{"description":"SSE resume token as a query parameter, for clients (curl, fetch) that cannot set the `Last-Event-ID` header. Same semantics: replay events after this id.\n","in":"query","name":"last_event_id","required":false,"schema":{"type":"string"}},"Limit":{"description":"Page size for the cursor-paginated agent surface (default 50; clamped to the 1-100 range).","in":"query","name":"limit","required":false,"schema":{"default":50,"maximum":100,"minimum":1,"type":"integer"}},"MessageID":{"description":"Opaque message id (`msg_...`). Encodes its owning inbox.","in":"path","name":"id","required":true,"schema":{"type":"string"}},"Offset":{"description":"Result offset for the legacy offset-paginated surface.","in":"query","name":"offset","required":false,"schema":{"minimum":0,"type":"integer"}},"PageToken":{"description":"Opaque page token echoed back from a prior `next_page`. Used by the legacy offset-paginated admin/console list surface; the cursor-paginated agent surface uses `Cursor` (`?cursor`) instead.\n","in":"query","name":"page","required":false,"schema":{"type":"string"}}},"responses":{"BadGateway":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Upstream delivery failed. The request can be retried."},"BadRequest":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request."},"Conflict":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Resource conflict (e.g. a duplicate entry)."},"Forbidden":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Authenticated but lacking the required scope, or out of quota."},"IdempotencyConflict":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The supplied idempotency key was already used with a different request body (`error` = `idempotency_conflict`).\n"},"IntentRequired":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The resolved review mode is `review` but no intent summary was supplied (Problem `code` = `intent_required`; D3). Nothing was sent and nothing was queued; `detail` names the exact field to add and re-send.\n"},"NotConfigured":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"A required integration or server-side capability is not configured."},"NotFound":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Resource not found."},"RateLimited":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Per-key rate limit exceeded. Carries a `Retry-After` header.","headers":{"Retry-After":{"description":"Seconds until the window resets.","schema":{"type":"integer"}}}},"ReviewConflict":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A Review Loop conflict, as problem+json. Branch on `code`, NOT on the 409 status; the four codes demand opposite behavior. `stale`: the revision/version you named is no longer current (a human moved the draft) and NOTHING was mutated; `errors[]` carries the current `state`, `revision` and `version`, so re-apply your change on top and resubmit with the new `parent_revision` (retry, bounded to ~3). `born_stale`: the redraft was built against an older rule high-water; re-read the rules and resubmit, or `restamp_review` if nothing genuinely changed (at most one retry per high-water). `wrong_state`: this VERB is illegal from the current state but the draft is still live; NEVER retry the same verb; `errors[]` repeats an `allowed_action` entry per verb that IS legal right now. `terminal`: the review is already sent/auto_sent/cancelled; nothing will ever succeed, stop retrying, and a `front_run_next` review event carries the outcome. `send_needs_reconciliation`: a prior attempt is unconfirmed and parked for recover-by-Message-ID; do NOT resend, poll the review.\n"},"SendBadRequest":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The send/reply/forward is malformed or fails validation. Decode and validation failures are problem+json (`code`: `bad_request`) and NAME the offending field; an unknown key lists the accepted set, and supplying both `text` and the deprecated `body` with DIFFERENT content is `errors[0].code = conflicting_alias` (there is no safe guess, so the request is refused rather than relayed with the wrong bytes). A few pre-existing domain rejections reached through this path (e.g. `domain_not_allowed`) still carry the legacy `{error, message}` envelope.\n"},"SendUnprocessable":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The send/reply/forward is well-formed but cannot be processed. Always problem+json; branch on `code`. `intent_required` (D3): the resolved review mode is `review` and no intent summary was supplied; nothing was sent and nothing was queued, and `detail` names the field to add. `recipient_suppressed`: one or more recipients have a list-unsubscribe opt-out, and `errors[]` names ONLY the suppressed addresses; never the suppression scope or origin; so the agent can retry without them.\n"},"ServiceUnavailable":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"A required capability is not configured (e.g. buy-through-us)."},"Unauthorized":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid credential."},"Unavailable":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A dependency could not be read, so the request was failed CLOSED rather than served on a guess (Problem `code` = `unavailable`). Retryable; see `Retry-After`. Distinct from `not_configured`, which is permanent for this deployment.\n","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}}},"schemas":{"AcceptInvitationRequest":{"description":"Accept an invitation with its raw token. IDENTITY-ONLY: the accept binds to the authenticated user's VERIFIED Clerk email, which must equal the normalized invitation email (else 403). Idempotent for the same user.\n","properties":{"token":{"type":"string"}},"required":["token"],"type":"object"},"AccountRiskDial":{"description":"The account-wide default risk dial (org_settings; D4/D12); the values a per-category null override inherits. The single user-configurable brand-risk lever (canary rate, drift-demote K, maturity-gate thresholds, min confidence, first-contact gate, per-day auto-send cap).\n","properties":{"auto_send_cap_per_day":{"description":"Plan-tier per-customer auto-send volume cap (D1).","type":"integer"},"canary_rate":{"format":"double","type":"number"},"drift_demote_after":{"description":"Drift-demote threshold K.","type":"integer"},"first_contact_gate":{"type":"boolean"},"graduate_min_age_hours":{"description":"Maturity-gate minimum category age.","type":"integer"},"graduate_min_approvals":{"description":"Maturity-gate N (clean approvals).","type":"integer"},"min_confidence":{"format":"double","type":"number"}},"required":["min_confidence","first_contact_gate","drift_demote_after","canary_rate","graduate_min_approvals","graduate_min_age_hours","auto_send_cap_per_day"],"type":"object"},"AckReviewEventRequest":{"description":"Advance per-(agent, review) cursors and/or mark broadcast nudges done. Idempotent and monotonic; re-acking an older seq is a no-op (exactly-once effect, spec §6). Either set may be empty.\n","properties":{"acks":{"items":{"properties":{"review_id":{"type":"string"},"through_seq":{"type":"integer"}},"required":["review_id","through_seq"],"type":"object"},"type":"array"},"broadcast_ids":{"items":{"type":"string"},"type":"array"}},"type":"object"},"AckReviewEventResponse":{"properties":{"cursors":{"items":{"$ref":"#/components/schemas/ReviewEventCursor"},"type":"array"}},"required":["cursors"],"type":"object"},"AddContactListRequest":{"description":"Add one allow/block entry to an inbox's contact lists. `pattern` is a bare email address (matched in full) or a bare domain (matches any address in that domain). A block entry rejects a matching recipient; when any allow entry exists, sends are restricted to recipients that match one (allowlist mode).\n","properties":{"direction":{"default":"send","description":"Traffic direction the entry governs. Only `send` is enforced today (at outbound time); `receive` is accepted for forward-compatibility.\n","enum":["send","receive"],"type":"string"},"kind":{"description":"Whether this entry permits (allow) or rejects (block) a match.","enum":["allow","block"],"type":"string"},"pattern":{"description":"A bare email address or a bare domain (e.g. `acme.com`).","type":"string"}},"required":["kind","pattern"],"type":"object"},"AdminBilling":{"properties":{"billing_owner_id":{"description":"The org id used for plan and monthly usage enforcement.","type":"string"},"customer_id":{"type":"string"},"entitlements":{"$ref":"#/components/schemas/AdminBillingPlan"},"org_id":{"type":"string"},"plan_tier":{"enum":["free","developer","startup","enterprise"],"type":"string"},"plans":{"items":{"$ref":"#/components/schemas/AdminBillingPlan"},"type":"array"},"stripe_configured":{"type":"boolean"},"stripe_mode":{"enum":["test","live"],"type":"string"},"subscription":{"$ref":"#/components/schemas/AdminBillingSubscription"},"usage":{"$ref":"#/components/schemas/AdminBillingUsage"}},"required":["org_id","customer_id","billing_owner_id","stripe_mode","stripe_configured","plan_tier","entitlements","usage","plans"],"type":"object"},"AdminBillingPlan":{"properties":{"checkout_available":{"type":"boolean"},"custom":{"type":"boolean"},"custom_domain_limit":{"format":"int64","type":"integer"},"daily_message_cap":{"format":"int64","type":"integer"},"domain_annual_com_reference_cents":{"description":"Reference annual managed-domain price for .com; other TLDs are quoted from live registrar cost at checkout.","format":"int64","type":"integer"},"inbox_limit":{"format":"int64","type":"integer"},"included_messages_monthly":{"description":"Combined inbound plus outbound recipient/message quota.","format":"int64","type":"integer"},"member_limit":{"format":"int64","type":"integer"},"monthly_price_cents":{"format":"int64","type":"integer"},"name":{"type":"string"},"pod_limit":{"format":"int64","type":"integer"},"storage_bytes":{"description":"Decimal GB converted to bytes.","format":"int64","type":"integer"},"tier":{"enum":["free","developer","startup","enterprise"],"type":"string"},"webhook_limit":{"format":"int64","type":"integer"}},"required":["tier","name","monthly_price_cents","domain_annual_com_reference_cents","included_messages_monthly","inbox_limit","custom_domain_limit","storage_bytes","pod_limit","webhook_limit","member_limit"],"type":"object"},"AdminBillingSubscription":{"properties":{"cancel_at_period_end":{"type":"boolean"},"current_period_end":{"format":"date-time","type":"string"},"current_period_start":{"format":"date-time","type":"string"},"customer_id":{"type":"string"},"org_id":{"type":"string"},"plan_tier":{"enum":["free","developer","startup","enterprise"],"type":"string"},"status":{"type":"string"},"stripe_customer_id":{"type":"string"},"stripe_price_id":{"type":"string"},"stripe_subscription_id":{"type":"string"},"stripe_subscription_item_id":{"type":"string"}},"required":["org_id","customer_id","plan_tier","status","cancel_at_period_end"],"type":"object"},"AdminBillingUsage":{"properties":{"billing_owner_id":{"type":"string"},"customer_id":{"type":"string"},"message_quota_exceeded":{"type":"boolean"},"message_quota_limit":{"description":"Combined monthly inbound plus outbound message quota for the effective plan; -1 means unlimited/custom.","format":"int64","type":"integer"},"message_quota_remaining":{"description":"Remaining included messages this month; -1 means unlimited/custom.","format":"int64","type":"integer"},"month":{"example":"2026-06","type":"string"},"received_messages":{"format":"int64","type":"integer"},"received_recipients":{"format":"int64","type":"integer"},"sent_messages":{"format":"int64","type":"integer"},"sent_recipients":{"format":"int64","type":"integer"},"storage_bytes":{"description":"Compatibility alias for storage_used_bytes.","format":"int64","type":"integer"},"storage_captured_at":{"format":"date-time","type":"string"},"storage_included_bytes":{"description":"Included storage bytes for the effective plan; -1 means unlimited/custom.","format":"int64","type":"integer"},"storage_mailbox_count":{"type":"integer"},"storage_over_limit_bytes":{"format":"int64","type":"integer"},"storage_peak_over_limit_bytes":{"format":"int64","type":"integer"},"storage_peak_used_bytes":{"description":"Billing-month high-water mark","format":"int64","summed from the peak observed bytes per durable storage object.":null,"type":"integer"},"storage_quota_exceeded":{"type":"boolean"},"storage_used_bytes":{"description":"Current owner-level storage gauge from latest mailbox snapshots.","format":"int64","type":"integer"},"total_messages":{"format":"int64","type":"integer"}},"required":["billing_owner_id","customer_id","month","sent_messages","sent_recipients","received_messages","received_recipients","storage_bytes","storage_used_bytes","storage_peak_used_bytes","storage_included_bytes","storage_over_limit_bytes","storage_peak_over_limit_bytes","storage_mailbox_count","storage_quota_exceeded","total_messages","message_quota_limit","message_quota_remaining","message_quota_exceeded"],"type":"object"},"AdminCreateCategoryRequest":{"description":"Create a human-authored shared category from the console.","properties":{"description":{"description":"Skill-style matcher text the agent reads (mutable).","type":"string"},"name":{"description":"Display name (mutable metadata; never a reference key).","type":"string"},"scope":{"description":"Defaults to org_shared.","enum":["org_shared","agent_private"],"type":"string"}},"required":["name"],"type":"object"},"AdminCreateInboxRequest":{"properties":{"agent_id":{"description":"Active agent that owns the new inbox.","type":"string"},"display_name":{"type":"string"},"domain":{"description":"Domain name fallback when domain_id is omitted.","type":"string"},"domain_id":{"description":"Domain id from the console domains list.","type":"string"},"username":{"description":"Local part. On `extrovertmail.com` and `free.extrovertmail.com` it is normalized to lowercase, must contain at least five characters, and must not be postmaster, admin, webadmin, legal, fraudmark, fraudmarc, keith, melissa, richard, sydney, syd, john, or johnny. These restrictions do not apply to customer-owned domains. Omit it for a generated local part.\n","type":"string"},"webhook_url":{"type":"string"}},"required":["agent_id"],"type":"object"},"AdminIdentity":{"properties":{"clerk_user_id":{"type":"string"},"email":{"type":"string"}},"type":"object"},"AdminInbox":{"properties":{"address":{"type":"string"},"agent_id":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"daily_send_cap":{"type":"integer"},"daily_send_used":{"description":"Recipients sent in the rolling 24-hour window.","type":"integer"},"direct_smtp_enabled":{"description":"Whether this inbox is configured for direct SMTP outside the review pipeline. Effective access also requires an active paid entitlement.\n","type":"boolean"},"domain":{"type":"string"},"webhook_url":{"type":"string"}},"type":"object"},"AdminInboxList":{"properties":{"inboxes":{"items":{"$ref":"#/components/schemas/AdminInbox"},"type":"array"},"next_page":{"type":"string"}},"type":"object"},"AdminMe":{"description":"The authenticated console identity's reachable orgs + projects (GET /v1/admin/me). IDENTITY-ONLY: the reachable set is derived from the user's membership rows, never from a preselected/cookie customer. The *_hint fields are landing hints only; the console revalidates them against reachable_orgs/projects_by_org before using them.\n","properties":{"active_org_hint":{"description":"Landing hint (the user's default org).","type":"string"},"active_project_hint":{"description":"Landing hint (the user's default project).","type":"string"},"identity":{"$ref":"#/components/schemas/AdminIdentity"},"last_project_by_org":{"additionalProperties":{"type":"string"},"description":"Per-org remembered/default project (orgId -\u003e projectId).","type":"object"},"pending_signup_claims":{"description":"Live system-seeded owner claims matching the authenticated identity's verified email. Claim ids are selectors, not bearer credentials; no invitation token or hash material is exposed.\n","items":{"$ref":"#/components/schemas/PendingSignupClaim"},"type":"array"},"projects_by_org":{"additionalProperties":{"items":{"$ref":"#/components/schemas/AdminProjectSummary"},"type":"array"},"description":"The active projects for each reachable org, keyed by org id.","type":"object"},"reachable_orgs":{"items":{"$ref":"#/components/schemas/AdminReachableOrg"},"type":"array"}},"required":["identity","last_project_by_org","reachable_orgs","projects_by_org","pending_signup_claims"],"type":"object"},"AdminMessage":{"description":"A source-preserving message shape for the console plane.","properties":{"body":{"type":"string"},"cc":{"type":"string"},"date":{"type":"string"},"direction":{"enum":["inbound","outbound"],"type":"string"},"extracted_html":{"type":"string"},"extracted_text":{"type":"string"},"from":{"type":"string"},"has_attachments":{"type":"boolean"},"html":{"type":"string"},"id":{"type":"string"},"in_reply_to":{"type":"string"},"message_id":{"type":"string"},"references":{"type":"string"},"reply_to":{"type":"string"},"seen":{"type":"boolean"},"seq":{"type":"string"},"subject":{"type":"string"},"text":{"type":"string"},"thread_id":{"type":"string"},"to":{"type":"string"}},"type":"object"},"AdminMessageDetail":{"allOf":[{"$ref":"#/components/schemas/Message"},{"properties":{"attachments":{"items":{"$ref":"#/components/schemas/Attachment"},"type":"array"}},"type":"object"}]},"AdminMessageList":{"properties":{"messages":{"items":{"$ref":"#/components/schemas/AdminMessage"},"type":"array"}},"type":"object"},"AdminOrgLimits":{"properties":{"max_child_orgs":{"type":"integer"},"max_projects":{"type":"integer"}},"type":"object"},"AdminProjectSummary":{"description":"A project summary as rendered in the project switcher.","properties":{"id":{"description":"Canonical project UUID.","type":"string"},"is_default":{"type":"boolean"},"name":{"type":"string"},"slug":{"type":"string"}},"required":["id","name","slug","is_default"],"type":"object"},"AdminReachableOrg":{"description":"One org the identity can reach, with the effective role + source.","properties":{"breadcrumb":{"items":{"type":"string"},"type":"array"},"customer_id":{"description":"Compatibility customer id linked to the org.","type":"string"},"depth":{"description":"Distance from the root org (0 = root).","type":"integer"},"display_name":{"type":"string"},"id":{"description":"Canonical org UUID.","type":"string"},"limits":{"$ref":"#/components/schemas/AdminOrgLimits"},"parent_org_id":{"description":"Null for a root org.","nullable":true,"type":"string"},"plan_tier":{"type":"string"},"role":{"enum":["owner","admin","member","viewer","billing"],"type":"string"},"root_org_id":{"type":"string"},"source":{"description":"How the identity reaches this org.","enum":["direct","inherited","msp_grant"],"type":"string"}},"required":["id","customer_id","display_name","root_org_id","role","source","depth","breadcrumb","plan_tier","limits"],"type":"object"},"AdminRegisterWebhookRequest":{"allOf":[{"$ref":"#/components/schemas/RegisterWebhookRequest"},{"properties":{"agent_id":{"description":"Active agent that owns the webhook registration.","type":"string"}},"required":["agent_id"],"type":"object"}]},"AdminReviewAction":{"description":"A human-authority review action body (console plane, D17). revision + version are the CAS naming the draft the human acted on (a mismatch is a 409 STALE). subject/body are supplied only on edit-send; feedback is the optional rule-birth signal (D7, empty allowed).\n","properties":{"body":{"description":"Edited body text (edit-send only).","type":"string"},"feedback":{"description":"Optional decision comment / rule-birth signal.","type":"string"},"revision":{"type":"integer"},"subject":{"description":"Edited subject (edit-send only).","type":"string"},"version":{"type":"integer"}},"required":["revision","version"],"type":"object"},"AdminReviewChatRequest":{"description":"The console chat side-panel body (M5; spec §10): a human comment whose OTHER party is the composing agent. CONSOLE-ONLY (never an MCP tool, D17).\n","properties":{"text":{"description":"The human's comment for the composing agent.","type":"string"}},"required":["text"],"type":"object"},"AdminReviewDetail":{"description":"Full console review detail (console plane): the review (intent + current draft + diff if revised) plus the append-only thread turns.\n","properties":{"review":{"$ref":"#/components/schemas/Review"},"turns":{"items":{"$ref":"#/components/schemas/ReviewTurn"},"type":"array"}},"required":["review","turns"],"type":"object"},"AdminReviewListItem":{"description":"One Approvals-queue row (console plane, D17). Metadata + intent summary + subject + a body snippet only; never the full body (loaded on detail open).\n","properties":{"agent_id":{"type":"string"},"category_id":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"effective_mode":{"enum":["review","direct"],"type":"string"},"escalation_reason":{"description":"Why a reviewer-loop draft landed back in the human queue (M8; §9): a reviewer's escalate, or a circuit breaker (max_hops / review_deadline) forcing it to the human. Empty for an ordinary review.","type":"string"},"from_address":{"type":"string"},"gate_outcome":{"description":"The auto-send divert reason (held:\u003creason\u003e) when the submit-time gate routed this message to the human (M6); empty for an ordinary review.","type":"string"},"hop_count":{"description":"The monotonic reviewer hand-back counter (M8 breaker (a)); surfaced so a maxed-out review reads as forced-to-human.","type":"integer"},"id":{"type":"string"},"intent_summary":{"type":"string"},"kind":{"enum":["send","reply","forward"],"type":"string"},"mode":{"enum":["review","direct"],"type":"string"},"revision":{"type":"integer"},"snippet":{"type":"string"},"stale_reason":{"type":"string"},"state":{"enum":["needs_review","in_review","chatting","stale","approved","sent","auto_sent","rejected","stalled","cancelled","failed"],"type":"string"},"subject":{"type":"string"},"updated_at":{"format":"date-time","type":"string"},"version":{"type":"integer"}},"required":["id","state","mode","effective_mode","kind","revision","version"],"type":"object"},"AdminReviewPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AdminReviewListItem"},"type":"array"},"next_cursor":{"type":"string"},"total":{"type":"integer"}},"required":["items","total"],"type":"object"},"AdminReviewRejectResult":{"properties":{"review_id":{"type":"string"},"state":{"type":"string"},"status":{"example":"rejected","type":"string"}},"required":["status","review_id","state"],"type":"object"},"AdminReviewSendResult":{"description":"The approve / edit-send success result. The platform performed the authenticated send via the COMPOSER's inbox; the send is irreversible once returned.\n","properties":{"message_id":{"type":"string"},"review_id":{"type":"string"},"state":{"type":"string"},"status":{"example":"sent","type":"string"},"thread_id":{"type":"string"}},"required":["status","review_id","state","message_id"],"type":"object"},"AdminThreadDetail":{"properties":{"messages":{"items":{"$ref":"#/components/schemas/AdminMessage"},"type":"array"},"subject":{"type":"string"},"thread_id":{"type":"string"}},"type":"object"},"AdminThreadList":{"description":"A cursor page of persistent thread summaries for one inbox.","properties":{"next_cursor":{"type":"string"},"threads":{"items":{"$ref":"#/components/schemas/AdminUnifiedThread"},"type":"array"},"total":{"type":"integer"}},"type":"object"},"AdminUnifiedThread":{"description":"One row in the shared-inbox feed, tagged with its owning inbox.","properties":{"id":{"type":"string"},"inbox":{"type":"string"},"last_message_at":{"type":"string"},"last_message_has_attachments":{"type":"boolean"},"last_message_id":{"type":"string"},"message_count":{"type":"integer"},"participants":{"items":{"type":"string"},"type":"array"},"snippet":{"type":"string"},"subject":{"type":"string"},"unread":{"type":"boolean"}},"type":"object"},"AdminUnifiedThreadFeed":{"description":"Stable keyset page merged newest-first across the active project's inboxes.","properties":{"failed_inboxes":{"items":{"type":"string"},"type":"array"},"inbox_count":{"type":"integer"},"next_cursor":{"description":"Opaque global keyset cursor; pass back unchanged.","type":"string"},"partial_failure":{"type":"boolean"},"threads":{"items":{"$ref":"#/components/schemas/AdminUnifiedThread"},"type":"array"},"total":{"type":"integer"}},"type":"object"},"AdminUpdateInboxRequest":{"additionalProperties":false,"minProperties":1,"properties":{"daily_send_limit":{"maximum":10000,"minimum":1,"type":"integer"},"direct_smtp_enabled":{"description":"Explicit per-inbox raw SMTP bypass. It is disabled by default and can be enabled only by a human for an account with an active paid entitlement. Disabling is always allowed. Agent API, SDK, and MCP sends continue through the normal review controls regardless of this setting.\n","type":"boolean"}},"type":"object"},"AgentDomain":{"description":"The agent-facing view of one domain: its status plus the nameserver records the customer must publish for delegated setup. Records are empty on list reads and for hosted/purchased modes.\n","properties":{"created_at":{"format":"date-time","type":"string"},"delegation_ns":{"items":{"$ref":"#/components/schemas/RecordInstruction"},"type":"array"},"dkim_status":{"type":"string"},"domain":{"type":"string"},"id":{"type":"string"},"instruction":{"type":"string"},"mode":{"enum":["shared","ns_delegated","manual","purchased"],"type":"string"},"provisioning_error":{"type":"string"},"provisioning_phase":{"type":"string"},"records":{"items":{"$ref":"#/components/schemas/RecordInstruction"},"type":"array"},"shared":{"type":"boolean"},"verification_status":{"type":"string"}},"type":"object"},"AgentDomainList":{"description":"A page of domains in the canonical agent-plane envelope.","properties":{"items":{"items":{"$ref":"#/components/schemas/AgentDomain"},"type":"array"},"next_cursor":{"type":"string"},"total":{"type":"integer"}},"type":"object"},"AgentKeyList":{"properties":{"keys":{"items":{"$ref":"#/components/schemas/AgentKeySummary"},"type":"array"},"next_page":{"type":"string"}},"type":"object"},"AgentKeySummary":{"properties":{"agent_handle":{"type":"string"},"agent_id":{"type":"string"},"agent_name":{"type":"string"},"ceiling_inbox_id":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"enrollment_token_id":{"type":"string"},"expires_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"key_tier":{"enum":["org","project","inbox"],"type":"string"},"last_used_at":{"format":"date-time","type":"string"},"prefix":{"type":"string"},"revoked":{"type":"boolean"},"scopes":{"items":{"type":"string"},"type":"array"}},"type":"object"},"AgentList":{"properties":{"agents":{"items":{"$ref":"#/components/schemas/AgentSummary"},"type":"array"},"next_page":{"type":"string"}},"type":"object"},"AgentStatusResult":{"properties":{"agent_id":{"type":"string"},"status":{"enum":["active","disabled"],"type":"string"}},"type":"object"},"AgentSummary":{"properties":{"created_at":{"format":"date-time","type":"string"},"handle":{"type":"string"},"id":{"type":"string"},"last_seen_at":{"description":"Latest authenticated API-key activity.","format":"date-time","nullable":true,"type":"string"},"mailbox_count":{"description":"Inboxes owned by this agent in the active project.","minimum":0,"type":"integer"},"name":{"type":"string"},"status":{"enum":["active","disabled"],"type":"string"}},"type":"object"},"Attachment":{"description":"Attachment metadata. Download the bytes from the attachment endpoint.","properties":{"content_type":{"example":"application/pdf","type":"string"},"filename":{"type":"string"},"id":{"type":"string"},"size":{"description":"Size in bytes.","type":"integer"}},"type":"object"},"AttachmentInput":{"description":"An outbound attachment on send/reply/forward.","properties":{"content_base64":{"description":"Standard base64-encoded attachment bytes.","type":"string"},"content_type":{"type":"string"},"filename":{"type":"string"}},"required":["content_base64"],"type":"object"},"AttachmentPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Attachment"},"type":"array"},"total":{"type":"integer"}},"type":"object"},"AuditEvent":{"properties":{"action":{"type":"string"},"actor":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"metadata":{"additionalProperties":{"type":"string"},"type":"object"},"severity":{"enum":["info","warn","error"],"type":"string"},"target":{"type":"string"}},"type":"object"},"AuditList":{"properties":{"events":{"items":{"$ref":"#/components/schemas/AuditEvent"},"type":"array"},"next_page":{"type":"string"}},"type":"object"},"BatchUpdateMessagesRequest":{"description":"Apply a read-state toggle and/or a folder move to a list of message ids that all belong to the path inbox. At least one of `read` / `folder` must be set. Ids that are malformed or address a different inbox are reported in the response's `failed` list rather than failing the whole batch.\n","properties":{"folder":{"description":"When present, move each message to this folder. One of INBOX, Sent, Trash, Junk, Archive.\n","enum":["INBOX","Sent","Trash","Junk","Archive"],"type":"string"},"ids":{"description":"Opaque message ids (msg_…), all owned by the path inbox. Max 200.","items":{"type":"string"},"type":"array"},"read":{"description":"When present, set (true) or clear (false) the \\Seen flag on each id.","type":"boolean"}},"required":["ids"],"type":"object"},"BatchUpdateResult":{"description":"Per-id outcome of a batch update.","properties":{"failed":{"description":"Ids skipped (not found, malformed, or not owned by this inbox).","items":{"type":"string"},"type":"array"},"updated":{"description":"Ids that were updated.","items":{"type":"string"},"type":"array"}},"required":["updated","failed"],"type":"object"},"Category":{"description":"A category (cat_…) in the registry (Review Loop, D9/D10). name + description are the skill-style metadata an agent fuzzy-matches against (NO LLM on our side; the agent does the matching). Categories are CUSTOMER-scoped and agent-attributed; nothing keys on the name (renames never break a reference).\n","properties":{"author_kind":{"enum":["agent","human"],"type":"string"},"clean_approval_count":{"description":"Clean human-approve-as-is count toward the maturity gate (D16).","type":"integer"},"created_at":{"format":"date-time","type":"string"},"created_by_agent_id":{"type":"string"},"description":{"type":"string"},"drift_count":{"description":"Human edit/reject count in a graduated category toward drift auto-demote (K; §7).","type":"integer"},"graduated_at":{"description":"When the category was last graduated (omitted if never).","format":"date-time","type":"string"},"graduated_by":{"description":"Who last graduated it ('human:\u003csub\u003e'); empty if never/demoted.","type":"string"},"id":{"description":"Opaque category id (cat_…).","type":"string"},"merged_into":{"description":"Survivor category id when this one was merged/soft-deleted (cat_…).","type":"string"},"name":{"type":"string"},"never_graduate":{"description":"Human lock pinning the category at supervised (no live auto-send; D16).","type":"boolean"},"rule_high_water":{"type":"integer"},"rules_version":{"type":"integer"},"scope":{"enum":["org_shared","agent_private"],"type":"string"},"state":{"enum":["supervised","auto_notify","auto_silent"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","name","description","scope","state","author_kind","rule_high_water","rules_version"],"type":"object"},"CategoryPacingState":{"description":"The demand-driven pacing snapshot for a category (agent-readable, $0-LLM, M7 Slice B/§8): the human review cursor position, the effective window/ceiling/ interval, the queued count, and each queued draft's in-window/redrafting/ behind-cursor classification. Read-only; the cursor advances from the human's console approve/reject/edit actions.\n","properties":{"category_id":{"type":"string"},"cursor_advanced_count":{"description":"Monotonic count of cursor advances.","type":"integer"},"cursor_review_id":{"description":"The last queued draft the human acted on (the cursor); omitted when nothing reviewed yet.","type":"string"},"in_window":{"description":"Of the queued, how many sit in the freshness-guaranteed window.","type":"integer"},"items":{"items":{"$ref":"#/components/schemas/PacingItem"},"type":"array"},"lookahead_window":{"description":"Effective freshness window (default org_settings.lookahead_window=3).","type":"integer"},"nudge_min_interval_ms":{"description":"Per-agent token-bucket interval that coalesces feedback storms (default 5000).","type":"integer"},"queued":{"description":"How many drafts are in the human queue (needs_review|in_review|chatting).","type":"integer"},"redrafting":{"description":"Of the in-window, how many are stale and being redrafted (the console shimmer set).","type":"integer"},"rework_batch_max":{"description":"HARD per-nudge fan-out ceiling (default org_settings.rework_batch_max=10); one nudge can never fan to 500.","type":"integer"}},"required":["category_id","cursor_advanced_count","lookahead_window","rework_batch_max","nudge_min_interval_ms","queued","in_window","redrafting","items"],"type":"object"},"CategoryPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Category"},"type":"array"},"total":{"type":"integer"}},"required":["items","total"],"type":"object"},"CategoryRiskDial":{"description":"One category's risk-dial OVERRIDE columns (null = inherit the account default; D12) alongside the resolved effective dial. A null field means the category inherits that value from the account default.\n","properties":{"canary_rate":{"format":"double","nullable":true,"type":"number"},"category_id":{"type":"string"},"drift_demote_after":{"nullable":true,"type":"integer"},"effective":{"$ref":"#/components/schemas/EffectiveRiskDial"},"first_contact_gate":{"nullable":true,"type":"boolean"},"graduate_min_age_hours":{"nullable":true,"type":"integer"},"graduate_min_approvals":{"nullable":true,"type":"integer"},"min_confidence":{"format":"double","nullable":true,"type":"number"}},"required":["category_id","effective"],"type":"object"},"CategoryRiskDialRequest":{"description":"Set / clear a category's risk-dial overrides (console plane, D12). For each field, a non-null value SETS the override; an explicit JSON null RESETS it to inherit; an omitted field is unchanged.\n","properties":{"canary_rate":{"format":"double","nullable":true,"type":"number"},"drift_demote_after":{"nullable":true,"type":"integer"},"first_contact_gate":{"nullable":true,"type":"boolean"},"graduate_min_age_hours":{"nullable":true,"type":"integer"},"graduate_min_approvals":{"nullable":true,"type":"integer"},"min_confidence":{"format":"double","nullable":true,"type":"number"}},"type":"object"},"CommerceBlocker":{"properties":{"code":{"type":"string"},"limit_cents":{"format":"int64","type":"integer"},"limit_count":{"format":"int64","type":"integer"},"limit_id":{"type":"string"},"manage_url":{"format":"uri","type":"string"},"message":{"type":"string"},"requested_cents":{"format":"int64","type":"integer"},"reserved_cents":{"format":"int64","type":"integer"},"reserved_count":{"format":"int64","type":"integer"},"reset_at":{"format":"date-time","type":"string"},"scope":{"type":"string"},"used_cents":{"format":"int64","type":"integer"},"used_count":{"format":"int64","type":"integer"}},"required":["code","message"],"type":"object"},"CommerceRequest":{"properties":{"agent_id":{"description":"Present when an agent initiated the request.","type":"string"},"agent_next_action":{"type":"string"},"approval_url":{"format":"uri","type":"string"},"approved_max_cents":{"format":"int64","type":"integer"},"auto_renew":{"type":"boolean"},"blocker_code":{"type":"string"},"blockers":{"items":{"$ref":"#/components/schemas/CommerceBlocker"},"type":"array"},"created_at":{"format":"date-time","type":"string"},"currency":{"type":"string"},"current_plan":{"type":"string"},"domain":{"type":"string"},"domain_scope":{"enum":["org","project"],"type":"string"},"effective_at":{"format":"date-time","type":"string"},"external_job_id":{"type":"string"},"id":{"type":"string"},"kind":{"enum":["domain_purchase","plan_change"],"type":"string"},"notification_last_error":{"type":"string"},"notification_state":{"type":"string"},"object":{"enum":["commerce_request"],"type":"string"},"payment_action_url":{"format":"uri","type":"string"},"poll_after_seconds":{"type":"integer"},"project_id":{"type":"string"},"quote_cents":{"format":"int64","type":"integer"},"quote_expires_at":{"format":"date-time","type":"string"},"rationale":{"type":"string"},"renewal_cents":{"format":"int64","type":"integer"},"required_plan":{"type":"string"},"required_plan_price_cents":{"format":"int64","type":"integer"},"retry_safe":{"type":"boolean"},"state":{"type":"string"},"target_plan":{"type":"string"},"updated_at":{"format":"date-time","type":"string"},"version":{"format":"int64","type":"integer"}},"required":["object","id","kind","state","currency","quote_cents","renewal_cents","auto_renew","blockers","agent_next_action","retry_safe","poll_after_seconds","version","created_at","updated_at"],"type":"object"},"CommerceRequestPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/CommerceRequest"},"type":"array"},"next_cursor":{"type":"string"},"total":{"type":"integer"}},"required":["items","total"],"type":"object"},"CommerceSpendLimit":{"allOf":[{"$ref":"#/components/schemas/CommerceSpendLimitInput"},{"properties":{"created_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"org_id":{"type":"string"},"period_end":{"format":"date-time","type":"string"},"period_start":{"format":"date-time","type":"string"},"purchased_count":{"format":"int64","type":"integer"},"reserved_cents":{"format":"int64","type":"integer"},"reserved_count":{"format":"int64","type":"integer"},"spent_cents":{"format":"int64","type":"integer"},"updated_at":{"format":"date-time","type":"string"},"version":{"format":"int64","type":"integer"}},"required":["id","org_id","currency","period_start","spent_cents","reserved_cents","purchased_count","reserved_count","active","version","created_at","updated_at"],"type":"object"}]},"CommerceSpendLimitInput":{"properties":{"active":{"type":"boolean"},"agent_id":{"type":"string"},"allow_premium":{"type":"boolean"},"allowed_tlds":{"items":{"type":"string"},"type":"array"},"budget_cents":{"format":"int64","minimum":0,"type":"integer"},"budget_enabled":{"type":"boolean"},"cadence":{"enum":["does_not_repeat","weekly","monthly","quarterly","annually"],"type":"string"},"currency":{"default":"usd","type":"string"},"domain_count_enabled":{"type":"boolean"},"domain_count_limit":{"format":"int64","minimum":0,"type":"integer"},"expected_version":{"format":"int64","type":"integer"},"expires_at":{"format":"date-time","type":"string"},"name":{"type":"string"},"per_purchase_enabled":{"type":"boolean"},"per_purchase_max_cents":{"format":"int64","minimum":0,"type":"integer"},"project_id":{"type":"string"},"scope":{"enum":["org","project","agent"],"type":"string"}},"required":["scope","name","cadence","budget_cents","budget_enabled","per_purchase_max_cents","per_purchase_enabled","domain_count_limit","domain_count_enabled","allow_premium"],"type":"object"},"Connection":{"description":"One IMAP or SMTP endpoint for a mailbox.","properties":{"host":{"example":"smtp.extrovert.dev","type":"string"},"port":{"example":993,"type":"integer"},"security":{"description":"`tls` (implicit TLS, e.g. IMAP 993) or `starttls` (e.g. SMTP 587).","enum":["tls","starttls"],"type":"string"}},"type":"object"},"ContactListEntry":{"description":"One allow/block contact-list entry. `inbox` is null when the entry is account-wide (covers every inbox the agent owns).\n","properties":{"created_at":{"format":"date-time","type":"string"},"direction":{"enum":["send","receive"],"type":"string"},"id":{"type":"string"},"inbox":{"nullable":true,"type":"string"},"kind":{"enum":["allow","block"],"type":"string"},"pattern":{"type":"string"}},"type":"object"},"ContactListPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ContactListEntry"},"type":"array"},"total":{"type":"integer"}},"type":"object"},"CreateAgentRequest":{"additionalProperties":false,"properties":{"name":{"description":"Human-facing agent name. The server generates its technical handle.","maxLength":120,"minLength":1,"type":"string"}},"required":["name"],"type":"object"},"CreateBillingCheckoutRequest":{"properties":{"cancel_url":{"format":"uri","type":"string"},"plan_tier":{"enum":["developer","startup"],"type":"string"},"success_url":{"format":"uri","type":"string"}},"required":["plan_tier","success_url","cancel_url"],"type":"object"},"CreateBillingCheckoutResponse":{"properties":{"id":{"description":"Stripe Checkout Session id.","type":"string"},"mode":{"enum":["test","live"],"type":"string"},"plan_tier":{"enum":["developer","startup"],"type":"string"},"status":{"type":"string"},"subscription":{"$ref":"#/components/schemas/AdminBillingSubscription"},"url":{"format":"uri","type":"string"}},"required":["id","url","status","plan_tier","mode","subscription"],"type":"object"},"CreateBillingPortalRequest":{"properties":{"return_url":{"format":"uri","type":"string"}},"required":["return_url"],"type":"object"},"CreateBillingPortalResponse":{"properties":{"id":{"description":"Stripe Billing Portal Session id.","type":"string"},"mode":{"enum":["test","live"],"type":"string"},"url":{"format":"uri","type":"string"}},"required":["id","url","mode"],"type":"object"},"CreateDomainBillingCheckoutRequest":{"properties":{"cancel_url":{"format":"uri","type":"string"},"domain":{"example":"agent.agency","type":"string"},"success_url":{"format":"uri","type":"string"}},"required":["domain","success_url","cancel_url"],"type":"object"},"CreateDomainBillingCheckoutResponse":{"properties":{"baseline_com_cost_cents":{"format":"int64","type":"integer"},"currency":{"example":"usd","type":"string"},"domain":{"type":"string"},"domain_annual_price_cents":{"format":"int64","type":"integer"},"id":{"description":"Stripe Checkout Session id.","type":"string"},"mode":{"enum":["test","live"],"type":"string"},"plan_tier":{"enum":["developer","startup"],"type":"string"},"registrar_cost_cents":{"format":"int64","type":"integer"},"status":{"type":"string"},"stripe_price_id":{"type":"string"},"url":{"format":"uri","type":"string"}},"required":["id","url","status","mode","domain","plan_tier","currency","registrar_cost_cents","baseline_com_cost_cents","domain_annual_price_cents","stripe_price_id"],"type":"object"},"CreateDomainPurchaseRequest":{"properties":{"auto_renew":{"default":true,"type":"boolean"},"domain":{"type":"string"},"project_id":{"type":"string"},"rationale":{"maxLength":2000,"type":"string"},"scope":{"default":"org","enum":["org","project"],"type":"string"}},"required":["domain"],"type":"object"},"CreateInboxRequest":{"properties":{"client_id":{"description":"Optional idempotency key (alias for the `Idempotency-Key` header). Re-creating with the same key returns the existing inbox rather than a duplicate; the same key with a different body returns 409.\n","type":"string"},"display_name":{"type":"string"},"domain":{"description":"Must be within the key's allowed domains. Omit for the account's plan-appropriate shared domain.","type":"string"},"metadata":{"additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]},"description":"Optional arbitrary key-value metadata to store on the inbox (AgentMail parity). Values may be string, number, or boolean. Caps: ≤256 keys, ≤256 chars per key, ≤256 chars per string value. Nested objects and arrays are rejected. Echoed back (and replayed on idempotent retries) on the create response.\n","nullable":true,"type":"object"},"project_id":{"description":"Optional assertion that must match the key's bound project; NEVER a selector. A mismatch is 403. The inbox is always created in the key's stored project.\n","type":"string"},"return_credentials":{"default":false,"description":"Return the one-time IMAP/SMTP password on a newly created inbox. Requires the mailbox:credentials scope and a paid account. Omit this on ordinary agent/MCP creates.\n","type":"boolean"},"username":{"description":"Local part. On `extrovertmail.com` and `free.extrovertmail.com` it is normalized to lowercase, must contain at least five characters, and must not be postmaster, admin, webadmin, legal, fraudmark, fraudmarc, keith, melissa, richard, sydney, syd, john, or johnny. These restrictions do not apply to customer-owned domains. Omit it for a generated local part.\n","type":"string"},"webhook_url":{"description":"Register an inbound webhook for this inbox.","type":"string"}},"type":"object"},"CreateInvitationRequest":{"description":"Invite an email to the org. Role-capped: the inviter cannot grant a role above their own effective role. Idempotent: one pending invitation per (org, email). The raw token is returned ONCE on a fresh create.\n","properties":{"email":{"format":"email","type":"string"},"expires_in_days":{"description":"Optional TTL in days.","type":"integer"},"role":{"enum":["owner","admin","member","viewer","billing"],"type":"string"}},"required":["email","role"],"type":"object"},"CreateOrgRequest":{"description":"Create a CHILD org. parent_org_id is required (only child orgs are creatable from the console in v1; a user's single root org is bootstrapped on first sign-in). admin+ on the parent is required. Client-supplied org ids are NEVER accepted; the server creates a UUID and a compatibility customer id.\n","properties":{"display_name":{"type":"string"},"parent_org_id":{"type":"string"},"slug":{"type":"string"}},"required":["parent_org_id"],"type":"object"},"CreatePlanChangeRequest":{"properties":{"project_id":{"description":"Required on the console creation route; agent routes derive it from the key.","type":"string"},"rationale":{"maxLength":2000,"type":"string"},"target_plan":{"enum":["free","developer","startup"],"type":"string"}},"required":["target_plan"],"type":"object"},"CreateProjectRequest":{"description":"Create a project under the org. Enforced against the org's max_projects cap inside the same transaction as the create. Client-supplied ids are never accepted; the server creates a UUID.\n","properties":{"description":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"}},"required":["name"],"type":"object"},"CreateReviewLinkRequest":{"description":"Link a reviewer agent to an inbox (or account-wide). transport defaults to webhook; a webhook transport REQUIRES webhook_url. The timing knobs default at the server when omitted (escalate_after_s=300, max_hops=3, review_deadline_s= 86400). One link per scope; a duplicate scope is 409.\n","properties":{"escalate_after_s":{"type":"integer"},"hmac_secret":{"description":"Write-only signing secret for webhook deliveries.","type":"string"},"inbox_address":{"description":"Empty = account-wide.","type":"string"},"max_hops":{"type":"integer"},"review_deadline_s":{"type":"integer"},"reviewer_agent_id":{"description":"The reviewer agent (agt_…)","must belong to the customer.":null,"type":"string"},"transport":{"description":"Defaults webhook.","enum":["webhook","sse","websocket"],"type":"string"},"webhook_url":{"description":"Required for the webhook transport.","type":"string"}},"required":["reviewer_agent_id"],"type":"object"},"DecideCommerceRequest":{"properties":{"approved_max_cents":{"format":"int64","minimum":0,"type":"integer"},"auto_renew":{"type":"boolean"},"expected_version":{"format":"int64","type":"integer"},"future_authority":{"$ref":"#/components/schemas/CommerceSpendLimitInput"},"reason":{"type":"string"}},"required":["expected_version"],"type":"object"},"DeleteCategoryResult":{"description":"The result of a soft-delete (the row + history survive as training data; D9).","properties":{"category_id":{"type":"string"},"merged_into":{"type":"string"},"status":{"example":"deleted","type":"string"}},"required":["status","category_id"],"type":"object"},"DeleteResult":{"description":"Outcome of a message or thread delete.","properties":{"count":{"description":"Number of messages affected (1 for a message; the thread size for a thread).","type":"integer"},"deleted":{"description":"Always true on success.","type":"boolean"},"expunged":{"description":"true when the message(s) were permanently removed; false when moved to Trash (a recoverable soft delete).\n","type":"boolean"},"id":{"description":"The message id or thread id that was deleted.","type":"string"}},"required":["id","deleted","expunged","count"],"type":"object"},"DeleteReviewLinkResult":{"description":"The delete outcome plus how many in-flight reviews were swept back to the human queue (no orphan deliveries; §9).\n","properties":{"deleted":{"type":"boolean"},"swept":{"description":"In-flight reviews returned to the human queue by the delete.","type":"integer"}},"required":["deleted","swept"],"type":"object"},"DomainList":{"properties":{"domains":{"items":{"$ref":"#/components/schemas/DomainSummary"},"type":"array"},"next_page":{"type":"string"}},"type":"object"},"DomainQuote":{"properties":{"available":{"type":"boolean"},"blockers":{"items":{"$ref":"#/components/schemas/CommerceBlocker"},"type":"array"},"currency":{"example":"usd","type":"string"},"domain":{"type":"string"},"object":{"enum":["domain_quote"],"type":"string"},"premium":{"type":"boolean"},"quote_cents":{"format":"int64","type":"integer"},"quote_expires_at":{"format":"date-time","type":"string"},"renewal_cents":{"format":"int64","type":"integer"},"required_plan":{"enum":["developer","startup","enterprise"],"type":"string"},"required_plan_price_cents":{"description":"Maximum monthly price for the required plan; any actual immediate plan charge is prorated and must not exceed this amount.","format":"int64","type":"integer"}},"required":["object","domain","available","currency","quote_cents","renewal_cents","premium","quote_expires_at","blockers"],"type":"object"},"DomainQuoteRequest":{"properties":{"domain":{"example":"example.com","type":"string"}},"required":["domain"],"type":"object"},"DomainSummary":{"properties":{"dkim_status":{"type":"string"},"domain":{"type":"string"},"id":{"type":"string"},"mode":{"type":"string"},"provisioning_error":{"type":"string"},"provisioning_phase":{"type":"string"},"shared":{"description":"True for the hosted inbox domain included with the current plan.","type":"boolean"},"verification_status":{"type":"string"}},"type":"object"},"EffectiveRiskDial":{"description":"The RESOLVED risk dial for a category: the account default with any per- category override applied (null override = inherit; D12). Every field is a concrete value already in force.\n","properties":{"auto_send_cap_per_day":{"type":"integer"},"canary_rate":{"format":"double","type":"number"},"drift_demote_after":{"type":"integer"},"first_contact_gate":{"type":"boolean"},"graduate_min_age_hours":{"type":"integer"},"graduate_min_approvals":{"type":"integer"},"min_confidence":{"format":"double","type":"number"}},"required":["min_confidence","first_contact_gate","drift_demote_after","canary_rate","graduate_min_approvals","graduate_min_age_hours","auto_send_cap_per_day"],"type":"object"},"EmailAddress":{"description":"A structured RFC5322 address.","properties":{"email":{"example":"support@acme.test","format":"email","type":"string"},"name":{"example":"Acme Support","type":"string"}},"required":["email"],"type":"object"},"EnrollRequest":{"properties":{"agent_handle":{"description":"Idempotency key for the agent identity.","type":"string"},"agent_name":{"type":"string"},"client_id":{"description":"Optional idempotency key (alias for the `Idempotency-Key` header). A retry with the same key replays the original enrollment response.\n","type":"string"},"token":{"example":"pk_enroll_\u003cid\u003e_\u003csecret\u003e","type":"string"}},"required":["token"],"type":"object"},"EnrollResult":{"properties":{"agent_id":{"type":"string"},"agent_key":{"description":"pk_agent_..., shown once.","type":"string"},"org_id":{"description":"The fixed org the new key is bound to (the token's resolved org).","type":"string"},"project_id":{"description":"The fixed project the new key is bound to (the token's resolved project); the agent cannot change it.","type":"string"},"scopes":{"items":{"type":"string"},"type":"array"}},"type":"object"},"EnrollmentTokenList":{"properties":{"next_page":{"type":"string"},"tokens":{"items":{"$ref":"#/components/schemas/EnrollmentTokenSummary"},"type":"array"}},"type":"object"},"EnrollmentTokenSummary":{"properties":{"created_at":{"format":"date-time","type":"string"},"daily_send_limit":{"type":"integer"},"id":{"type":"string"},"label":{"type":"string"},"max_mailboxes":{"type":"integer"},"prefix":{"type":"string"},"reusable":{"type":"boolean"},"revoked":{"type":"boolean"},"scopes":{"items":{"type":"string"},"type":"array"},"used_count":{"type":"integer"}},"type":"object"},"Error":{"description":"The canonical error envelope. `error` is a stable machine code.","properties":{"error":{"description":"Stable error code (e.g. `unauthorized`, `forbidden`, `not_found`, `invalid`, `quota_exceeded`, `rate_limited`).","example":"forbidden","type":"string"},"message":{"description":"Human-readable detail (never leaks internals).","example":"missing required scope","type":"string"}},"required":["error"],"type":"object"},"ExtractedCredentials":{"description":"OTP code / verification link extracted from the matched message.","properties":{"link":{"nullable":true,"type":"string"},"otp":{"nullable":true,"type":"string"}},"type":"object"},"ForwardRequest":{"properties":{"bcc":{"description":"Blind recipients on the forward. Never rendered as a header.","items":{"format":"email","type":"string"},"type":"array"},"category_confidence":{"description":"Agent-supplied confidence (0..1) in the category match (see SendRequest.category_confidence).\n","format":"float","maximum":1,"minimum":0,"type":"number"},"category_id":{"description":"Opaque category id (cat_…) matched from the registry.","type":"string"},"cc":{"description":"Additional recipients on the forward. Screened by the same pre-flight as `to`.","items":{"format":"email","type":"string"},"type":"array"},"composition_token":{"description":"Opaque token from a fresh, unfiltered GET /v1/rules for this agent, project, and category.","type":"string"},"html":{"description":"Accepted and IGNORED. The forwarded content is a plain-text quote of the parent message; emitting an HTML alternative would show HTML-capable clients the note WITHOUT the forwarded thread.\n","type":"string"},"idempotency_key":{"deprecated":true,"description":"DEPRECATED body-level alias for the `Idempotency-Key` header (see SendRequest.idempotency_key). Send the header instead.\n","type":"string"},"intent":{"$ref":"#/components/schemas/ReviewIntent"},"mode":{"description":"Review Loop per-send assertion (see SendRequest.mode). A forward is an outbound message to arbitrary NEW recipients that quotes an inbound thread, so it is governed by the same review policy as send.\n","enum":["review","direct"],"type":"string"},"text":{"description":"Optional note prepended to the forwarded content.","type":"string"},"to":{"items":{"format":"email","type":"string"},"minItems":1,"type":"array"}},"required":["to"],"type":"object"},"GraduateCategoryRequest":{"description":"Graduate a category ONE rung up to to_state (console plane, D16).","properties":{"to_state":{"enum":["auto_notify","auto_silent"],"type":"string"}},"required":["to_state"],"type":"object"},"GraduationStatus":{"description":"The graduation gate status toward the NEXT rung (Review Loop, D16). Reports clean approvals (N / needed), category age, the maturity gate (auto_silent precondition), the drift counter vs K, and whether a human graduate would succeed right now (can_graduate). Read-only; agents propose but never flip the bit.\n","properties":{"age_hours":{"format":"double","type":"number"},"age_met":{"type":"boolean"},"approvals_met":{"type":"boolean"},"can_graduate":{"type":"boolean"},"category_id":{"type":"string"},"clean_approval_count":{"type":"integer"},"drift_count":{"type":"integer"},"drift_demote_after":{"type":"integer"},"graduate_min_age_hours":{"type":"integer"},"graduate_min_approvals":{"type":"integer"},"maturity_gate_met":{"type":"boolean"},"never_graduate":{"description":"Pinned at supervised (high-stakes lock).","type":"boolean"},"next_state":{"description":"The rung a graduate would move to (empty if none).","type":"string"},"state":{"enum":["supervised","auto_notify","auto_silent"],"type":"string"}},"required":["category_id","state","next_state","never_graduate","clean_approval_count","graduate_min_approvals","approvals_met","age_hours","graduate_min_age_hours","age_met","maturity_gate_met","drift_count","drift_demote_after","can_graduate"],"type":"object"},"Inbox":{"description":"An inbox. `id` is the canonical opaque inbox id and the path key (`/v1/inboxes/{inbox_id}`); treat it as an opaque string. `address` is the within-project email alias. Every redesign resource carries `object`, `org_id`, `project_id`, and timestamps (RFC D9). `password` is returned only on an explicitly requested, paid create response whose key has `mailbox:credentials`; list/get responses omit it.\n","properties":{"address":{"example":"support@extrovertmail.com","type":"string"},"agent_id":{"example":"agent_3kP9wQ","type":"string"},"created_at":{"format":"date-time","type":"string"},"daily_send_limit":{"description":"Effective rolling-24h recipient cap enforced for this inbox.","maximum":10000,"minimum":1,"type":"integer"},"direct_smtp_enabled":{"description":"Whether this inbox is configured for direct SMTP submission outside the review pipeline. It is disabled by default, read-only for agents, and can be enabled only by a human administrator for an account with an active paid entitlement. The stored toggle does not grant access after that paid entitlement ends.\n","readOnly":true,"type":"boolean"},"display_name":{"example":"Support Bot","type":"string"},"effective_review_policy":{"description":"The RESOLVED review policy for this inbox: the per-inbox override, else the account default, else the `require_review` floor. Read it once before your first send: under `require_review` a send/reply/forward WITHOUT an `intent` is rejected 422 `intent_required` (nothing sent, nothing queued), and one WITH an intent is queued for a human (202 `queued_for_review`). Present on the single-inbox GET only; the list response omits it.\n","enum":["require_review","allow_direct","auto_send_graduated"],"type":"string"},"id":{"description":"Opaque inbox id (the path key). Treat as opaque.","example":"pmbx_8f3c2a1b","type":"string"},"imap_host":{"type":"string"},"imap_port":{"example":993,"type":"integer"},"metadata":{"additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]},"description":"Arbitrary key-value metadata stored on the inbox (AgentMail parity). Always an object; `{}` when none is set, never null. Values are string, number, or boolean. Project-scoped: an agent key can only read or mutate metadata for inboxes in its bound project.\n","type":"object"},"object":{"enum":["inbox"],"type":"string"},"org_id":{"example":"org_1f2e","type":"string"},"password":{"description":"Mailbox login. Present only on the create response; never persisted in the clear.","type":"string"},"project_id":{"example":"prj_9a8b","type":"string"},"smtp_host":{"type":"string"},"smtp_port":{"example":587,"type":"integer"},"webhook_url":{"description":"Inbound webhook registered for this inbox","if any.":null,"type":"string"}},"type":"object"},"InboxCredentials":{"description":"Full IMAP/SMTP connection config and login for an owned inbox. Export requires a paid plan plus `mailbox:credentials`. IMAP remains usable after export, but SMTP submission is rejected unless a human has separately enabled the inbox's paid-only `direct_smtp_enabled` bypass.\n","properties":{"address":{"example":"support@extrovertmail.com","type":"string"},"imap":{"$ref":"#/components/schemas/Connection"},"password":{"type":"string"},"smtp":{"$ref":"#/components/schemas/Connection"},"username":{"description":"Equals the address.","type":"string"}},"type":"object"},"InboxReviewPolicy":{"description":"The per-inbox review-policy override view after a set/clear: the raw override (empty = inherit), the account default it inherits from, and the resolved effective policy for this inbox (override-or-account-or-floor; D6).\n","properties":{"account":{"enum":["require_review","allow_direct","auto_send_graduated"],"type":"string"},"address":{"type":"string"},"effective":{"enum":["require_review","allow_direct","auto_send_graduated"],"type":"string"},"override":{"description":"Per-inbox override; empty = inherit the account default.","type":"string"}},"required":["address","override","account","effective"],"type":"object"},"InboxReviewPolicyRequest":{"description":"Set the per-inbox override (a non-null policy) or clear it back to inherit the account default (explicit JSON null; D6).\n","properties":{"policy":{"description":"A value SETS the override; explicit null CLEARS it (= inherit).","enum":["require_review","allow_direct","auto_send_graduated"],"nullable":true,"type":"string"}},"type":"object"},"IssueAgentKeyRequest":{"properties":{"agent_id":{"type":"string"},"expires_in_hours":{"minimum":0,"type":"integer"},"scopes":{"items":{"type":"string"},"type":"array"}},"required":["agent_id","scopes"],"type":"object"},"IssueAgentKeyResult":{"properties":{"agent_handle":{"type":"string"},"agent_id":{"type":"string"},"agent_name":{"type":"string"},"ceiling_inbox_id":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"enrollment_token_id":{"type":"string"},"expires_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"key":{"description":"Raw agent API key","shown once.":null,"type":"string"},"key_tier":{"enum":["org","project","inbox"],"type":"string"},"prefix":{"type":"string"},"scopes":{"items":{"type":"string"},"type":"array"}},"type":"object"},"IssueEnrollmentTokenRequest":{"properties":{"allowed_domains":{"items":{"type":"string"},"type":"array"},"daily_send_limit":{"type":"integer"},"expires_in_hours":{"type":"integer"},"label":{"type":"string"},"max_mailboxes":{"type":"integer"},"reusable":{"type":"boolean"},"scopes":{"items":{"type":"string"},"type":"array"}},"type":"object"},"IssueEnrollmentTokenResult":{"properties":{"daily_send_limit":{"type":"integer"},"id":{"type":"string"},"max_mailboxes":{"type":"integer"},"prefix":{"type":"string"},"scopes":{"items":{"type":"string"},"type":"array"},"token":{"description":"Raw enrollment token","shown once.":null,"type":"string"}},"type":"object"},"List":{"description":"The ONE collection envelope for every list response (redesign §5.2). `next_cursor` is an opaque pagination token (pass it back as `?cursor`); it is null when there are no more rows.\n","properties":{"data":{"items":{},"type":"array"},"has_more":{"type":"boolean"},"next_cursor":{"nullable":true,"type":"string"},"object":{"enum":["list"],"type":"string"}},"required":["object","data","has_more"],"type":"object"},"MailboxQuickstart":{"description":"MCP-first, read-only next calls for the verified signup inbox. Use these instead of inventing REST routes or parsing raw HTTP response files.\n","properties":{"inbox":{"format":"email","type":"string"},"list_mail":{"$ref":"#/components/schemas/MailboxQuickstartCall"},"read_message":{"$ref":"#/components/schemas/MailboxQuickstartCall"},"wait_for_mail":{"$ref":"#/components/schemas/MailboxQuickstartCall"}},"required":["inbox","list_mail","read_message","wait_for_mail"],"type":"object"},"MailboxQuickstartCall":{"description":"A copy-ready MCP tool call for ordinary mailbox use.","properties":{"arguments":{"additionalProperties":true,"type":"object"},"tool":{"enum":["read_messages","get_message","wait_for_email"],"type":"string"}},"required":["tool","arguments"],"type":"object"},"MarkMessageRequest":{"properties":{"read":{"description":"Set the native IMAP \\Seen flag (true = read, false = unread).","type":"boolean"}},"type":"object"},"MergeCategoryRequest":{"description":"Merge the path category (the loser) into into_category_id (the survivor), repointing all rr_/rule_ references by cat_ id in one transaction (D9/D10). A cross-tenant or unknown into_category_id is 404 (never a cross-customer merge).\n","properties":{"into_category_id":{"description":"The survivor category id (cat_…).","type":"string"}},"required":["into_category_id"],"type":"object"},"MergeCategoryResult":{"description":"The survivor category plus how many references were repointed by the merge.","properties":{"category":{"$ref":"#/components/schemas/Category"},"review_requests_repointed":{"type":"integer"},"writing_rules_repointed":{"type":"integer"}},"required":["category","review_requests_repointed","writing_rules_repointed"],"type":"object"},"Message":{"description":"The canonical message wire shape (agent plane).","properties":{"cc":{"items":{"$ref":"#/components/schemas/EmailAddress"},"type":"array"},"date":{"description":"Original Date header value.","type":"string"},"direction":{"description":"Derived relative to the owning inbox.","enum":["inbound","outbound"],"type":"string"},"extracted_html":{"description":"Best-effort derivative of html with common quoted-history containers removed; null when html is absent or no authored HTML remains. Not authoritative.","nullable":true,"type":"string"},"extracted_text":{"description":"Best-effort derivative of text with quoted history and signatures removed; null when text is absent or no authored text remains. Not authoritative.","nullable":true,"type":"string"},"folder":{"type":"string"},"from":{"$ref":"#/components/schemas/EmailAddress"},"html":{"description":"Decoded text/html MIME alternative; null for text-only mail. Never synthesized from plain text.","nullable":true,"type":"string"},"id":{"description":"Opaque","example":"msg_8Tz","inbox-resolvable id.":null,"type":"string"},"in_reply_to":{"description":"RFC5322 In-Reply-To header.","type":"string"},"inbox":{"example":"agent7@extrovertmail.com","type":"string"},"message_id":{"description":"RFC5322 Message-ID.","type":"string"},"references":{"description":"RFC5322 References header chain.","type":"string"},"reply_to":{"items":{"$ref":"#/components/schemas/EmailAddress"},"type":"array"},"seen":{"description":"Native IMAP \\Seen flag (read state).","type":"boolean"},"subject":{"type":"string"},"text":{"description":"Decoded UTF-8 text/plain MIME alternative; null when the message had no plain-text part. Never derived from HTML.","nullable":true,"type":"string"},"thread_id":{"example":"thr_9aB","type":"string"},"to":{"items":{"$ref":"#/components/schemas/EmailAddress"},"type":"array"}},"type":"object"},"MessagePage":{"description":"A paginated page of messages.","properties":{"items":{"items":{"$ref":"#/components/schemas/Message"},"type":"array"},"next_cursor":{"description":"Present when more results remain; pass the opaque value back as `cursor`.","type":"string"},"total":{"type":"integer"}},"type":"object"},"NeverGraduateRequest":{"description":"Set/clear the never-graduate lock on a category (console plane, D16).","properties":{"locked":{"description":"true pins at supervised (demoting first if graduated); false releases the pin.","type":"boolean"}},"required":["locked"],"type":"object"},"OnboardAgentDomainRequest":{"description":"Request body for the agent-facing `POST /v1/domains`. `ns_delegated` adds a domain the customer controls without spending. The legacy `purchased` input is accepted only as a compatibility shim and is converted to the human-controlled commerce request flow; it never approves, charges, or registers inline.\n","properties":{"domain":{"type":"string"},"mode":{"description":"Onboarding path. Defaults to ns_delegated. `purchased` is a deprecated compatibility input that creates a commerce request.","enum":["ns_delegated","purchased"],"type":"string"},"project_id":{"description":"Optional assertion that must match the key's bound project; NEVER a selector. A mismatch is 403. The binding is always derived from the key.\n","type":"string"},"scope":{"description":"Domain visibility. Defaults to `org` (org-shared, usable by every project in the org). `project` binds the domain to the key's OWN bound project (never client-selected) so it can create inboxes only in that project. A legacy/unscoped key (no bound project) falls back to `org`.\n","enum":["org","project"],"type":"string"}},"required":["domain"],"type":"object"},"OnboardDomainRequest":{"properties":{"domain":{"type":"string"},"mode":{"enum":["ns_delegated","purchased"],"type":"string"}},"required":["domain","mode"],"type":"object"},"OnboardDomainResult":{"properties":{"delegation_ns":{"items":{"$ref":"#/components/schemas/RecordInstruction"},"type":"array"},"domain":{"type":"string"},"instruction":{"type":"string"},"mode":{"enum":["shared","ns_delegated","manual","purchased"],"type":"string"},"provisioning_error":{"type":"string"},"provisioning_phase":{"type":"string"},"records":{"items":{"$ref":"#/components/schemas/RecordInstruction"},"type":"array"},"verification_status":{"type":"string"},"zone_id":{"type":"string"}},"type":"object"},"Org":{"description":"An Extrovert organization (the authority/billing boundary). org ids are plain server-created UUIDs (never client-supplied). A root org has a null parent_org_id; child orgs reference their parent.\n","properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"type":"string"},"display_name":{"type":"string"},"id":{"type":"string"},"lifecycle_status":{"enum":["active","archived","deleted"],"type":"string"},"max_child_orgs":{"type":"integer"},"max_projects":{"type":"integer"},"parent_org_id":{"nullable":true,"type":"string"},"plan_tier":{"type":"string"},"root_org_id":{"type":"string"},"slug":{"type":"string"},"updated_at":{"format":"date-time","type":"string"},"version":{"description":"Optimistic-CAS version.","type":"integer"}},"required":["id","customer_id","root_org_id","display_name","slug","lifecycle_status","plan_tier","max_child_orgs","max_projects","version","created_at","updated_at"],"type":"object"},"OrgInvitation":{"description":"An org invitation. `token` is the raw secret returned ONCE on a fresh create (empty when an existing pending invitation was reused, or on accept/revoke).\n","properties":{"created_at":{"format":"date-time","type":"string"},"email":{"type":"string"},"expires_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"org_id":{"type":"string"},"role":{"enum":["owner","admin","member","viewer","billing"],"type":"string"},"status":{"enum":["pending","accepted","revoked","expired"],"type":"string"},"token":{"description":"Raw invitation token; present only on a fresh create.","type":"string"},"token_prefix":{"type":"string"}},"required":["id","org_id","email","role","status","token_prefix","expires_at","created_at"],"type":"object"},"OrgList":{"properties":{"orgs":{"items":{"$ref":"#/components/schemas/Org"},"type":"array"}},"type":"object"},"OrgMember":{"description":"One org membership row.","properties":{"clerk_user_id":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"email":{"type":"string"},"role":{"enum":["owner","admin","member","viewer","billing"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["clerk_user_id","email","role","created_at","updated_at"],"type":"object"},"OrgMemberList":{"properties":{"members":{"items":{"$ref":"#/components/schemas/OrgMember"},"type":"array"}},"type":"object"},"OrgSettings":{"properties":{"default_domain":{"type":"string"},"default_mailbox_cap":{"type":"integer"},"default_onboarding_mode":{"type":"string"},"early_access":{"type":"boolean"},"org_name":{"type":"string"},"webhook_signing_prefix":{"type":"string"},"x402_mode":{"type":"string"}},"type":"object"},"OutboundRouteRetirement":{"description":"Provider-neutral progress for one old sending route being cleaned up after a switch. Infrastructure identifiers and snapshots are never exposed.\n","properties":{"created_at":{"format":"date-time","type":"string"},"decommission_due_at":{"description":"When the retiring stint's records may be pruned.","format":"date-time","type":"string"},"object":{"enum":["outbound_route_retirement"],"type":"string"},"status":{"enum":["cleanup_scheduled"],"type":"string"}},"required":["object","status","decommission_due_at","created_at"],"type":"object"},"OutboundRouteRetirementList":{"description":"The domain's retiring-sender ledger rows (list envelope).","properties":{"data":{"items":{"$ref":"#/components/schemas/OutboundRouteRetirement"},"type":"array"},"has_more":{"type":"boolean"},"next_cursor":{"nullable":true,"type":"string"},"object":{"enum":["list"],"type":"string"}},"required":["object","data"],"type":"object"},"OutboundRouteView":{"description":"A provider-neutral view of a domain's current outbound route. An unassigned domain has assigned=false and route_state \"unassigned\" (it routes direct by fail-safe).\n","properties":{"assigned":{"description":"True when a route row exists for the domain.","type":"boolean"},"domain":{"type":"string"},"object":{"enum":["outbound_route"],"type":"string"},"route_state":{"enum":["unassigned","provisioning","active","switching","deprovisioning","failed","paused"],"type":"string"},"status":{"enum":["pending","setting_up","ready","needs_attention"],"type":"string"},"switched_at":{"format":"date-time","type":"string"}},"required":["object","domain","assigned","status"],"type":"object"},"PacingItem":{"description":"One queued draft's pacing classification relative to the human review cursor + lookahead window (M7 Slice B/§8). $0-LLM (a cheap integer staleness compare).\n","properties":{"review_id":{"type":"string"},"state":{"description":"behind_cursor = the human has reviewed past it; in_window_fresh = in the freshness-guaranteed window and current-enough; in_window_redrafting = in the window but stale (a redraft is in flight; the console shows a shimmer); ahead = queued beyond the window, not yet freshness-guaranteed.\n","enum":["behind_cursor","in_window_fresh","in_window_redrafting","ahead"],"type":"string"}},"required":["review_id","state"],"type":"object"},"PatchOrgRequest":{"description":"Update an org's display fields. Plan/limit fields are not console-patchable in v1.","properties":{"display_name":{"type":"string"},"expected_version":{"description":"Optimistic-CAS version of the row being updated.","type":"integer"},"slug":{"type":"string"}},"type":"object"},"PatchOrgSettingsRequest":{"description":"Any subset of the org settings; omitted fields are unchanged.","properties":{"default_domain":{"type":"string"},"default_mailbox_cap":{"type":"integer"},"default_onboarding_mode":{"type":"string"},"early_access":{"type":"boolean"},"org_name":{"type":"string"},"webhook_signing_prefix":{"type":"string"},"x402_mode":{"type":"string"}},"type":"object"},"PatchProjectRequest":{"description":"Update a project's display fields.","properties":{"description":{"type":"string"},"expected_version":{"description":"Optimistic-CAS version of the row being updated.","type":"integer"},"name":{"type":"string"},"slug":{"type":"string"}},"type":"object"},"PendingSignupClaim":{"properties":{"created_at":{"format":"date-time","type":"string"},"expires_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"org_id":{"type":"string"},"role":{"enum":["owner"],"type":"string"}},"required":["id","org_id","role","created_at","expires_at"],"type":"object"},"PostReviewChatRequest":{"description":"A chat turn on a review's thread (M5). The agent posts an agent_question turn; if the draft is in_review it flips to chatting; a feedback_added nudge is enqueued to the OTHER party (the human reviewer, via the journal/console stream) and a review.chat event is emitted. Idempotent on the Idempotency-Key.\n","properties":{"text":{"description":"The agent's question/comment for the human reviewer.","type":"string"}},"required":["text"],"type":"object"},"Problem":{"description":"RFC-9457 problem+json error body. `code` is a closed machine enum clients switch on; `type` is a dereferenceable URI under https://extrovert.dev/problems/. Served as application/problem+json.\n","properties":{"code":{"description":"The CLOSED machine code. The Review Loop members split what used to be a single opaque `conflict`, because an agent must take a DIFFERENT action on each: `stale` (the revision/version you named is no longer current; nothing was mutated; re-read, re-apply, resubmit; retryable, bounded) and `born_stale` (built against an older rule high-water; re-read the rules or restamp_review; at most one retry per high-water) are the ONLY retryable 409s. `wrong_state` means this VERB is illegal from the current state while the draft is still live; never retry the same verb, read the `state` and the repeated `allowed_action` hints in `errors[]` and pick a legal one. `terminal` means the review is already sent/auto_sent/cancelled and nothing will EVER succeed; stop, and drain your review events for the outcome. `send_needs_reconciliation` means a prior send is unconfirmed and parked. Do not resend. Poll instead. `unavailable` (503) is the retryable fail-closed answer when a dependency could not be read; it carries `Retry-After` and is distinct from `not_configured`, which is permanent for this deployment.\n","enum":["bad_request","unauthorized","forbidden_scope","not_found","conflict","idempotency_conflict","breadth_required","quota_exceeded","rate_limited","domain_not_allowed","recipient_blocked","recipient_suppressed","not_configured","domain_unavailable","internal","intent_required","wrong_state","terminal","stale","born_stale","send_needs_reconciliation","graduation_locked","maturity_gate_unmet","scope_taken","unavailable"],"type":"string"},"detail":{"type":"string"},"errors":{"items":{"properties":{"code":{"type":"string"},"detail":{"type":"string"},"field":{"type":"string"}},"type":"object"},"type":"array"},"request_id":{"type":"string"},"status":{"type":"integer"},"title":{"type":"string"},"type":{"format":"uri","type":"string"}},"required":["type","title","status","code"],"type":"object"},"Project":{"description":"An Extrovert project (the resource namespace inside an org). project ids are plain server-created UUIDs (never client-supplied).\n","properties":{"created_at":{"format":"date-time","type":"string"},"customer_id":{"type":"string"},"description":{"type":"string"},"id":{"type":"string"},"is_default":{"type":"boolean"},"lifecycle_status":{"enum":["active","archived","deleted"],"type":"string"},"name":{"type":"string"},"org_id":{"type":"string"},"slug":{"type":"string"},"updated_at":{"format":"date-time","type":"string"},"version":{"description":"Optimistic-CAS version.","type":"integer"}},"required":["id","org_id","customer_id","name","slug","description","is_default","lifecycle_status","version","created_at","updated_at"],"type":"object"},"ProjectList":{"properties":{"projects":{"items":{"$ref":"#/components/schemas/Project"},"type":"array"}},"type":"object"},"PromoteRuleRequest":{"description":"Move a rule between the category and general/house-style layers (via a supersession).","properties":{"to_scope":{"enum":["general","category"],"type":"string"}},"required":["to_scope"],"type":"object"},"ProposeCategoryRequest":{"description":"Propose a new category on the fly (D9). It stands immediately (author_kind= agent, state supervised) and writes a create audit/undo row.\n","properties":{"description":{"description":"Skill-style matcher text the agent reads (mutable).","type":"string"},"name":{"description":"Display name (mutable metadata; never a reference key).","type":"string"},"scope":{"description":"Defaults to org_shared.","enum":["org_shared","agent_private"],"type":"string"}},"required":["name"],"type":"object"},"ProposeGraduationRequest":{"description":"Record an agent's request to graduate a category (D16/D6). evidence is an opaque agent-supplied object stored on the request transition for the human to review. It does NOT flip the bit.\n","properties":{"evidence":{"additionalProperties":true,"type":"object"}},"type":"object"},"PurchaseRequest":{"description":"x402 paid-purchase body. The buyer-supplied amount is never trusted; price is server-computed.","properties":{"display_name":{"type":"string"},"domain":{"type":"string"},"quantity":{"description":"Number of mailboxes to provision.","type":"integer"},"webhook_url":{"type":"string"}},"type":"object"},"PurchaseResult":{"properties":{"inboxes":{"items":{"$ref":"#/components/schemas/Inbox"},"type":"array"},"payment_id":{"type":"string"},"settlement_ref":{"type":"string"}},"type":"object"},"QueuedForReviewResult":{"description":"A Review Loop submit that was parked for human review.","properties":{"kind":{"enum":["queued_for_review"],"type":"string"},"review":{"properties":{"effective_mode":{"description":"The mode after the policy resolved the agent's assertion.","enum":["review","direct"],"type":"string"},"id":{"description":"Opaque review id (rr_…).","type":"string"},"state":{"description":"Current review state (e.g. needs_review).","type":"string"}},"required":["id","state"],"type":"object"}},"required":["kind","review"],"type":"object"},"RealtimeTicket":{"description":"A short-lived, single-use ticket the console creates (under its Clerk session) to open the live Approvals SSE stream; EventSource cannot set an Authorization header, so the customer scope is carried by this opaque ticket in the stream's `ticket` query parameter. Bound to the session's customer at create time, consumed on first stream connect, and self-expiring (~60s).\n","properties":{"expires_at":{"format":"date-time","type":"string"},"ticket":{"description":"Opaque single-use ticket (`rtk_…`).","type":"string"}},"required":["ticket","expires_at"],"type":"object"},"ReconcileMessageOutcome":{"description":"One per-message reconciliation outcome (D19); WHY a queued draft released or was held. verdict is the integer-compare result; released is true only when a current-enough draft also passed the M6 gate; a stale draft is NEVER released as-is.\n","properties":{"composed_category_rules_version":{"type":"integer"},"composed_house_style_version":{"type":"integer"},"current_category_rules_version":{"type":"integer"},"current_house_style_version":{"type":"integer"},"gate_outcome":{"description":"The M6 gate decision for a current-enough draft (auto_silent|auto_notify, or held:\u003creason\u003e).","type":"string"},"held_reason":{"description":"The held token when a gate diverted a current-enough draft.","type":"string"},"nudged":{"description":"Whether a reprocess nudge was enqueued (redraft a stale draft, or re-submit a releasable one).","type":"boolean"},"released":{"type":"boolean"},"review_id":{"type":"string"},"verdict":{"enum":["current_enough","stale"],"type":"string"}},"required":["review_id","verdict","released","composed_category_rules_version","composed_house_style_version","current_category_rules_version","current_house_style_version","nudged"],"type":"object"},"ReconcileResult":{"description":"The D19/§8 reconciliation sweep summary (console scan-backlog / graduate / rule-change). Records every per-message decision so the human never hand-touches the backlog and no stale draft slips out. Deterministic, $0-LLM.\n","properties":{"category_id":{"type":"string"},"current_category_rules_version":{"type":"integer"},"current_house_style_version":{"type":"integer"},"held_by_gate":{"description":"Current-enough drafts that a M6 gate diverted (transient re-supervision).","type":"integer"},"outcomes":{"items":{"$ref":"#/components/schemas/ReconcileMessageOutcome"},"type":"array"},"released":{"description":"Current-enough drafts released through the M6 gate (re-submit).","type":"integer"},"scanned":{"type":"integer"},"stale":{"description":"Stale drafts nudged to redraft against current rules (held, not released).","type":"integer"},"staleness_tolerance":{"type":"integer"},"trigger":{"description":"What kicked off the sweep.","enum":["graduate","rule_change","scan_backlog"],"type":"string"}},"required":["category_id","trigger","scanned","released","stale","held_by_gate","current_category_rules_version","current_house_style_version","staleness_tolerance","outcomes"],"type":"object"},"RecordInstruction":{"description":"A DNS record the customer must add for domain onboarding.","properties":{"name":{"type":"string"},"priority":{"nullable":true,"type":"integer"},"ttl":{"type":"integer"},"type":{"example":"TXT","type":"string"},"value":{"type":"string"}},"type":"object"},"RegisterWebhookRequest":{"properties":{"address":{"description":"Legacy alias for `inbox`.","type":"string"},"client_id":{"description":"Optional idempotency key (alias for the `Idempotency-Key` header). A retry with the same key replays the original webhook registration.\n","type":"string"},"event_types":{"description":"AgentMail-compatible alias for `events`.","items":{"enum":["message.received"],"example":"message.received","type":"string"},"type":"array"},"events":{"items":{"enum":["message.received"],"example":"message.received","type":"string"},"type":"array"},"inbox":{"description":"Scope to one mailbox; omit for all.","type":"string"},"url":{"format":"uri","type":"string"}},"required":["url"],"type":"object"},"ReplyRequest":{"description":"Thread-aware reply. Exactly one of `thread_id` / `message_id` selects the parent; recipients, subject, and threading headers are derived server-side.\n","oneOf":[{"required":["thread_id"]},{"required":["message_id"]}],"properties":{"attachments":{"items":{"$ref":"#/components/schemas/AttachmentInput"},"type":"array"},"bcc":{"items":{"format":"email","type":"string"},"type":"array"},"category_confidence":{"description":"Agent-supplied confidence (0..1) in the category match (see SendRequest.category_confidence). Feeds the min_confidence auto-send gate only; the server never scores.\n","format":"float","maximum":1,"minimum":0,"type":"number"},"category_id":{"description":"Opaque category id (cat_…) matched from the registry.","type":"string"},"cc":{"items":{"format":"email","type":"string"},"type":"array"},"composition_token":{"description":"Opaque token from a fresh, unfiltered GET /v1/rules for this agent, project, and category.","type":"string"},"expected_last_message_id":{"description":"Optional stale-context guard; returns 409 if the thread head changed before request materialization.","type":"string"},"headers":{"additionalProperties":{"type":"string"},"type":"object"},"html":{"type":"string"},"idempotency_key":{"deprecated":true,"description":"DEPRECATED body-level alias for the `Idempotency-Key` header (see SendRequest.idempotency_key). Send the header instead.\n","type":"string"},"intent":{"$ref":"#/components/schemas/ReviewIntent"},"message_id":{"type":"string"},"mode":{"description":"Review Loop per-send assertion (see SendRequest.mode).","enum":["review","direct"],"type":"string"},"reply_all":{"description":"Include all original recipients (reply-all) when true.","type":"boolean"},"reply_to":{"type":"string"},"text":{"type":"string"},"thread_id":{"type":"string"}},"type":"object"},"ReputationFinding":{"description":"One deliverability finding (internal status/severity/type; raw provider vocabulary is not exposed).","properties":{"detail":{"type":"string"},"domain":{"type":"string"},"first_seen_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"last_seen_at":{"format":"date-time","type":"string"},"resolved_at":{"format":"date-time","type":"string"},"sender":{"type":"string"},"severity":{"enum":["low","high","unknown"],"type":"string"},"status":{"enum":["open","resolved"],"type":"string"},"title":{"type":"string"},"type":{"description":"bounce/complaint/feedback_3p/ip_listing/dkim/dmarc/spf/bimi/suppression/account_health/unknown.","type":"string"}},"required":["id","type","severity","status","title","detail","first_seen_at","last_seen_at"],"type":"object"},"ReputationFindingsPage":{"description":"The paged list of the org's deliverability findings (newest-first).","properties":{"items":{"items":{"$ref":"#/components/schemas/ReputationFinding"},"type":"array"},"next_cursor":{"description":"Opaque cursor for the next page; absent on the last page.","type":"string"},"total":{"type":"integer"}},"required":["items","total"],"type":"object"},"ReputationMetrics":{"description":"The latest window's Sends/Bounces/Complaints rollup for the org.","properties":{"bounce_rate":{"type":"number"},"bounces":{"type":"integer"},"complaint_rate":{"type":"number"},"complaints":{"type":"integer"},"sends":{"type":"integer"},"window_end":{"format":"date-time","type":"string"},"window_start":{"format":"date-time","type":"string"}},"required":["sends","bounces","complaints","bounce_rate","complaint_rate"],"type":"object"},"ReputationRollup":{"description":"The org's provider-neutral deliverability rollup: derived status badge, sending readiness, the latest metrics window, and open-finding count.\n","properties":{"configured":{"description":"Whether outbound sending infrastructure is configured.","type":"boolean"},"last_checked_at":{"format":"date-time","type":"string"},"metrics":{"$ref":"#/components/schemas/ReputationMetrics"},"object":{"enum":["reputation"],"type":"string"},"open_findings":{"description":"Count of open findings for the org.","type":"integer"},"org_id":{"type":"string"},"sending_status":{"description":"The org's effective sending status.","type":"string"},"status":{"description":"UI badge: healthy/at_risk/paused/enforced/unknown.","type":"string"}},"required":["object","org_id","status","sending_status","configured","metrics","open_findings"],"type":"object"},"RestampReviewRequest":{"description":"The D19/§8 re-stamp-without-redraft escape valve ($0). The agent asserts it reviewed the draft against rules `against_version` and no change is needed; the server advances the draft's composed_* rules-versions WITHOUT a new draft. The optional house_style_version re-stamps the house-style axis too. against_version must not exceed the category's current rules-version (a re-stamp can never claim a version that does not exist yet).\n","properties":{"against_version":{"description":"The category rules-version the agent reviewed against (≤ the category's current rules-version).","type":"integer"},"house_style_version":{"description":"Optional: re-stamp the house-style axis to this version (≤ the org's current house_style_version).","type":"integer"}},"required":["against_version"],"type":"object"},"Review":{"description":"A review request (rr_…); the server-owned pre-send record of a message under the Review Loop. Carries intent, the current proposed draft, category, state machine fields, and (once sent) the sent body + diff.\n","properties":{"agent_id":{"type":"string"},"category_id":{"type":"string"},"closed":{"description":"True once this review will never move again; `sent`, `auto_sent`, `cancelled` OR `failed`. It is the definitive per-review \"am I done?\" answer and the poll-side companion to the terminal review events; use it after a restart when your event cursor is gone. `failed` is included deliberately: nothing re-approves a failed review, so treating it as open means waiting forever.\n","type":"boolean"},"created_at":{"format":"date-time","type":"string"},"decided_at":{"format":"date-time","type":"string"},"decision_feedback":{"type":"string"},"diff_unified":{"type":"string"},"effective_mode":{"enum":["review","direct"],"type":"string"},"from_address":{"type":"string"},"gate_outcome":{"type":"string"},"id":{"type":"string"},"intent_meta":{"additionalProperties":true,"type":"object"},"intent_summary":{"type":"string"},"kind":{"enum":["send","reply","forward"],"type":"string"},"mode":{"enum":["review","direct"],"type":"string"},"proposed_bcc":{"items":{"type":"string"},"type":"array"},"proposed_body_html":{"type":"string"},"proposed_body_text":{"type":"string"},"proposed_cc":{"items":{"type":"string"},"type":"array"},"proposed_subject":{"type":"string"},"proposed_to":{"items":{"type":"string"},"type":"array"},"revision":{"type":"integer"},"send_error":{"description":"Vendor-scrubbed delivery failure, present on a failed review.","type":"string"},"send_path":{"description":"How the message was released, once sent.","enum":["human_reviewed","reviewer_approved","graduated_auto","agent_direct"],"type":"string"},"sent_at":{"format":"date-time","type":"string"},"sent_body_text":{"type":"string"},"sent_message_id":{"type":"string"},"sent_subject":{"type":"string"},"stale_reason":{"type":"string"},"state":{"enum":["needs_review","in_review","chatting","stale","approved","sent","auto_sent","rejected","stalled","cancelled","failed"],"type":"string"},"updated_at":{"format":"date-time","type":"string"},"version":{"type":"integer"}},"required":["id","state","mode","effective_mode","kind","revision","version"],"type":"object"},"ReviewDecisionContext":{"description":"The reviewer's read-only decision surface for a review (D5; §9): the intent + current draft + thread + the two-circuit-breaker budget. force_to_human is true when EITHER breaker has tripped (hop_count ≥ max_hops, or the hard review_deadline); the reviewer's next reject would be FORCED to the human regardless of intent (the human is the only terminal authority, D17).\n","properties":{"deadline_passed":{"description":"Breaker (b) tripped: now ≥ review_deadline.","type":"boolean"},"force_reason":{"description":"The tripped breaker (max_hops_reached | review_deadline_passed).","type":"string"},"force_to_human":{"description":"Either breaker tripped: a reject is overridden to a human escalation.","type":"boolean"},"hop_count":{"description":"Circuit breaker (a): reviewer hand-backs so far.","type":"integer"},"hops_exhausted":{"description":"Breaker (a) tripped: hop_count ≥ max_hops.","type":"boolean"},"max_hops":{"description":"Circuit breaker (a): the ceiling; at hop_count ≥ max_hops the next action is forced to the human.","type":"integer"},"review":{"$ref":"#/components/schemas/Review"},"review_deadline":{"description":"Circuit breaker (b): the hard per-review wall-clock deadline (created_at + review_deadline_s).","format":"date-time","type":"string"},"turns":{"items":{"$ref":"#/components/schemas/ReviewTurn"},"type":"array"}},"required":["review","turns","hop_count","max_hops","review_deadline","deadline_passed","hops_exhausted","force_to_human"],"type":"object"},"ReviewEvent":{"description":"One durable review nudge (ndg_…) as drained from the authoritative liveness queue (spec §11). seq is the per-review monotonic ordinal the ack cursor advances against (0 for a broadcast nudge). Opaque typed ids only (D10).\n","properties":{"category_id":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"payload":{"additionalProperties":true,"type":"object"},"reason":{"description":"The work-item kind. sent / send_failed / cancelled are TERMINAL: the LAST event a review ever produces is one of these; ack it and stop polling that review. (Almost every review emits exactly one; a failed send the agent then closes out emits send_failed and then cancelled.) `sent` covers both delivery flavors; payload.state distinguishes sent from auto_sent. `approved` and `staleness` are RESERVED and never emitted (kept so the enum is never narrowed). Treat an unrecognized reason as ack-and-ignore: this enum is additive across 0.x releases.\n","enum":["redraft_requested","feedback_added","recheck_category","staleness","approved","rejected","front_run_next","rule_changed","propagate_general_rule","sent","send_failed","cancelled"],"type":"string"},"review_id":{"type":"string"},"seq":{"type":"integer"}},"required":["seq","id","reason","created_at"],"type":"object"},"ReviewEventCursor":{"description":"The agent's per-(agent, review) ack frontier; its strict-FIFO position for one review.","properties":{"last_acked_seq":{"type":"integer"},"review_id":{"type":"string"}},"required":["review_id","last_acked_seq"],"type":"object"},"ReviewEventsResponse":{"description":"The drain result for list_review_events / wait_for_review_event; un-acked events in FIFO seq order plus the per-review cursors.","properties":{"cursors":{"items":{"$ref":"#/components/schemas/ReviewEventCursor"},"type":"array"},"events":{"items":{"$ref":"#/components/schemas/ReviewEvent"},"type":"array"}},"required":["events"],"type":"object"},"ReviewFeedback":{"description":"The human's assembled feedback for a review (spec §11): the unified + structured diff of the human's edit, the human comments/rejection feedback, the decision, and the rules born from this review (rule_ ids whose source_review_id is this review). Read-only; $0 LLM (pure assembly over stored turns/rules).\n","properties":{"comments":{"items":{"$ref":"#/components/schemas/ReviewFeedbackComment"},"type":"array"},"decision":{"description":"edited | approved | rejected | \u003clive state\u003e.","type":"string"},"diff_json":{"additionalProperties":true,"type":"object"},"diff_unified":{"type":"string"},"new_rules":{"description":"rule_ ids whose provenance points at this review (M4 source_review_id).","items":{"type":"string"},"type":"array"},"review_id":{"type":"string"}},"required":["review_id","decision","comments","new_rules"],"type":"object"},"ReviewFeedbackComment":{"description":"One human/agent comment in the assembled review feedback (spec §11).","properties":{"actor_id":{"type":"string"},"actor_kind":{"enum":["agent","human","review_agent","system"],"type":"string"},"body":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"turn_id":{"type":"string"}},"required":["turn_id","actor_kind","body","created_at"],"type":"object"},"ReviewIntent":{"description":"The agent's \"for the human reviewer\" summary. `summary` is REQUIRED when the resolved mode is review (else the submit is 422).\n","properties":{"meta":{"description":"Structured intent payload.","properties":{"goal":{"type":"string"},"prior_touches":{"type":"integer"},"recipient":{"type":"string"},"urgency":{"type":"string"}},"type":"object"},"summary":{"description":"Free-text intent summary (who/what/why).","type":"string"}},"type":"object"},"ReviewLink":{"description":"A BYO review-agent link (rvl_…); the subscription that routes a reviewed draft to a linked review-agent (D5; §9). One link per scope: inbox_address set = that inbox, empty = account-wide (per-inbox overrides account-wide). The reviewer holds review:act, NEVER mailbox:send; on approve/edit the platform sends with the COMPOSER's creds (credential boundary). hmac_secret is write-only; reads return has_secret only. Opaque ids only (D10).\n","properties":{"active":{"type":"boolean"},"consec_failures":{"description":"Consecutive delivery failures; an unhealthy link is skipped by routing until recovery.","type":"integer"},"created_at":{"format":"date-time","type":"string"},"escalate_after_s":{"description":"Seconds before the reviewer-liveness sweeper auto-escalates to the human (default 300).","type":"integer"},"has_secret":{"description":"Whether an hmac signing secret is configured (the secret itself is never echoed).","type":"boolean"},"id":{"description":"Opaque review-link id (rvl_…).","type":"string"},"inbox_address":{"description":"Scope: a specific inbox; empty = account-wide.","type":"string"},"max_hops":{"description":"Circuit breaker: max reviewer hand-backs before the next action is forced to the human (default 3).","type":"integer"},"review_deadline_s":{"description":"Circuit breaker: hard per-review deadline in seconds (default 86400).","type":"integer"},"reviewer_agent_id":{"description":"The linked reviewer agent (agt_…).","type":"string"},"transport":{"enum":["webhook","sse","websocket"],"type":"string"},"updated_at":{"format":"date-time","type":"string"},"webhook_url":{"description":"Delivery URL (webhook transport only).","type":"string"}},"required":["id","reviewer_agent_id","transport","escalate_after_s","max_hops","review_deadline_s","active","consec_failures","has_secret","created_at","updated_at"],"type":"object"},"ReviewLinkList":{"properties":{"review_links":{"items":{"$ref":"#/components/schemas/ReviewLink"},"type":"array"}},"required":["review_links"],"type":"object"},"ReviewPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Review"},"type":"array"},"next_cursor":{"type":"string"},"total":{"type":"integer"}},"required":["items","total"],"type":"object"},"ReviewPolicy":{"description":"The account-default review policy (D6) plus the effective floor an inbox with no override resolves to (require_review is the safe floor).\n","properties":{"effective":{"enum":["require_review","allow_direct","auto_send_graduated"],"type":"string"},"policy":{"enum":["require_review","allow_direct","auto_send_graduated"],"type":"string"}},"required":["policy","effective"],"type":"object"},"ReviewPolicyRequest":{"description":"Set the account-default review policy (D6). An invalid value is 400.","properties":{"policy":{"enum":["require_review","allow_direct","auto_send_graduated"],"type":"string"}},"required":["policy"],"type":"object"},"ReviewTurn":{"description":"One immutable turn in a review's append-only thread (turn_…).","properties":{"actor_id":{"type":"string"},"actor_kind":{"enum":["agent","human","review_agent","system"],"type":"string"},"body":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"diff_json":{"additionalProperties":true,"type":"object"},"id":{"type":"string"},"metadata":{"additionalProperties":true,"type":"object"},"revision":{"type":"integer"},"seq":{"type":"integer"},"turn_type":{"enum":["agent_draft","agent_question","agent_note","human_comment","human_question","human_edit","human_approve","human_reject","human_reconfirm","system_diff","state_change","nudge"],"type":"string"}},"required":["id","seq","turn_type","actor_kind","created_at"],"type":"object"},"ReviewTurnPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ReviewTurn"},"type":"array"},"total":{"type":"integer"}},"required":["items","total"],"type":"object"},"ReviewerDecisionRequest":{"description":"A reviewer decision. action is approve|edit|reject|escalate. revision + version are the optimistic CAS (a mismatch is 409 STALE with NO mutation; the human always wins, D17). subject/body carry the edited content for the edit action. feedback is the reviewer's note (reject: the rule-birth signal; escalate: the human-facing escalation reason).\n","properties":{"action":{"enum":["approve","edit","reject","escalate"],"type":"string"},"body":{"description":"Edited body text (edit action).","type":"string"},"feedback":{"description":"Reviewer note (reject: rule-birth signal; escalate: human-facing reason).","type":"string"},"revision":{"description":"The revision you decided against (PRIMARY CAS).","type":"integer"},"subject":{"description":"Edited subject (edit action).","type":"string"},"version":{"description":"Optional row-version CAS (defense in depth).","type":"integer"}},"required":["action","revision"],"type":"object"},"ReviewerDecisionResult":{"description":"The reviewer-decision outcome. kind=sent when the platform sent with the COMPOSER's creds (approve/edit); kind=sent_to_human when the draft returned to the human queue (reject/escalate, or a reject forced to the human by a circuit breaker). forced_by_breaker names the tripped breaker when one overrode the intent.\n","properties":{"forced_by_breaker":{"description":"The tripped circuit breaker (max_hops_reached | review_deadline_passed) when one forced the human.","type":"string"},"kind":{"enum":["sent","sent_to_human"],"type":"string"},"message_id":{"description":"The delivered message id when sent.","type":"string"},"review":{"$ref":"#/components/schemas/Review"},"sent":{"description":"True iff the platform sent with the composer's creds.","type":"boolean"},"sent_to_human":{"description":"True iff the draft returned to the human queue.","type":"boolean"},"thread_id":{"description":"The thread id when sent on the reply path.","type":"string"}},"required":["kind","review","sent","sent_to_human"],"type":"object"},"RevokeSuppressionRequest":{"description":"Revoke (un-suppress) one org-scope row. The reason is REQUIRED and audit-logged.\n","properties":{"reason":{"description":"Why the suppression is being revoked (required, audit-logged).","type":"string"}},"required":["reason"],"type":"object"},"RiskDial":{"description":"The effective risk dial (Review Loop, agent plane; D4/D12): the account default plus every category's overrides (each with its resolved effective value). Read-only for agents; flipping the dial is a console (human) action (D16).\n","properties":{"account":{"$ref":"#/components/schemas/AccountRiskDial"},"categories":{"items":{"$ref":"#/components/schemas/CategoryRiskDial"},"type":"array"}},"required":["account","categories"],"type":"object"},"RiskDialRequest":{"description":"Set the account-default risk dial (console plane, D4). A nil field leaves that column unchanged.\n","properties":{"auto_send_cap_per_day":{"type":"integer"},"canary_rate":{"format":"double","type":"number"},"drift_demote_after":{"type":"integer"},"first_contact_gate":{"type":"boolean"},"graduate_min_age_hours":{"type":"integer"},"graduate_min_approvals":{"type":"integer"},"min_confidence":{"format":"double","type":"number"}},"type":"object"},"Rule":{"description":"A learned writing rule (rule_…) in the Review Loop (D2/D11). House-style/ general (scope='general', applies across all categories) or category-scoped. Append-only by supersession: an edit is a new rev (same lineage_id) with the prior flipped to superseded. Read by the agent at compose/redraft time via the ordered get_rules ladder; we never apply it. Opaque ids only (D10).\n","properties":{"author_kind":{"enum":["agent","human"],"type":"string"},"category_id":{"description":"Set iff scope=category (cat_…).","type":"string"},"created_at":{"format":"date-time","type":"string"},"id":{"description":"Opaque rule id (rule_…).","type":"string"},"kind":{"description":"hard = non-overridable.","enum":["soft","hard"],"type":"string"},"lineage_id":{"description":"Stable lineage handle across versions (rln_…).","type":"string"},"org_id":{"description":"The org this rule belongs to.","type":"string"},"priority":{"type":"integer"},"project_id":{"description":"The project this rule belongs to; empty for an org-layer rule.","type":"string"},"rev":{"type":"integer"},"rule_layer":{"description":"Ownership layer (org/project model). `org` = house-style inherited by every project in the org; `project` = layered on top (the agent-plane default). Project/per-agent rules outrank broader org rules in the ordered get_rules ladder.\n","enum":["org","project"],"type":"string"},"rule_text":{"type":"string"},"scope":{"description":"general = house-style (D2).","enum":["general","category"],"type":"string"},"scope_agent_id":{"description":"Set for a per-agent override; empty = all org agents.","type":"string"},"status":{"enum":["proposed","active","superseded","retired"],"type":"string"},"supersedes_id":{"description":"The prior rev this row superseded (rule_…).","type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","lineage_id","rev","scope","rule_text","kind","priority","status","author_kind","created_at","updated_at"],"type":"object"},"RuleAuditEntry":{"description":"One append-only rule/category change \u0026 undo audit row (udo_…). before_json / after_json carry the snapshot enabling an undo. undo = a later 'restore' entry; this row's undone flips true when it has been undone.\n","properties":{"action":{"enum":["create","supersede","retire","rename","redescribe","merge","restore"],"type":"string"},"actor_id":{"type":"string"},"actor_kind":{"enum":["agent","human","system"],"type":"string"},"after_json":{"description":"JSON snapshot of the new version.","type":"string"},"before_json":{"description":"JSON snapshot of the prior version.","type":"string"},"created_at":{"format":"date-time","type":"string"},"entity_id":{"description":"rule_… (lineage head) or cat_….","type":"string"},"entity_kind":{"enum":["rule","category"],"type":"string"},"id":{"description":"Opaque audit id (udo_…).","type":"string"},"undone":{"type":"boolean"}},"required":["id","entity_kind","entity_id","action","actor_kind","undone","created_at"],"type":"object"},"RuleAuditPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/RuleAuditEntry"},"type":"array"},"next_cursor":{"type":"string"},"total":{"type":"integer"}},"required":["items","total"],"type":"object"},"RulePage":{"description":"The ORDERED active rule set (the §7 precedence ladder applied SERVER-SIDE, capped). Category rules precede general/house-style rules; within each, highest precedence first. The agent reconciles the list semantically (NO LLM on our side).\n","properties":{"category_rules_version":{"type":"integer"},"composition_token":{"description":"Opaque short-lived proof of this exact effective rules snapshot. Omitted on filtered scope queries.","type":"string"},"composition_token_expires_at":{"format":"date-time","type":"string"},"house_style_version":{"type":"integer"},"items":{"items":{"$ref":"#/components/schemas/Rule"},"type":"array"},"rule_high_water":{"type":"integer"},"total":{"type":"integer"}},"required":["items","total"],"type":"object"},"SaveRuleRequest":{"description":"Write or edit a rule (append-only by supersession; D11). scope='general' iff category_id is empty (house-style, D2). With supersedes_id the write is an EDIT (rev+1, same lineage). kind defaults soft. propagate_to_pending is the D8 retro- propagation HUMAN OPT-IN (default OFF): when true, a NEW category rule that could apply to pending siblings enqueues ONE propagate_general_rule nudge (siblings + suggested_batch) so the agent redrafts a FEW at a time; never the whole queue. Agent-plane saves are ALWAYS project-layer (the saved rule's rule_layer is `project`, bound to the key's project); creating org-layer/house-style rules is console/admin-only in v1.\n","properties":{"category_id":{"description":"Category id (cat_…); empty = house-style/general.","type":"string"},"client_id":{"description":"Stable retry identifier; also accepted through Idempotency-Key. Replays the original response for 24 hours.","type":"string"},"kind":{"description":"Defaults soft.","enum":["soft","hard"],"type":"string"},"priority":{"type":"integer"},"propagate_to_pending":{"description":"D8 retro-propagation HUMAN OPT-IN (default false): enqueue a propagate_general_rule nudge to pending siblings of a NEW category rule.","type":"boolean"},"rule_text":{"type":"string"},"scope":{"description":"Defaults from category_id (general iff empty).","enum":["general","category"],"type":"string"},"scope_agent_id":{"description":"Set for a per-agent override; empty = all org agents.","type":"string"},"source_review_id":{"description":"Provenance (rr_…).","type":"string"},"source_turn_id":{"description":"Provenance (turn_…).","type":"string"},"suggested_batch":{"description":"Override the propagate batch (0 = base 3, bounded by rework_batch_max); never fans one nudge to the whole queue.","type":"integer"},"supersedes_id":{"description":"Set to EDIT the prior version (rule_…).","type":"string"}},"required":["rule_text"],"type":"object"},"ScanBacklogRequest":{"description":"The D19/§8 on-demand reconciliation sweep request (console). staleness_tolerance overrides the strict default (0 = must be at/above current); null = the default.\n","properties":{"staleness_tolerance":{"description":"How many rules-versions behind current a queued draft may be and still release.","type":"integer"}},"type":"object"},"ScanBacklogStatus":{"description":"The D19/§8 backlog-reconciliation snapshot for a category (agent-readable, $0-LLM). Counts the QUEUED drafts that are stale vs current-enough against the current category rules-version + house-style version (a pure integer compare). Read-only; the agent READS the picture; the human / hooks TRIGGER the sweep.\n","properties":{"category_id":{"type":"string"},"current_category_rules_version":{"type":"integer"},"current_enough":{"description":"Of the queued, how many are within the staleness tolerance of the current rules-version.","type":"integer"},"current_house_style_version":{"type":"integer"},"queued":{"description":"How many drafts are in the human queue (needs_review|in_review|chatting).","type":"integer"},"stale":{"description":"Of the queued, how many were composed under older rules and need a redraft.","type":"integer"},"staleness_tolerance":{"description":"How many versions behind current a draft may be and still count current-enough.","type":"integer"},"state":{"enum":["supervised","auto_notify","auto_silent","probation"],"type":"string"}},"required":["category_id","state","queued","current_enough","stale","current_category_rules_version","current_house_style_version","staleness_tolerance"],"type":"object"},"SendRequest":{"properties":{"attachments":{"items":{"$ref":"#/components/schemas/AttachmentInput"},"type":"array"},"bcc":{"items":{"format":"email","type":"string"},"type":"array"},"body":{"deprecated":true,"description":"DEPRECATED alias for `text`, kept accepted indefinitely so already-deployed callers keep working; it will never be removed. Send `text` in new code. Supplying BOTH with different content is a 400 (code bad_request, errors[].code conflicting_alias); the server never guesses which bytes to relay; supplying both with identical content is accepted.\n","type":"string"},"category_confidence":{"description":"Agent-supplied confidence (0..1) in the category match. Feeds the submit-time min_confidence auto-send gate ONLY; the server never scores ($0 LLM). Below the effective threshold (or omitted when a threshold is set) the would-be auto-send routes to needs_review (gate_outcome held:low_confidence).\n","format":"float","maximum":1,"minimum":0,"type":"number"},"category_id":{"description":"Opaque category id (cat_…) matched from the registry. Never a name.","type":"string"},"cc":{"items":{"format":"email","type":"string"},"type":"array"},"composition_token":{"description":"Opaque token from a fresh, unfiltered GET /v1/rules for this agent, project, and category.","type":"string"},"headers":{"additionalProperties":{"type":"string"},"description":"Arbitrary custom headers (reserved/unsafe header names are dropped).","type":"object"},"html":{"description":"Optional HTML body","sent as an alternative alongside the plain-text part.":null,"type":"string"},"idempotency_key":{"deprecated":true,"description":"DEPRECATED body-level alias for the `Idempotency-Key` header, tolerated for @extrovert.dev/sdk \u003c= 0.1.0 builds that serialize the whole request object. Send the header instead; when both are present the header wins. Note that the replay key is scoped to a hash of the RAW request body, so the same logical message retried once as `body` and once as `text` under one key is a body mismatch and answers 409 idempotency_conflict. Different bytes are a different request.\n","type":"string"},"in_reply_to":{"description":"Message-ID to thread under (optional).","type":"string"},"intent":{"$ref":"#/components/schemas/ReviewIntent"},"mode":{"description":"Review Loop (HITL) per-send assertion. `review` (default) routes the message into the human-review queue; `direct` requests an immediate send. The authoritative account/inbox review policy may downgrade `direct` to `review`. Setting any of mode/intent/category_id opts the send into the Review Loop.\n","enum":["review","direct"],"type":"string"},"reply_to":{"description":"Override the Reply-To header.","type":"string"},"subject":{"type":"string"},"text":{"description":"Plain-text body. This is the canonical name and matches ReplyRequest.text, ForwardRequest.text and Message.text.\n","type":"string"},"to":{"items":{"format":"email","type":"string"},"minItems":1,"type":"array"}},"required":["to"],"type":"object"},"SendResult":{"description":"The outcome of a reply or forward.","properties":{"message_id":{"type":"string"},"review_id":{"description":"Opaque review id (rr_…) for the review row that governed this send. ADDITIVE. Every agent-plane send now creates one, so an agent that crashes after issuing the request can still call `GET /v1/reviews/{id}` and read `closed` / `sent_message_id` instead of guessing whether the message went out.\n","type":"string"},"thread_id":{"type":"string"}},"type":"object"},"SentResult":{"description":"A Review Loop submit that was sent immediately (policy-permitted direct or graduated path). `kind` is always \"sent\".\n","properties":{"kind":{"enum":["sent"],"type":"string"},"message":{"properties":{"id":{"type":"string"},"thread_id":{"type":"string"}},"type":"object"},"review":{"description":"The review row that governed this send (ADDITIVE).","properties":{"id":{"description":"Opaque review id (rr_…).","type":"string"},"state":{"description":"Terminal state (sent | auto_sent).","type":"string"}},"type":"object"}},"required":["kind","message"],"type":"object"},"SignUpRequest":{"properties":{"human_email":{"description":"Where the verification code is sent.","format":"email","type":"string"},"username":{"description":"Desired local part for the first free inbox. It is normalized to lowercase, must contain at least five characters, and cannot be postmaster, admin, webadmin, legal, fraudmark, fraudmarc, keith, melissa, richard, sydney, syd, john, or johnny. Omit it for a generated local part.\n","type":"string"}},"required":["human_email"],"type":"object"},"SignUpResult":{"description":"The verification-only `signup:verify` bootstrap key (shown once) plus the pending inbox on `free.extrovertmail.com`. The account is not active until OTP verification. Before then the key may call signup verification only; it cannot create or read inboxes, export credentials, or send customer-authored mail. The key expires at `otp_expires_at`; the OTP is sent only to `human_email`.\n","properties":{"address":{"description":"The pending inbox on `free.extrovertmail.com`.","format":"email","type":"string"},"agent_id":{"type":"string"},"agent_key":{"description":"Limited-scope bootstrap key","shown once and expiring with the OTP.":null,"type":"string"},"customer_id":{"type":"string"},"key_prefix":{"type":"string"},"message":{"type":"string"},"otp_expires_at":{"format":"date-time","type":"string"},"otp_sent_to":{"type":"string"},"scopes":{"items":{"type":"string"},"type":"array"},"verified":{"type":"boolean"}},"type":"object"},"SignupStatus":{"properties":{"free_signups_enabled":{"description":"Whether unauthenticated free-account signup and verification are operationally enabled. Currently false in production.","type":"boolean"}},"required":["free_signups_enabled"],"type":"object"},"StatusResult":{"properties":{"message_id":{"description":"A stable identifier for the submitted message the sender can self-correlate on: the opaque msg_ id when the Sent append resolved, else the bracketed RFC5322 Message-ID header value. Present on the direct-send response; always non-empty when status is \"sent\".\n","type":"string"},"review_id":{"description":"Opaque review id (rr_…) for the review row that governed this send. ADDITIVE; see SendResult.review_id.\n","type":"string"},"status":{"type":"string"}},"type":"object"},"StreamEvent":{"description":"One event from the SSE stream, carried as the `data:` payload of an `text/event-stream` frame. It is the SAME envelope a webhook delivers, so a stream consumer and a webhook consumer see byte-identical data. The SSE frame's `id:` field carries the monotonic resume token (pass it back as `Last-Event-ID` on reconnect) and its `event:` field carries `event` below.\n","properties":{"created_at":{"format":"date-time","type":"string"},"event":{"description":"Event type, e.g. `message.received`.","example":"message.received","type":"string"},"id":{"description":"Opaque event id (`evt_...`).","type":"string"},"inbox":{"description":"The inbox this event concerns.","type":"string"},"message":{"$ref":"#/components/schemas/Message"}},"type":"object"},"StripeWebhookAck":{"properties":{"event_id":{"type":"string"},"event_type":{"type":"string"},"inserted":{"type":"boolean"},"status":{"enum":["ok"],"type":"string"}},"required":["status","inserted","event_id","event_type"],"type":"object"},"SubmitRevisionRequest":{"description":"Post a NEW agent draft under a parent_revision CAS (D17). parent_revision is the PRIMARY conflict check; it must equal the draft's current revision, else 409 STALE with NO mutation (a human/inbound actor moved the draft). version is OPTIONAL belt-and-suspenders (a human edit that did not bump the revision still bumps the version). On a clean CAS the proposed_* body is re-rendered in place (revision++), the draft returns to needs_review, and the reviewer nudge + review event fire (all atomic). rules_version_seen pins the rule high-water the draft was composed against (born-stale basis, D19).\n","properties":{"attachments":{"description":"REPLACES the draft's attachments. Omit the field to leave them untouched; send an empty array to clear them. Without this a redraft could never restore an attachment, so an agent redrafting after feedback would ship a message the reviewer saw WITH a file and the recipient received without.\n","items":{"$ref":"#/components/schemas/AttachmentInput"},"type":"array"},"body":{"deprecated":true,"description":"DEPRECATED alias for `text`, kept accepted indefinitely so already-deployed callers keep working; it will never be removed. Send `text` in new code. Supplying BOTH with different content is a 400 (code bad_request, errors[].code conflicting_alias); the server never guesses which bytes the reviewer will be shown; supplying both with identical content is accepted. Note that Idempotency-Key replay hashes the RAW body, so the same redraft retried once as `body` and once as `text` under one key is a 409 idempotency_conflict.\n","type":"string"},"built_at":{"description":"When the agent built this draft (informational).","format":"date-time","type":"string"},"composition_token":{"description":"Opaque token from a fresh, unfiltered GET /v1/rules for the review's category.","type":"string"},"html":{"type":"string"},"parent_revision":{"description":"The revision the agent composed against (PRIMARY CAS).","type":"integer"},"rules_version_seen":{"description":"Rule high-water this draft was composed against (born-stale basis).","type":"integer"},"subject":{"type":"string"},"text":{"description":"Plain-text body of the redraft. This is the canonical name and matches SendRequest.text, ReplyRequest.text, ForwardRequest.text and Message.text, so the same field name composes a message and redrafts it.\n","type":"string"},"version":{"description":"Optional row-version CAS (defense in depth).","type":"integer"}},"required":["parent_revision"],"type":"object"},"Suppression":{"description":"One recipient opt-out (suppression) row visible to the caller's own org. Only org-scope rows are ever returned to the agent/console planes; global and shared_domain rows are operator-only. Rows soft-revoke (revoked_at/by/reason) rather than delete, so opt-out history outlives tenant lifecycle.\n","properties":{"created_at":{"format":"date-time","type":"string"},"id":{"description":"Opaque suppression id (sup_…).","type":"string"},"narrow_agent_id":{"description":"Set on a recipient-chosen 'just this sender' narrow row.","type":"string"},"narrow_mailbox":{"type":"string"},"origin_agent_id":{"type":"string"},"origin_mailbox":{"description":"The sending mailbox that prompted the opt-out (audit).","type":"string"},"origin_message_id":{"type":"string"},"reactivation_count":{"description":"Cumulative unsub→revoke→unsub cycles for this row (the §7 abuse input).","type":"integer"},"recipient":{"description":"Canonicalized recipient address (NFC, punycode domain, lower-cased).","type":"string"},"recipient_raw":{"description":"The address as originally received.","type":"string"},"revoke_reason":{"type":"string"},"revoked":{"type":"boolean"},"revoked_at":{"description":"Set when the row was soft-revoked.","format":"date-time","type":"string"},"revoked_by":{"type":"string"},"scope":{"description":"Always 'org' on these planes (global/shared_domain are operator-only).","enum":["org"],"type":"string"},"source":{"enum":["one_click","page","mailto","reply_stop","manual","complaint","escalation"],"type":"string"}},"required":["id","recipient","scope","source","reactivation_count","created_at","revoked"],"type":"object"},"SuppressionPage":{"description":"The paged list of the caller's own org suppression rows (newest-first).","properties":{"items":{"items":{"$ref":"#/components/schemas/Suppression"},"type":"array"},"next_cursor":{"description":"Opaque cursor for the next page; absent on the last page.","type":"string"},"total":{"type":"integer"}},"required":["items","total"],"type":"object"},"SuppressionPrecheck":{"description":"GET /v1/suppressions?recipient= pre-check result: whether the CALLER'S OWN ORG has an active suppression for the recipient, plus those org rows. Reflects only the caller's org state; never a global/shared/cross-tenant opt-out (R4 non-leakage).\n","properties":{"recipient":{"description":"The canonicalized recipient that was checked.","type":"string"},"rows":{"items":{"$ref":"#/components/schemas/Suppression"},"type":"array"},"suppressed":{"description":"True iff the caller's org has an active suppression for the recipient.","type":"boolean"}},"required":["recipient","suppressed","rows"],"type":"object"},"Thread":{"description":"A conversation backed by the mail server's persistent thread index.","properties":{"id":{"example":"thr_9aB","type":"string"},"inbox_id":{"example":"agent7@extrovertmail.com","type":"string"},"last_message_at":{"type":"string"},"last_message_has_attachments":{"description":"Whether the latest message has attachments.","type":"boolean"},"last_message_id":{"description":"Opaque id of the latest message; usable by message endpoints.","type":"string"},"message_count":{"type":"integer"},"participants":{"items":{"type":"string"},"type":"array"},"snippet":{"type":"string"},"subject":{"type":"string"},"unread":{"description":"Whether the latest message is unread.","type":"boolean"}},"type":"object"},"ThreadDetail":{"allOf":[{"$ref":"#/components/schemas/Thread"},{"properties":{"messages":{"description":"The thread's messages, oldest-first.","items":{"$ref":"#/components/schemas/Message"},"type":"array"}},"type":"object"}]},"ThreadPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Thread"},"type":"array"},"next_cursor":{"type":"string"},"total":{"type":"integer"}},"type":"object"},"UpdateCategoryRequest":{"description":"Rename / re-describe a category; metadata ONLY (D10). Either field may be omitted (unchanged).","properties":{"description":{"type":"string"},"name":{"type":"string"}},"type":"object"},"UpdateInboxRequest":{"description":"Cheap, in-place inbox settings an owning agent may change without delete+recreate. Every field is optional; an omitted field leaves the stored value untouched (PATCH semantics). Sending an empty string clears a display/webhook field (display name falls back to the local part at the mail layers).\n","properties":{"daily_send_limit":{"description":"Replace the inbox's rolling-24h recipient cap. Requires mailbox:quota in addition to mailbox:read; ordinary create/send keys cannot raise their own safety throttle.\n","maximum":10000,"minimum":1,"type":"integer"},"display_name":{"description":"Sender display / \"From\" name. Propagated to the inbox and the authenticated sender.","type":"string"},"metadata":{"additionalProperties":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"}]},"description":"Patch the inbox's arbitrary metadata (AgentMail parity). Shallow merge: an omitted `metadata` leaves it unchanged; an object merges into the existing metadata; a key whose value is null deletes that key; a top-level `metadata: null` clears ALL metadata (the response then carries `{}`). Values may be string, number, or boolean; a per-key `null` value DELETES that key (the documented delete mechanism); nested objects/arrays are rejected; the same ≤256 key/length caps as create apply.\n","nullable":true,"type":"object"},"project_id":{"description":"Optional assertion that must match the key's bound project; NEVER a selector. A mismatch is 403.\n","type":"string"},"webhook_url":{"description":"Replace the inbox's inbound webhook target (empty string clears it).","type":"string"}},"type":"object"},"UpdateMemberRoleRequest":{"description":"Change an existing member's role. Role-capped: the actor cannot grant a role above their own effective role. Demoting the org's last owner is refused (409).\n","properties":{"role":{"enum":["owner","admin","member","viewer","billing"],"type":"string"}},"required":["role"],"type":"object"},"UpdateWebhookRequest":{"description":"PATCH body for a webhook. Every field is optional; an omitted field leaves the stored value unchanged (PATCH semantics). The signing secret and id are immutable. `inbox` empty-string clears the per-inbox filter (covers all inboxes the agent owns).\n","properties":{"active":{"description":"Enable or disable delivery without deleting.","type":"boolean"},"address":{"description":"Legacy alias for `inbox`.","type":"string"},"event_types":{"description":"AgentMail-compatible alias for `events`.","items":{"enum":["message.received"],"example":"message.received","type":"string"},"type":"array"},"events":{"items":{"enum":["message.received"],"example":"message.received","type":"string"},"type":"array"},"inbox":{"description":"Scope to one mailbox; empty string clears the filter.","type":"string"},"url":{"format":"uri","type":"string"}},"type":"object"},"VerifyRequest":{"properties":{"otp":{"type":"string"}},"required":["otp"],"type":"object"},"VerifyResult":{"description":"OTP verification activates the free account and returns the replacement full-permission key plus the ready `free.extrovertmail.com` inbox; the verification-only bootstrap key was revoked atomically. The inbox quickstart makes the response a self-contained handoff after a process restart or context compaction.\n","properties":{"address":{"description":"The signup inbox, ready for immediate use.","format":"email","type":"string"},"agent_id":{"type":"string"},"agent_key":{"description":"New full-permission key","shown once.":null,"type":"string"},"key_prefix":{"type":"string"},"mailbox_quickstart":{"$ref":"#/components/schemas/MailboxQuickstart"},"message":{"type":"string"},"org_claim_token":{"description":"One-time, email-bound owner claim seed for the signup org. Present only on a fresh signup. In the console, sign in with the verified email and call GET /v1/admin/me to find the matching pending_signup_claims entry. Then POST /v1/admin/signup-claims/{claim_id}/accept to bind that identity to the signup org as owner.\n","type":"string"},"scopes":{"items":{"type":"string"},"type":"array"},"verified":{"type":"boolean"}},"required":["agent_id","agent_key","key_prefix","scopes","address","verified","message","mailbox_quickstart"],"type":"object"},"WaitRequest":{"description":"Block until a matching message arrives. The inbox is taken from the path on `POST /v1/inboxes/{inbox_id}/wait`; on the legacy `POST /v1/wait` it is the `address` field.\n","properties":{"address":{"description":"Required on POST /v1/wait; ignored on the inbox-scoped path.","type":"string"},"folder":{"type":"string"},"from":{"description":"Substring match on the From header.","type":"string"},"link_hint":{"description":"Hint to bias verification-link extraction.","type":"string"},"match":{"description":"Regex matched over subject + body.","type":"string"},"since_now":{"description":"When true (default), match only arrivals after the wait begins.","type":"boolean"},"subject":{"description":"Substring match on the Subject header.","type":"string"},"timeout_seconds":{"description":"Max seconds to block (default 300, capped at 600).","type":"integer"}},"type":"object"},"WaitResult":{"properties":{"extracted":{"$ref":"#/components/schemas/ExtractedCredentials"},"message":{"allOf":[{"$ref":"#/components/schemas/Message"}],"nullable":true},"timed_out":{"type":"boolean"}},"type":"object"},"Webhook":{"description":"A webhook registration. `secret` is present only on the create response (shown once); list/get redact it. `inbox` is null when the webhook covers every inbox.\n","properties":{"active":{"type":"boolean"},"agent_id":{"description":"Agent that owns the webhook.","type":"string"},"created_at":{"format":"date-time","type":"string"},"events":{"items":{"enum":["message.received"],"type":"string"},"type":"array"},"id":{"type":"string"},"inbox":{"nullable":true,"type":"string"},"secret":{"description":"HMAC signing secret. Create response only.","type":"string"},"secret_prefix":{"type":"string"},"url":{"type":"string"}},"type":"object"},"WebhookPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Webhook"},"type":"array"},"total":{"type":"integer"}},"type":"object"},"WhoAmI":{"description":"The verified principal behind an agent key. org_id/project_id are the FIXED org/project the key is bound to (resolved from the stored key, never client input). There is NO mutable project selector for a scoped key; whoami is the canonical project-visibility surface; project selection happens when the human/admin issues the enrollment token or agent key.\n","properties":{"agent_id":{"type":"string"},"customer_id":{"type":"string"},"key_id":{"type":"string"},"org_id":{"description":"The fixed org the key is bound to.","type":"string"},"project_id":{"description":"The fixed project the key is bound to.","type":"string"},"scopes":{"items":{"type":"string"},"type":"array"}},"type":"object"}},"securitySchemes":{"AgentKey":{"description":"Per-agent capability key (`pk_agent_...`) presented as `Authorization: Bearer ...`. Scoped (mailbox:create / read / send / delete / quota / credentials; signup:verify; domain:manage; domain:purchase; commerce:request; review:act), revocable, and self-expiring. The customer/tenant and the fixed org/project binding are derived from the key, never from client input. Privileged scopes are opt-in and default-off: `domain:manage` gates onboarding for domains the customer already controls. `commerce:request` permits quotes, durable purchase/plan requests, and status reads but never approval or spend.\n","scheme":"bearer","type":"http"},"ClerkSession":{"description":"Clerk session token for the console/admin surface. Authority is derived from the identity's membership in the org/project addressed in the PATH (/v1/admin/orgs/{org_id}/projects/{project_id}/...); there are no scope headers.\n","scheme":"bearer","type":"http"}}},"info":{"description":"Extrovert gives an AI agent a persistent inbox that sends and receives mail. Create it in one call with an agent key whose permissions can expire or be revoked.\n\nThe surface has two planes:\n\n- **Agent plane** (`/v1/...`, excluding `/v1/admin`) uses a\n  permissioned agent key (`pk_agent_...`) as a Bearer token. `customer_id` is always\n  derived from the key, never from client input, so the API is tenant-scoped by\n  construction. The MCP server and TypeScript SDK map 1:1 onto this plane.\n\n- **Console / admin plane** (`/v1/admin/...`) uses a Clerk\n  session token and strictly customer-scoped. Backs the human console,\n  including the shared-inbox viewer.\n\n\n`POST /v1/enroll` and `POST /v1/agent/sign-up` are unauthenticated bootstrap endpoints. `GET /healthz`, `GET /readyz`, `GET /openapi.yaml`, and `GET /openapi.json` are public.\n\n**Review Loop contract.** `info.version`, the SDK package version, and the SDK `CONTRACT_VERSION` all use `0.1.0-pre.6`. The stable agent-facing Review Loop JSON shapes are published in the SDK `contract` module (`CONTRACT_MANIFEST`) and the Agent contract documentation.\n","license":{"name":"Proprietary"},"title":"Extrovert API","version":"0.1.0-pre.6"},"openapi":"3.0.3","paths":{"/healthz":{"get":{"operationId":"healthz","responses":{"200":{"description":"ok"}},"security":[],"summary":"Liveness probe","tags":["ops"]}},"/openapi.json":{"get":{"operationId":"getOpenApiJson","responses":{"200":{"content":{"application/json":{"schema":{"type":"object"}}},"description":"The OpenAPI 3 spec converted to JSON."}},"security":[],"summary":"This OpenAPI description (JSON)","tags":["ops"]}},"/openapi.yaml":{"get":{"operationId":"getOpenApiYaml","responses":{"200":{"content":{"application/yaml":{"schema":{"type":"string"}}},"description":"The canonical OpenAPI 3 spec."}},"security":[],"summary":"This OpenAPI description (YAML)","tags":["ops"]}},"/readyz":{"get":{"operationId":"readyz","responses":{"200":{"description":"ready"},"503":{"description":"not ready"}},"security":[],"summary":"Readiness probe (checks the store)","tags":["ops"]}},"/v1/admin/invitations/accept":{"post":{"description":"Accepts an invitation by its raw token. IDENTITY-ONLY (no {org_id}; the token carries the org). The accept binds to the authenticated user's VERIFIED Clerk email == the normalized invitation email (else 403). Idempotent for the same user; a revoked/expired invitation cannot be accepted.\n","operationId":"acceptInvitation","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptInvitationRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgInvitation"}}},"description":"Accepted (membership written)."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Accept an invitation (identity-only; email-bound)","tags":["admin"],"x-fern-sdk-group-name":["admin","invitations"],"x-fern-sdk-method-name":"accept"}},"/v1/admin/me":{"get":{"description":"Returns the authenticated Clerk identity plus the orgs/projects it can reach (derived from membership). The console uses this to render the org/project switchers and to revalidate cookie landing hints. IDENTITY-ONLY; no {org_id} in the URL.\n","operationId":"adminMe","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminMe"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"ClerkSession":[]}],"summary":"The identity's reachable orgs + projects (landing scope)","tags":["admin"],"x-fern-sdk-group-name":["admin"],"x-fern-sdk-method-name":"me"}},"/v1/admin/orgs":{"get":{"operationId":"listOrgs","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgList"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"ClerkSession":[]}],"summary":"List the identity's reachable orgs","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs"],"x-fern-sdk-method-name":"list"},"post":{"description":"Create a CHILD org under parent_org_id (required). Requires admin+ on the parent. The child inherits the root org's tier/limits and is capped by the root's max_child_orgs. Client org/customer ids are never accepted.\n","operationId":"createOrg","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrgRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Org"}}},"description":"Created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Create a child org (admin+ on the parent)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs"],"x-fern-sdk-method-name":"create"}},"/v1/admin/orgs/{org_id}":{"delete":{"description":"Soft-deletes (archives) the org. Guarded: an org with active child orgs or active projects cannot be archived. The compatibility customers row is never hard-deleted.\n","operationId":"archiveOrg","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Org"}}},"description":"Archived."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Archive (soft-delete) an org (owner)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs"],"x-fern-sdk-method-name":"delete"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}],"patch":{"operationId":"patchOrg","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchOrgRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Org"}}},"description":"Updated."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Update an org's display fields (admin)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs"],"x-fern-sdk-method-name":"update"}},"/v1/admin/orgs/{org_id}/billing":{"get":{"operationId":"adminGetBilling","parameters":[{"in":"query","name":"month","required":false,"schema":{"example":"2026-06","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminBilling"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"Get org billing state and plan entitlements","tags":["billing"],"x-fern-sdk-group-name":["admin","orgs","billing"],"x-fern-sdk-method-name":"get"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/billing/checkout":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"adminCreateBillingCheckout","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBillingCheckoutRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBillingCheckoutResponse"}}},"description":"created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"503":{"$ref":"#/components/responses/NotConfigured"}},"security":[{"ClerkSession":[]}],"summary":"Create a Stripe Checkout Session for an Extrovert paid plan","tags":["billing"],"x-fern-sdk-group-name":["admin","orgs","billing"],"x-fern-sdk-method-name":"createCheckout"}},"/v1/admin/orgs/{org_id}/billing/domain-checkout":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}],"post":{"description":"Quotes the requested domain and a configured .com baseline with the registrar, reuses or creates a lookup-keyed annual Stripe Price, then returns a Checkout Session. Registration is queued only after the domain Checkout succeeds.","operationId":"adminCreateDomainBillingCheckout","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainBillingCheckoutRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainBillingCheckoutResponse"}}},"description":"created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"503":{"$ref":"#/components/responses/NotConfigured"}},"security":[{"ClerkSession":[]}],"summary":"Create a Stripe Checkout Session for an annual managed-domain registration","tags":["billing"],"x-fern-sdk-group-name":["admin","orgs","billing"],"x-fern-sdk-method-name":"createDomainCheckout"}},"/v1/admin/orgs/{org_id}/billing/portal":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"adminCreateBillingPortal","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBillingPortalRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBillingPortalResponse"}}},"description":"created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/NotConfigured"}},"security":[{"ClerkSession":[]}],"summary":"Create a Stripe Billing Portal Session for payment recovery and subscription management","tags":["billing"],"x-fern-sdk-group-name":["admin","orgs","billing"],"x-fern-sdk-method-name":"createPortal"}},"/v1/admin/orgs/{org_id}/commerce/requests":{"get":{"operationId":"adminListCommerceRequests","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/PageToken"},{"in":"query","name":"kind","schema":{"type":"string"}},{"in":"query","name":"state","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceRequestPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"List commerce approvals for an org","tags":["commerce","admin"]},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/commerce/requests/domain-purchases":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"adminCreateDomainPurchaseRequest","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainPurchaseRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceRequest"}}},"description":"Review request created"},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Create an exact-price domain request without charging or registering","tags":["commerce","admin"]}},"/v1/admin/orgs/{org_id}/commerce/requests/plan-changes":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"adminCreatePlanChangeRequest","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanChangeRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceRequest"}}},"description":"Review request created"},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Create a reviewable upgrade or downgrade without charging","tags":["commerce","admin"]}},"/v1/admin/orgs/{org_id}/commerce/requests/{request_id}":{"get":{"operationId":"adminGetCommerceRequest","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceRequest"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Get a commerce approval request","tags":["commerce","admin"]},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"request_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/commerce/requests/{request_id}/approve":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"request_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"adminApproveCommerceRequest","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecideCommerceRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceRequest"}}},"description":"Decision recorded"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Approve once and optionally create bounded future authority","tags":["commerce","admin"]}},"/v1/admin/orgs/{org_id}/commerce/requests/{request_id}/cancel":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"request_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"adminCancelCommerceRequest","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceRequest"}}},"description":"Cancelled"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Cancel a commerce request before irreversible work","tags":["commerce","admin"]}},"/v1/admin/orgs/{org_id}/commerce/requests/{request_id}/deny":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"request_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"adminDenyCommerceRequest","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecideCommerceRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceRequest"}}},"description":"Denied"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Deny a pending commerce request","tags":["commerce","admin"]}},"/v1/admin/orgs/{org_id}/commerce/requests/{request_id}/payment-link":{"get":{"operationId":"adminGetCommercePaymentLink","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"expires_at":{"type":"string"},"url":{"format":"uri","type":"string"}},"type":"object"}}},"description":"Secure hosted payment link"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Get Stripe's hosted payment-authentication link for a human","tags":["commerce","admin"]},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"request_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/commerce/requests/{request_id}/retry":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"request_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"adminRetryCommerceRequest","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceRequest"}}},"description":"Retry accepted"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Resume the same idempotent request after a recoverable blocker","tags":["commerce","admin"]}},"/v1/admin/orgs/{org_id}/commerce/spend-limits":{"get":{"operationId":"adminListCommerceSpendLimits","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"items":{"items":{"$ref":"#/components/schemas/CommerceSpendLimit"},"type":"array"},"total":{"type":"integer"}},"type":"object"}}},"description":"ok"}},"security":[{"ClerkSession":[]}],"summary":"List bounded future domain-purchase authority","tags":["commerce","admin"]},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"adminCreateCommerceSpendLimit","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceSpendLimitInput"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceSpendLimit"}}},"description":"Created"}},"security":[{"ClerkSession":[]}],"summary":"Create bounded future domain-purchase authority","tags":["commerce","admin"]}},"/v1/admin/orgs/{org_id}/commerce/spend-limits/{limit_id}":{"delete":{"operationId":"adminDeleteCommerceSpendLimit","responses":{"204":{"description":"Disabled"}},"security":[{"ClerkSession":[]}],"summary":"Disable a spend control","tags":["commerce","admin"]},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"limit_id","required":true,"schema":{"type":"string"}}],"put":{"operationId":"adminUpdateCommerceSpendLimit","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceSpendLimitInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceSpendLimit"}}},"description":"Updated"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Update a spend control with version fencing","tags":["commerce","admin"]}},"/v1/admin/orgs/{org_id}/domains":{"get":{"operationId":"adminListDomains","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainList"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"ClerkSession":[]}],"summary":"List onboarded domains","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","domains"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"adminOnboardDomain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardDomainRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardDomainResult"}}},"description":"Connected; returns the nameserver records for delegated setup."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"ClerkSession":[]}],"summary":"Add a delegated or purchased domain","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","domains"],"x-fern-sdk-method-name":"create"}},"/v1/admin/orgs/{org_id}/domains/{domain}":{"get":{"description":"Read one onboarded domain the caller's org owns, including the DNS nameserver records the customer must publish for `ns_delegated` mode. The list endpoint omits records to stay lightweight, so the console reads this when a domain row is expanded so the delegation reappears after the onboarding dialog is dismissed or the page reloaded. Tenant-scoped: an unknown domain, or one owned by a different org, is a 404 (records are never leaked across tenants).\n","operationId":"adminGetDomain","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardDomainResult"}}},"description":"The domain detail with delegation_ns inline."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Get one domain's detail and nameserver records","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","domains"],"x-fern-sdk-method-name":"get"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"domain","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/domains/{domain}/outbound-route":{"get":{"description":"Read-only view of the domain's assigned outbound provider account and route state (viewer). An unassigned domain returns route_state \"unassigned\" (it routes direct by fail-safe). A domain the caller's org does not own returns 404.\n","operationId":"adminGetOutboundRoute","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundRouteView"}}},"description":"The domain's outbound route."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"The domain's current outbound provider route (console)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","outboundRoute"],"x-fern-sdk-method-name":"get"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"domain","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/domains/{domain}/outbound-route/retirements":{"get":{"description":"Read-only list of the domain's retiring provider stints (viewer); the accounts a switch left decommissioning during their overlap window. The active route view clears previous_account_id on flip, so this is the only HTTP surface that observes a retiring stint. provider_state_json is never exposed. A domain the caller's org does not own returns 404.\n","operationId":"adminListOutboundRouteRetirements","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutboundRouteRetirementList"}}},"description":"The domain's retiring-sender ledger rows."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"The domain's retiring-sender ledger (console)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","outboundRoute"],"x-fern-sdk-method-name":"retirements"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"domain","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/invitations":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}],"post":{"description":"Creates (or idempotently reuses an existing pending) org invitation. The raw token is returned ONCE on a fresh create (201); a reused pending invite returns 200 with no token. Role-capped to the inviter's own role.\n","operationId":"createInvitation","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInvitationRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgInvitation"}}},"description":"Existing pending invitation reused (no new token)."},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgInvitation"}}},"description":"Created (raw token shown once)."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Invite a member to the org (admin; role-capped)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","invitations"],"x-fern-sdk-method-name":"create"}},"/v1/admin/orgs/{org_id}/invitations/{invitation_id}/revoke":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"invitation_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"revokeInvitation","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgInvitation"}}},"description":"Revoked."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Revoke a pending invitation (admin)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","invitations"],"x-fern-sdk-method-name":"revoke"}},"/v1/admin/orgs/{org_id}/members":{"get":{"operationId":"listMembers","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgMemberList"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"List the org's members (viewer)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","members"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/members/{user_id}":{"delete":{"description":"Removes a member. Removing the org's LAST owner is refused (409 last_owner).\n","operationId":"removeMember","responses":{"204":{"description":"Removed."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Remove a member from the org (admin; last-owner guarded)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","members"],"x-fern-sdk-method-name":"delete"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"user_id","required":true,"schema":{"type":"string"}}],"patch":{"description":"Changes a member's role. Role-capped to the actor's own effective role; demoting the org's LAST owner is refused (409 last_owner).\n","operationId":"updateMemberRole","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberRoleRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgMember"}}},"description":"Updated membership."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Change a member's role (admin; role-capped, last-owner guarded)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","members"],"x-fern-sdk-method-name":"update"}},"/v1/admin/orgs/{org_id}/projects":{"get":{"operationId":"listProjects","parameters":[{"in":"query","name":"include_archived","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectList"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"List the org's projects (viewer)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}],"post":{"description":"Create a project under the org. The org's max_projects cap is enforced inside the same transaction as the create. Client ids are never accepted.\n","operationId":"createProject","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}},"description":"Created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Create a project in the org (admin)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects"],"x-fern-sdk-method-name":"create"}},"/v1/admin/orgs/{org_id}/projects/{project_id}":{"delete":{"description":"Soft-deletes (archives) the project. Guarded: the default project can never be archived, and a project with active resources cannot be archived.\n","operationId":"archiveProject","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}},"description":"Archived."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Archive (soft-delete) a project (admin)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects"],"x-fern-sdk-method-name":"delete"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}],"patch":{"operationId":"patchProject","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchProjectRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}},"description":"Updated."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Update a project's display fields (admin)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects"],"x-fern-sdk-method-name":"update"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/agent-keys":{"get":{"operationId":"listAgentKeys","parameters":[{"in":"query","name":"agent_id","schema":{"type":"string"}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentKeyList"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"List issued agent API keys","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","agentKeys"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"issueAgentKey","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueAgentKeyRequest"}}}},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueAgentKeyResult"}}},"description":"Created (key shown once)."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Issue an agent API key (secret shown once)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","agentKeys"],"x-fern-sdk-method-name":"create"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/agent-keys/{id}":{"delete":{"operationId":"revokeAgentKey","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"revoked"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Revoke an agent API key","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","agentKeys"],"x-fern-sdk-method-name":"delete"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/agents":{"get":{"operationId":"listAgents","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentList"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"ClerkSession":[]}],"summary":"List agents","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","agents"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}],"post":{"description":"Creates an active, project-bound agent for console-managed inboxes. API keys can be issued separately.","operationId":"createAgent","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAgentRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentSummary"}}},"description":"created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"Create an agent identity without issuing credentials","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","agents"],"x-fern-sdk-method-name":"create"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/agents/{id}/disable":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"disableAgent","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentStatusResult"}}},"description":"disabled"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Disable an agent (instantly invalidates its keys)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","agents"],"x-fern-sdk-method-name":"disable"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/agents/{id}/enable":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"enableAgent","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentStatusResult"}}},"description":"active"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Re-enable a disabled agent","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","agents"],"x-fern-sdk-method-name":"enable"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/audit":{"get":{"operationId":"listAuditEvents","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditList"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"ClerkSession":[]}],"summary":"List the org's console audit log","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","audit"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/categories":{"get":{"description":"List the shared category registry, scoped to the resolved org/project. The agent-plane read (GET /v1/categories) is AgentKey-only, so the console reads the SAME view here (Clerk session). The optional `match` is a pure lexical/substring filter (NO LLM); identity is opaque cat_ ids (D10).\n","operationId":"adminListCategories","parameters":[{"description":"Lexical substring filter over name+description+slug (every token must match; NO LLM).","in":"query","name":"match","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Browse the category registry (console plane)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","categories"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"adminCreateCategory","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminCreateCategoryRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}},"description":"Created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"Create a category from the console","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","categories"],"x-fern-sdk-method-name":"create"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/categories/{id}":{"delete":{"description":"SOFT delete the category (D9 never-hard-delete): the row + its references + history survive as training data. The soft-delete is a self-tombstone (merged_into = self) so it drops out of the default registry list; an audit/undo row (action=retire) records it. Console-only; a foreign id is 404.\n","operationId":"adminDeleteCategory","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteCategoryResult"}}},"description":"Soft-deleted."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Soft-delete a category (console plane, human authority)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","categories"],"x-fern-sdk-method-name":"delete"},"get":{"description":"Read one category from the shared registry, scoped to the resolved org/project. The agent-plane read (GET /v1/categories/{id}) is AgentKey-only, so the console reads the SAME view here (Clerk session). The console re-reads after a soft-delete to reflect the self-tombstone. A foreign id is 404.\n","operationId":"adminGetCategory","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Get one category (console plane)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","categories"],"x-fern-sdk-method-name":"get"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"patch":{"description":"Rename / re-describe a category with author_kind=human (metadata only, D10); writes a rename/redescribe audit/undo row. Console-only (never an MCP tool, D17). Customer-scoped; a foreign id is 404.\n","operationId":"adminUpdateCategory","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCategoryRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Rename / re-describe a category (console plane, human authority)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","categories"],"x-fern-sdk-method-name":"update"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/categories/{id}/backlog-status":{"get":{"description":"Read the $0-LLM, read-only D19 snapshot of how many queued drafts are stale vs current-enough against the current rules-version (§8). The agent-plane read (GET /v1/categories/{id}/backlog-status) is AgentKey-only, so the console reads the SAME view here (Clerk session) for its reconciliation panel; the human scan-backlog button TRIGGERS the sweep. Read-only; a foreign id is 404.\n","operationId":"adminGetBacklogStatus","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanBacklogStatus"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Read a category's backlog reconciliation status (console plane)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","categories"],"x-fern-sdk-method-name":"getBacklogStatus"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/categories/{id}/demote":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"Flip the graduation bit ONE rung down (auto_silent→auto_notify→supervised). Demoting from supervised is 409 (nowhere below). On success it clears the graduated provenance, writes a ctr_ transition (reason regressed), emits category.demoted, and enqueues recheck_category nudges. Console-only (never an MCP tool, D17). A foreign id is 404.\n","operationId":"adminDemoteCategory","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}},"description":"Demoted."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"ClerkSession":[]}],"summary":"Demote a category one rung down (console plane, human authority)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","categories"],"x-fern-sdk-method-name":"demote"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/categories/{id}/graduate":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"Flip the graduation bit ONE rung up: supervised→auto_notify→auto_silent (D16). never_graduate is locked at supervised (409 graduation_locked); a non-adjacent target is 400; graduating to auto_silent requires the MATURITY GATE (clean_approval_count ≥ N AND category age ≥ min_age_hours) or it is 409 maturity_gate_unmet. On success it writes a ctr_ transition, emits category.graduated, and enqueues recheck_category nudges to pending drafts. Console-only (never an MCP tool, D17). A foreign id is 404.\n","operationId":"adminGraduateCategory","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraduateCategoryRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}},"description":"Graduated."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"ClerkSession":[]}],"summary":"Graduate a category one rung up (console plane, human authority)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","categories"],"x-fern-sdk-method-name":"graduate"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/categories/{id}/graduation-status":{"get":{"description":"Read the gate status toward the next rung (the maturity gate + drift tripwire counters that drive the console graduation controls). The agent-plane read (GET /v1/categories/{id}/graduation-status) is AgentKey-only, so the console reads the SAME view here (Clerk session). Read-only; a foreign id is 404.\n","operationId":"adminGetGraduationStatus","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraduationStatus"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Read a category's graduation gate status (console plane)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","categories"],"x-fern-sdk-method-name":"getGraduationStatus"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/categories/{id}/merge":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"Merge the path category (the loser) into into_category_id (the survivor), repointing all rr_/rule_ references BY cat_ id and setting merged_into on the loser in ONE transaction (D9/D10), plus a merge transition + audit/undo row. A cross-tenant or unknown into_category_id is 404 (never a cross-customer merge); merging into itself is 400. Console-only.\n","operationId":"adminMergeCategory","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MergeCategoryRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MergeCategoryResult"}}},"description":"Merged."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"ClerkSession":[]}],"summary":"Merge a category into another (console plane, human authority)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","categories"],"x-fern-sdk-method-name":"merge"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/categories/{id}/never-graduate":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"Pin a category at supervised (locked=true) or release the pin (locked=false; D16). Locking a graduated category FIRST demotes it down to supervised (each rung writes its own ctr_ transition) so a locked category can never sit in a live auto-send state. Clearing the lock leaves the state untouched. Console-only (never an MCP tool, D17). A foreign id is 404.\n","operationId":"adminSetNeverGraduate","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeverGraduateRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Set/clear the never-graduate lock on a category (console plane, human authority)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","categories"],"x-fern-sdk-method-name":"neverGraduate"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/categories/{id}/pacing-state":{"get":{"description":"Read the demand-driven pacing snapshot: the human review cursor, the effective window/ceiling/interval, the queued count, and each draft's in-window / redrafting / behind-cursor classification (the \"redrafting…\" shimmer). The agent-plane read (GET /v1/categories/{id}/pacing-state) is AgentKey-only, so the console reads the SAME view here (Clerk session). Read-only; a foreign id is 404.\n","operationId":"adminGetPacingState","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryPacingState"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Read a category's demand-driven pacing state (console plane)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","categories"],"x-fern-sdk-method-name":"getPacingState"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/categories/{id}/risk-dial":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"patch":{"description":"Set / clear the per-category risk-dial OVERRIDES (D12). For each field, a non-null value SETS the override; an explicit JSON null RESETS it back to inherit (null = account default); an omitted field is unchanged. Console-only (never an MCP tool, D17). A foreign id is 404.\n","operationId":"adminUpdateCategoryRiskDial","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryRiskDialRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryRiskDial"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Set a category's risk-dial overrides (console plane, human authority)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","categories"],"x-fern-sdk-method-name":"updateRiskDial"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/categories/{id}/scan-backlog":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"Run the D19/§8 on-demand reconciliation sweep for a category: walk every QUEUED draft and INTEGER-COMPARE its composed_* rules-versions against the category's CURRENT versions (with a tunable staleness tolerance). A current-enough draft is released through the M6 submit-time gate (the agent re-submits to deliver; the gate is re-run, never bypassed); a stale draft is nudged to redraft against current rules and stays queued. The human never hand-touches the backlog and no stale draft slips out. Deterministic, $0-LLM. Console-only (never an MCP tool, D17). A foreign id is 404.\n","operationId":"adminScanBacklog","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanBacklogRequest"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReconcileResult"}}},"description":"The reconciliation sweep result (per-message outcomes + counts)."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Run the D19 backlog reconciliation sweep on demand (console plane)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","categories"],"x-fern-sdk-method-name":"scanBacklog"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/enrollment-tokens":{"get":{"operationId":"listEnrollmentTokens","parameters":[{"in":"query","name":"include_revoked","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollmentTokenList"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"ClerkSession":[]}],"summary":"List enrollment tokens","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","enrollmentTokens"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"issueEnrollmentToken","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueEnrollmentTokenRequest"}}}},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueEnrollmentTokenResult"}}},"description":"Created (token shown once)."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"Issue an enrollment token (secret shown once)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","enrollmentTokens"],"x-fern-sdk-method-name":"create"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/enrollment-tokens/{id}":{"delete":{"operationId":"revokeEnrollmentToken","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"revoked"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Revoke an enrollment token","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","enrollmentTokens"],"x-fern-sdk-method-name":"delete"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/inboxes":{"get":{"operationId":"adminListInboxes","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminInboxList"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"ClerkSession":[]}],"summary":"List every inbox in the org","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","inboxes"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"adminCreateInbox","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminCreateInboxRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminInbox"}}},"description":"Created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Create an inbox from the console","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","inboxes"],"x-fern-sdk-method-name":"create"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/inboxes/{addr}":{"delete":{"operationId":"adminDeleteInbox","responses":{"204":{"description":"Deleted."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Permanently delete an inbox and its authenticated sender","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","inboxes"],"x-fern-sdk-method-name":"delete"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Addr"}],"patch":{"operationId":"adminUpdateInbox","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUpdateInboxRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminInbox"}}},"description":"Updated."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Update an inbox's enforced daily recipient limit","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","inboxes"],"x-fern-sdk-method-name":"update"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/inboxes/{addr}/messages":{"get":{"operationId":"adminListMessages","parameters":[{"$ref":"#/components/parameters/Folder"},{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminMessageList"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"List recent messages for an org inbox","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","inboxes","messages"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Addr"}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/inboxes/{addr}/messages/{id}":{"get":{"operationId":"adminGetMessage","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminMessageDetail"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Get a single message (with attachment metadata) for an org inbox","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","inboxes","messages"],"x-fern-sdk-method-name":"get"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Addr"},{"$ref":"#/components/parameters/MessageID"}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/inboxes/{addr}/messages/{id}/attachments":{"get":{"operationId":"adminListAttachments","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachmentPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"List a message's attachment metadata for an org inbox","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","inboxes","messages","attachments"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Addr"},{"$ref":"#/components/parameters/MessageID"}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/inboxes/{addr}/messages/{id}/attachments/{attId}":{"get":{"operationId":"adminGetAttachment","responses":{"200":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}},"description":"The attachment bytes."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Download one attachment's bytes for an org inbox","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","inboxes","messages","attachments"],"x-fern-sdk-method-name":"get"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Addr"},{"$ref":"#/components/parameters/MessageID"},{"$ref":"#/components/parameters/AttachmentID"}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/inboxes/{addr}/reply":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Addr"}],"post":{"operationId":"adminReplyMessage","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplyRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendResult"}}},"description":"Accepted for delivery."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Thread-aware console reply from an org inbox","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","inboxes"],"x-fern-sdk-method-name":"reply"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/inboxes/{addr}/review-policy":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"addr","required":true,"schema":{"type":"string"}}],"patch":{"description":"Set the per-inbox review-policy override (a non-null policy) or clear it back to inherit the account default (explicit JSON null; D6). A foreign address is 404; an invalid non-null policy value is 400. Console-only (never an MCP tool, D17).\n","operationId":"adminUpdateInboxReviewPolicy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxReviewPolicyRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxReviewPolicy"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Set/clear the per-inbox review-policy override (console plane, human authority)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","inboxes"],"x-fern-sdk-method-name":"updateReviewPolicy"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/inboxes/{addr}/send":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Addr"}],"post":{"operationId":"adminSendMessage","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResult"}}},"description":"Accepted for delivery."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Send a message from an org inbox","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","inboxes"],"x-fern-sdk-method-name":"send"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/inboxes/{addr}/threads":{"get":{"operationId":"adminListInboxThreads","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminThreadList"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"List persistent threads for an org inbox","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","inboxes","threads"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Addr"}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/inboxes/{addr}/threads/{thread_id}":{"get":{"operationId":"adminGetInboxThread","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminThreadDetail"}}},"description":"Thread messages, oldest-first."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Get one persistent thread and its messages","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","inboxes","threads"],"x-fern-sdk-method-name":"get"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Addr"},{"in":"path","name":"thread_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/realtime/ticket":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}],"post":{"description":"Create a short-lived, single-use ticket bound to the Clerk session's customer scope, for opening the live Approvals SSE stream (`GET /v1/admin/reviews/stream?ticket=…`). A browser EventSource cannot set an Authorization header, so this ticket carries the customer scope instead. The ticket is consumed on first stream connect and self-expires (~60s).\n","operationId":"adminMintRealtimeTicket","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RealtimeTicket"}}},"description":"A freshly created realtime ticket."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"Create a single-use ticket for the console realtime stream","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","realtime"],"x-fern-sdk-method-name":"ticket"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/review-links":{"get":{"description":"The customer's review links (D5). Secrets are elided (has_secret only). Console-only (Clerk-authed).\n","operationId":"adminListReviewLinks","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewLinkList"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"List BYO review-agent links (console plane)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","reviewLinks"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}],"post":{"description":"Link a reviewer agent to an inbox (inbox_address empty = account-wide) so reviewed drafts on that scope route to the linked review-agent instead of straight to the human queue (D5; §9). One link per scope (the UNIQUE scope index); a duplicate scope is 409. The reviewer holds review:act, never mailbox:send; the platform sends with the COMPOSER's creds. Console-only (Clerk-authed); configuring WHO reviews is a human-authority setup decision, NEVER an MCP tool (the reviewer DECISION endpoints are agent-plane).\n","operationId":"adminCreateReviewLink","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReviewLinkRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewLink"}}},"description":"created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"ClerkSession":[]}],"summary":"Link a BYO review-agent to an inbox (console plane)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","reviewLinks"],"x-fern-sdk-method-name":"create"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/review-links/{rvl_id}":{"delete":{"description":"Remove a review link AND sweep every in-flight review currently routed through it back to the HUMAN queue; no orphan deliveries (§9): a review held by the deleted reviewer must not stay assigned to a reviewer that no longer exists. Console-only (Clerk-authed). A foreign id is 404.\n","operationId":"adminDeleteReviewLink","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteReviewLinkResult"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Delete a BYO review-agent link (console plane)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","reviewLinks"],"x-fern-sdk-method-name":"delete"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"rvl_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/review-policy":{"get":{"description":"The authoritative account-default review policy (D6): require_review, allow_direct, or auto_send_graduated. require_review always downgrades an agent's per-send mode assertion (an agent can never override it). effective is the account policy with the safe require_review floor applied. Console-only (Clerk-authed); the agent plane only READS the effective policy.\n","operationId":"adminGetReviewPolicy","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewPolicy"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"Read the account-default review policy (console plane)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects"],"x-fern-sdk-method-name":"getReviewPolicy"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}],"patch":{"description":"Set the account-default review policy (D6). An invalid policy value is 400. Console-only (never an MCP tool, D17).\n","operationId":"adminUpdateReviewPolicy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewPolicyRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewPolicy"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"Set the account-default review policy (console plane, human authority)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects"],"x-fern-sdk-method-name":"updateReviewPolicy"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/reviews":{"get":{"description":"The human Approvals queue: pending reviews across ALL the tenant's inboxes, newest-first and paginated, each with an intent summary + a body snippet (never the full body). Filter by state (repeatable / comma-separated), inbox, and category_id. Customer-scoped to the Clerk session; these human-authority reads/actions are console-only and never MCP tools (D17).\n","operationId":"adminListReviews","parameters":[{"description":"Filter by state (repeatable or comma-separated).","in":"query","name":"state","schema":{"type":"string"}},{"description":"Filter by composer inbox address.","in":"query","name":"inbox","schema":{"type":"string"}},{"description":"Filter by opaque category id (cat_…).","in":"query","name":"category_id","schema":{"type":"string"}},{"$ref":"#/components/parameters/Limit"},{"description":"Opaque page cursor.","in":"query","name":"page","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminReviewPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"Approvals queue (Review Loop, console plane)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","reviews"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/reviews/stream":{"get":{"description":"The live human Approvals feed: a `text/event-stream` of `review.*` events across EVERY inbox the org owns, sourced from the SAME monotonic event journal the agent-plane stream tails; so both planes read one event log (spec §6). Authenticated by REDEEMING the single-use `ticket` query parameter (created via POST /v1/admin/realtime/ticket), because a browser EventSource cannot set a bearer header. Each frame's `id:` is a monotonic resume token: on reconnect, pass it as `Last-Event-ID` (or the `last_event_id` query param) and the server replays every review event after it. The console applies a RealtimeEventDeduper keyed on this id so a replay-on-reconnect never double-applies. Customer-scoped to the ticket; no cross-tenant leak.\n","operationId":"adminStreamReviews","responses":{"200":{"content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/StreamEvent"}}},"description":"An open SSE stream of review.* events."},"401":{"$ref":"#/components/responses/Unauthorized"}},"summary":"Live Approvals queue stream (console plane, Server-Sent Events)","tags":["admin"],"x-fern-ignore":true},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"description":"Single-use ticket from POST /v1/admin/realtime/ticket.","in":"query","name":"ticket","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/LastEventID"},{"$ref":"#/components/parameters/LastEventIDQuery"}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/reviews/{id}":{"get":{"description":"The full review for the console detail view: intent, the current draft (subject/body), the append-only thread turns, and the diff if the draft was revised. Customer-scoped; a foreign id is 404 (no cross-tenant leak).\n","operationId":"adminGetReview","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminReviewDetail"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Get one review (intent + current draft + turns + diff)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","reviews"],"x-fern-sdk-method-name":"get"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/reviews/{id}/approve":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"Approve the draft as-is under the revision+version CAS (D17), with the staleness check run INSIDE approve (a stale draft 409s; reconfirm first). The platform then performs the authenticated send using the COMPOSER's inbox credentials (credential boundary) and records terminal success, returning the sent message id + thread id. The send is irreversible once returned.\n","operationId":"adminApproveReview","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminReviewAction"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminReviewSendResult"}}},"description":"Approved and sent."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"ClerkSession":[]}],"summary":"Approve a draft and send it (human authority)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","reviews"],"x-fern-sdk-method-name":"approve"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/reviews/{id}/chat":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"The console chat side-panel (M5; spec §5.3, §10): a human_comment turn whose OTHER party is the COMPOSING agent; it enqueues a feedback_added durable nudge to the composer (the agent wakes to answer/redraft) and emits a review.chat event; when the draft is in_review it flips to chatting. CONSOLE-ONLY (Clerk- authed); NEVER an MCP tool (D17). $0 LLM; the human writes the comment.\n","operationId":"adminReviewChat","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminReviewChatRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"review_id":{"type":"string"},"state":{"type":"string"},"status":{"type":"string"}},"type":"object"}}},"description":"Comment posted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"ClerkSession":[]}],"summary":"Post a human comment on a review's chat thread (console side-panel)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","reviews"],"x-fern-sdk-method-name":"chat"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/reviews/{id}/edit-send":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"The human supplies an edited subject/body. The platform captures the proposed-vs-sent diff into a system_diff turn (deterministic Go diff, $0 LLM), approves under the revision+version CAS, then performs the authenticated send of the EDITED content via the COMPOSER's inbox and records terminal success. Irreversible once returned; a stale draft or CAS race 409s.\n","operationId":"adminEditSendReview","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminReviewAction"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminReviewSendResult"}}},"description":"Edited, diffed, and sent."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"ClerkSession":[]}],"summary":"Edit a draft, capture the diff, and send (human authority)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","reviews"],"x-fern-sdk-method-name":"editSend"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/reviews/{id}/reject":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"Reject the draft under the revision+version CAS, with an optional feedback comment persisted as the raw rule-birth signal (D7; empty allowed). The composing agent may redraft from rejected. Console-only.\n","operationId":"adminRejectReview","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminReviewAction"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminReviewRejectResult"}}},"description":"Rejected."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"ClerkSession":[]}],"summary":"Reject a draft (human authority)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","reviews"],"x-fern-sdk-method-name":"reject"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/risk-dial":{"get":{"description":"Read the effective brand-risk dial; the account-wide default plus every category's per-category overrides (each with its resolved effective value; null override = inherit, D12). The agent-plane read (GET /v1/risk-dial) is AgentKey-only, so the console reads the SAME view here (Clerk session) to render the risk-dial panel. Read-only; setting the dial is the PATCH above.\n","operationId":"adminGetRiskDial","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RiskDial"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"Read the effective risk dial (console plane)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects"],"x-fern-sdk-method-name":"getRiskDial"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}],"patch":{"description":"Set the account-wide risk-dial defaults every inheriting category uses (D4): min_confidence, first_contact_gate, drift_demote_after (K), canary_rate, graduate_min_approvals, graduate_min_age_hours, auto_send_cap_per_day. A nil field is unchanged. Console-only (never an MCP tool, D17).\n","operationId":"adminUpdateRiskDial","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RiskDialRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountRiskDial"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"Set the account-default risk dial (console plane, human authority)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects"],"x-fern-sdk-method-name":"updateRiskDial"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/rules":{"get":{"description":"Read the §7 precedence-ordered effective writing-rule stack for the resolved org/project (and optional category), applied SERVER-SIDE (deterministic, NO LLM). The agent-plane read (GET /v1/rules) is AgentKey-only, so the console reads the SAME ordered list here (Clerk session) for its rules panel.\n","operationId":"adminGetRules","parameters":[{"description":"Category id (cat_…). Empty returns ONLY the house-style/general layer.","in":"query","name":"category_id","schema":{"type":"string"}},{"description":"Narrow to one layer (general | category). Default returns both.","in":"query","name":"scope","schema":{"enum":["general","category"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RulePage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Read the effective rule stack (console plane)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","rules"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/rules/audit":{"get":{"description":"The human-facing change/undo audit log spanning rules AND categories (D11), optionally narrowed to one entity. Console-only (Clerk-authed); the safety net for the shared/house-style rule governance. Undo a row via POST /v1/admin/rules/audit/{udo_id}/undo.\n","operationId":"adminGetRuleAudit","parameters":[{"description":"Narrow to one entity kind.","in":"query","name":"entity_kind","schema":{"enum":["rule","category"],"type":"string"}},{"description":"Narrow to one entity (rule_… or cat_…).","in":"query","name":"entity_id","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuleAuditPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"Read the rule/category change audit log (console plane)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","rules","audit"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/rules/audit/{udo_id}/undo":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"udo_id","required":true,"schema":{"type":"string"}}],"post":{"description":"Restore the prior version recorded in an audit row with author_kind=human (D11). UNDO = a forward 'restore' supersession; the source row is marked undone. Idempotent: a re-undo of an already-undone row is a clean 409. Console-only.\n","operationId":"adminUndoRuleChange","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rule"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"ClerkSession":[]}],"summary":"Undo a rule change (console plane, human authority)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","rules","audit"],"x-fern-sdk-method-name":"undo"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/threads":{"get":{"description":"Uses bounded per-inbox fan-out, tags each thread with its inbox, and merges them newest-first with a stable global keyset cursor.","operationId":"listSharedInboxThreads","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUnifiedThreadFeed"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"description":"A mailbox or thread exceeds a documented traversal safety limit."}},"security":[{"ClerkSession":[]}],"summary":"Shared-inbox feed; recent threads across every org inbox","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","threads"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/projects/{project_id}/webhooks":{"get":{"operationId":"adminListWebhooks","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"List project webhooks","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","webhooks"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"adminRegisterWebhook","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminRegisterWebhookRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}},"description":"Registered. `secret` is shown once."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Register a project webhook","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","webhooks"],"x-fern-sdk-method-name":"create"}},"/v1/admin/orgs/{org_id}/projects/{project_id}/webhooks/{id}":{"delete":{"operationId":"adminDeleteWebhook","responses":{"204":{"description":"deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Delete a project webhook","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","webhooks"],"x-fern-sdk-method-name":"delete"},"get":{"operationId":"adminGetWebhook","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Get one project webhook","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","webhooks"],"x-fern-sdk-method-name":"get"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"patch":{"operationId":"adminUpdateWebhook","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}},"description":"Updated (secret redacted)."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Update a project webhook","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","projects","webhooks"],"x-fern-sdk-method-name":"update"}},"/v1/admin/orgs/{org_id}/reputation":{"get":{"description":"Read-only deliverability rollup for the org (viewer): status badge, per- provider/tenant sending status, latest metrics window, open-finding count.\n","operationId":"adminGetReputation","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReputationRollup"}}},"description":"The org reputation rollup."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"The org's deliverability rollup (console)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","reputation"],"x-fern-sdk-method-name":"get"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/reputation/findings":{"get":{"description":"The org's deliverability findings, newest-first (viewer). Supports ?status=, ?severity=, ?domain=, ?sender= filters and limit/cursor paging.\n","operationId":"adminListReputationFindings","parameters":[{"in":"query","name":"status","schema":{"enum":["open","resolved"],"type":"string"}},{"in":"query","name":"severity","schema":{"enum":["low","high","unknown"],"type":"string"}},{"in":"query","name":"domain","schema":{"type":"string"}},{"in":"query","name":"sender","schema":{"type":"string"}},{"$ref":"#/components/parameters/Limit"},{"in":"query","name":"cursor","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReputationFindingsPage"}}},"description":"A page of deliverability findings."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"List the org's deliverability findings (console)","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","reputation"],"x-fern-sdk-method-name":"listFindings"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/settings":{"get":{"operationId":"getOrgSettings","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgSettings"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"ClerkSession":[]}],"summary":"Get the org's console settings","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","settings"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}],"patch":{"operationId":"updateOrgSettings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchOrgSettingsRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgSettings"}}},"description":"Updated settings."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"ClerkSession":[]}],"summary":"Update a subset of the org's console settings","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","settings"],"x-fern-sdk-method-name":"update"}},"/v1/admin/orgs/{org_id}/suppressions":{"get":{"description":"The org's recipient opt-out (suppression) rows, newest-first. Only org-scope rows are visible; global/shared-domain rows are operator-only. Supports ?recipient=, ?scope=, ?include_revoked=true, and limit/cursor paging.\n","operationId":"adminListSuppressions","parameters":[{"description":"Filter by (canonicalized) recipient.","in":"query","name":"recipient","schema":{"type":"string"}},{"in":"query","name":"scope","schema":{"enum":["org"],"type":"string"}},{"in":"query","name":"include_revoked","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/Limit"},{"in":"query","name":"cursor","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuppressionPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"List / search the org's suppression rows","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","suppressions"],"x-fern-sdk-method-name":"list"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/suppressions/export":{"get":{"description":"A CSV of the org's suppression rows (viewer). ?include_revoked=true adds soft-revoked rows; ?recipient= / ?scope= narrow the export.\n","operationId":"adminExportSuppressions","parameters":[{"in":"query","name":"recipient","schema":{"type":"string"}},{"in":"query","name":"scope","schema":{"enum":["org"],"type":"string"}},{"in":"query","name":"include_revoked","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"text/csv":{"schema":{"type":"string"}}},"description":"CSV export."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"ClerkSession":[]}],"summary":"Export the org's suppression rows as CSV","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","suppressions"],"x-fern-sdk-method-name":"export"},"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}}]},"/v1/admin/orgs/{org_id}/suppressions/{id}/revoke":{"parameters":[{"in":"path","name":"org_id","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"An org admin (role \u003e= admin) revokes ONE org-scope row with a REQUIRED reason (audit-logged). A foreign/global/shared id is a 404; an empty reason is a 400.\n","operationId":"adminRevokeSuppression","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokeSuppressionRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Suppression"}}},"description":"The revoked row."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Revoke (un-suppress) one org-scope suppression row","tags":["admin"],"x-fern-sdk-group-name":["admin","orgs","suppressions"],"x-fern-sdk-method-name":"revoke"}},"/v1/admin/signup-claims/{claim_id}/accept":{"parameters":[{"in":"path","name":"claim_id","required":true,"schema":{"type":"string"}}],"post":{"description":"Accepts a live system-seeded owner claim previously discovered through GET /v1/admin/me. IDENTITY-ONLY: the claim id is only a selector and the server accepts it only when its normalized email matches the authenticated user's VERIFIED Clerk email. No raw invitation token is required or exposed.\n","operationId":"acceptSignupClaim","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgInvitation"}}},"description":"Accepted (owner membership written)."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ClerkSession":[]}],"summary":"Claim an agent-created account (identity-only; email-bound)","tags":["admin"],"x-fern-sdk-group-name":["admin","signupClaims"],"x-fern-sdk-method-name":"accept"}},"/v1/agent/sign-up":{"post":{"description":"When the operational gate is enabled, provisions (or idempotently re-provisions) a free account and a first inbox on `free.extrovertmail.com`, returns a limited-permission agent key that expires with the emailed verification code, and sends that code to `human_email`. Call `POST /v1/agent/verify` to activate the account and atomically exchange the bootstrap key for a full-permission key. Before verification, that key may call verification only and the account cannot send. The OTP is never returned in the body. Free signup is currently disabled in production.\n","operationId":"signUp","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignUpRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignUpResult"}}},"description":"Account created; verification code emailed."},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Free signup is temporarily paused (`signup_disabled`)."},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Self-signup is not configured or the signup gate is unavailable."}},"security":[],"summary":"Self-signup for a free account + first inbox","tags":["enrollment"],"x-fern-sdk-group-name":["agent"],"x-fern-sdk-method-name":"signUp"}},"/v1/agent/verify":{"post":{"description":"Requires the verification-only `signup:verify` key. Atomically revokes it and returns a new full-permission key, activates the free account and its `free.extrovertmail.com` inbox, and returns copy-ready MCP read_messages/get_message/wait_for_email calls on success.\n","operationId":"verify","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyResult"}}},"description":"Verified; full-permission key issued."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Free signup verification is temporarily paused (`signup_disabled`)."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Signup availability could not be determined (`signup_gate_unavailable`)."}},"security":[{"AgentKey":["signup:verify"]}],"summary":"Verify a signup code and upgrade to a full-permission key","tags":["enrollment"],"x-fern-sdk-group-name":["agent"],"x-fern-sdk-method-name":"verify"}},"/v1/auth/me":{"get":{"description":"Requires only a valid key (any scope), so an agent can always read its own authority.","operationId":"whoami","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WhoAmI"}}},"description":"The verified principal."},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"AgentKey":[]}],"summary":"Introspect the principal behind the agent key","tags":["enrollment"],"x-fern-sdk-group-name":["auth"],"x-fern-sdk-method-name":"me"}},"/v1/billing/stripe/webhook":{"post":{"description":"Unauthenticated by bearer token. Stripe authenticates requests with the `Stripe-Signature` HMAC header; invalid signatures are rejected before event parsing or persistence.\n","operationId":"stripeBillingWebhook","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeWebhookAck"}}},"description":"accepted"},"400":{"$ref":"#/components/responses/BadRequest"},"503":{"$ref":"#/components/responses/NotConfigured"}},"summary":"Receive Stripe billing webhooks","tags":["billing"]}},"/v1/categories":{"get":{"description":"List the customer's categories (id + name + description + scope + state) so a sending agent can fuzzy-match an existing one before composing. The optional `match` is a pure lexical/substring filter (NO LLM on our side); the agent does the semantic matching. Categories are CUSTOMER-scoped and agent- attributed (the deliberate cross-agent-404 exception); identity is opaque cat_ ids (D10).\n","operationId":"listCategories","parameters":[{"description":"Lexical substring filter over name+description+slug (every token must match; NO LLM).","in":"query","name":"match","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Browse the category registry (Review Loop, agent plane)","tags":["categories"],"x-fern-sdk-group-name":["categories"],"x-fern-sdk-method-name":"list"},"post":{"description":"Create a category on the fly (D9). It stands IMMEDIATELY (author_kind=agent, state supervised) and writes a create audit/undo row. Returns the cat_…; match the registry first so you do not duplicate an existing bucket.\n","operationId":"proposeCategory","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProposeCategoryRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}},"description":"Created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Propose a new category (agent plane)","tags":["categories"],"x-fern-sdk-group-name":["categories"],"x-fern-sdk-method-name":"create"}},"/v1/categories/{id}":{"get":{"operationId":"getCategory","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Get one category (agent plane)","tags":["categories"],"x-fern-sdk-group-name":["categories"],"x-fern-sdk-method-name":"get"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"put":{"description":"Update a category's name and/or description; metadata ONLY (D10). Renaming never breaks a reference because nothing keys on the name. Any agent in the customer may edit (the shared-registry exception); a rename/redescribe undo row is written (the audit/undo safety net, D11).\n","operationId":"updateCategory","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCategoryRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Rename / re-describe a category (agent plane, metadata only)","tags":["categories"],"x-fern-sdk-group-name":["categories"],"x-fern-sdk-method-name":"update"}},"/v1/categories/{id}/backlog-status":{"get":{"description":"Read a $0-LLM, non-mutating snapshot of the category's QUEUED drafts reconciled by rules-version (D19/§8): how many are stale vs current-enough against the current category rules-version + house-style version (a pure integer compare). Read-only; an agent READS the picture; the human (console scan-backlog) or the graduate/rule-change hooks TRIGGER the actual reconciliation sweep. A foreign id is 404.\n","operationId":"getScanBacklogStatus","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanBacklogStatus"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Read the D19 backlog-reconciliation status (agent plane)","tags":["categories"],"x-fern-sdk-group-name":["categories"],"x-fern-sdk-method-name":"getBacklogStatus"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}]},"/v1/categories/{id}/graduation-request":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"RECORD an agent's request to graduate this category (D16/D6). It writes a durable, NON-MUTATING request transition (evidence for the human to review) and returns the current graduation gate status. It does NOT change the category state; flipping the graduation bit is a human (console) action. A never_graduate category records the request but stays locked. A foreign id is 404.\n","operationId":"proposeGraduation","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProposeGraduationRequest"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraduationStatus"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Propose graduating a category (agent plane; cannot flip the bit)","tags":["categories"],"x-fern-sdk-group-name":["categories"],"x-fern-sdk-method-name":"graduationRequest"}},"/v1/categories/{id}/graduation-status":{"get":{"description":"Report the gates a category has passed / still needs toward the NEXT rung (supervised→auto_notify→auto_silent): clean approvals (N / needed), category age, the maturity gate (D16, required for auto_silent), the drift counter vs K, and whether a human graduate would succeed right now (can_graduate). Read-only; an agent proposes graduation via graduation-request but never flips the bit. A foreign id is 404.\n","operationId":"getGraduationStatus","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraduationStatus"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Read a category's graduation gate status (agent plane)","tags":["categories"],"x-fern-sdk-group-name":["categories"],"x-fern-sdk-method-name":"getGraduationStatus"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}]},"/v1/categories/{id}/pacing-state":{"get":{"description":"Read a $0-LLM, non-mutating snapshot of the category's demand-driven pacing (M7 Slice B/§8): the human review cursor position, the effective window/ceiling/ interval, the queued count, and each queued draft's in-window/redrafting/ behind-cursor classification. Read-only; the cursor advances from the human's console approve/reject/edit actions. A foreign id is 404.\n","operationId":"getCategoryPacingState","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryPacingState"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Read the demand-driven pacing state for a category (agent plane)","tags":["categories"],"x-fern-sdk-group-name":["categories"],"x-fern-sdk-method-name":"getPacingState"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}]},"/v1/commerce/domain-quotes":{"post":{"operationId":"quoteDomain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainQuoteRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainQuote"}}},"description":"Current time-limited quote"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["commerce:request"]}],"summary":"Quote a new domain without purchasing it","tags":["commerce"],"x-fern-sdk-group-name":["commerce"],"x-fern-sdk-method-name":"quoteDomain"}},"/v1/commerce/requests":{"get":{"operationId":"listCommerceRequests","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceRequestPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["commerce:request"]}],"summary":"List this agent's commerce requests","tags":["commerce"],"x-fern-sdk-group-name":["commerce"],"x-fern-sdk-method-name":"listRequests"}},"/v1/commerce/requests/domain-purchases":{"post":{"operationId":"requestDomainPurchase","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainPurchaseRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceRequest"}}},"description":"Request recorded"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["commerce:request"]}],"summary":"Request a domain purchase without granting approval or spending","tags":["commerce"],"x-fern-sdk-group-name":["commerce"],"x-fern-sdk-method-name":"requestDomainPurchase"}},"/v1/commerce/requests/plan-changes":{"post":{"operationId":"requestPlanChange","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanChangeRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceRequest"}}},"description":"Request recorded"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["commerce:request"]}],"summary":"Request a plan change for human approval","tags":["commerce"],"x-fern-sdk-group-name":["commerce"],"x-fern-sdk-method-name":"requestPlanChange"}},"/v1/commerce/requests/{request_id}":{"get":{"operationId":"getCommerceRequest","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceRequest"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["commerce:request"]}],"summary":"Get one commerce request and its exact blocker or progress","tags":["commerce"],"x-fern-sdk-group-name":["commerce"],"x-fern-sdk-method-name":"getRequest"},"parameters":[{"in":"path","name":"request_id","required":true,"schema":{"type":"string"}}]},"/v1/commerce/requests/{request_id}/cancel":{"parameters":[{"in":"path","name":"request_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"cancelCommerceRequest","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceRequest"}}},"description":"Cancelled"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"AgentKey":["commerce:request"]}],"summary":"Cancel an uncommitted commerce request","tags":["commerce"],"x-fern-sdk-group-name":["commerce"],"x-fern-sdk-method-name":"cancelRequest"}},"/v1/domains":{"get":{"description":"List the onboarded domains for the agent's customer (newest-first, paginated), each with its onboarding mode and verification/DKIM status. The customer/tenant is derived from the agent key.\n","operationId":"listDomains","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentDomainList"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["domain:manage"]}],"summary":"List the customer's domains and their status","tags":["domains"],"x-fern-sdk-group-name":["domains"],"x-fern-sdk-method-name":"list"},"post":{"description":"Add a domain the customer controls. `ns_delegated` is the default: the customer publishes the returned nameserver records and Extrovert serves the inbox domain's mail zone. The legacy `purchased` intent creates a commerce request and cannot charge or register until human or pre-authorized policy approval; use `/v1/commerce/requests/domain-purchases` for its canonical response. `ns_delegated` needs `domain:manage` only. `scope` chooses the domain's visibility (`org` shared by default, or `project` bound to the key's project).\n","operationId":"onboardDomain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardAgentDomainRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/AgentDomain"},{"$ref":"#/components/schemas/CommerceRequest"}]}}},"description":"Connected; returns the nameserver records for delegated setup."},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceRequest"}}},"description":"Legacy purchased intent recorded as a commerce request."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"AgentKey":["domain:manage"]}],"summary":"Add a delegated or purchased domain","tags":["domains"],"x-fern-sdk-group-name":["domains"],"x-fern-sdk-method-name":"create"}},"/v1/domains/{domain}":{"delete":{"description":"Accept an offboard for a domain and enqueue the full teardown job: it reaps the live outbound provider sender identities and the outbound_* routing rows, then scrubs the DNS zone/records and the domain row. Returns 202 with a job id and a poll URL (`status_url`); poll `GET /v1/jobs/{job_id}` until the status is terminal (succeeded/failed/cancelled). Idempotent; a repeat DELETE dedupes onto the same teardown job. New mailboxes can no longer be created on the domain; mailboxes already created are untouched at the mail layer.\n","operationId":"offboardDomain","responses":{"202":{"content":{"application/json":{"schema":{"properties":{"job_id":{"type":"string"},"object":{"example":"domain_offboard","type":"string"},"status":{"type":"string"},"status_url":{"example":"/v1/jobs/job-…","type":"string"}},"required":["object","job_id","status","status_url"],"type":"object"}}},"description":"Offboard accepted; poll the returned job for completion."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["domain:manage"]}],"summary":"Offboard (remove) a domain from the customer","tags":["domains"],"x-fern-sdk-group-name":["domains"],"x-fern-sdk-method-name":"delete"},"get":{"description":"Fetch one of the customer's domains: its verification/DKIM status and the nameserver records to publish for delegated setup (`delegation_ns`). Tenant-scoped: another customer's (or an unknown) domain is a 404.\n","operationId":"getDomain","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentDomain"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["domain:manage"]}],"summary":"Get one domain's detail, status, and nameserver records","tags":["domains"],"x-fern-sdk-group-name":["domains"],"x-fern-sdk-method-name":"get"},"parameters":[{"$ref":"#/components/parameters/Domain"}]},"/v1/domains/{domain}/verify":{"parameters":[{"$ref":"#/components/parameters/Domain"}],"post":{"description":"Trigger/refresh verification for an onboarded domain and return the (possibly advanced) detail. For `purchased` domains this re-drives the resumable, money-safe buy/verify/connect pipeline; for `ns_delegated` it re-reads the current status and returns the nameserver records the customer still needs to publish. Idempotent.\n","operationId":"verifyDomain","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentDomain"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["domain:manage"]}],"summary":"Trigger or refresh verification for a domain","tags":["domains"],"x-fern-sdk-group-name":["domains"],"x-fern-sdk-method-name":"verify"}},"/v1/enroll":{"post":{"description":"Validates the token (not revoked/expired/exhausted) and creates a permissioned agent key bound to an agent. Idempotent on `agent_handle`. Also accepts a client-supplied idempotency key (`Idempotency-Key` header or `client_id` body field) to replay the original response on retry.\n","operationId":"enroll","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollResult"}}},"description":"Agent key created (shown once)."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/IdempotencyConflict"}},"security":[],"summary":"Redeem an enrollment token for an agent key","tags":["enrollment"],"x-fern-sdk-group-name":["enroll"],"x-fern-sdk-method-name":"create"}},"/v1/events":{"get":{"description":"Like the inbox-scoped stream, but emits events across EVERY inbox the agent owns. Same `text/event-stream` envelope and `Last-Event-ID` resume contract. This stream also backs human-in-the-loop (HITL) events.\n","operationId":"streamEvents","responses":{"200":{"content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/StreamEvent"}}},"description":"An open SSE stream of events."},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Stream events across all of the agent's inboxes (Server-Sent Events)","tags":["messaging"],"x-fern-ignore":true},"parameters":[{"$ref":"#/components/parameters/LastEventID"},{"$ref":"#/components/parameters/LastEventIDQuery"}]},"/v1/inboxes":{"get":{"description":"Lists inboxes visible to the key. It never returns passwords or portable credentials.","operationId":"listInboxes","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/PageToken"}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"inboxes":{"items":{"$ref":"#/components/schemas/Inbox"},"type":"array"},"next_page":{"type":"string"}},"type":"object"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"List the agent's inboxes","tags":["inboxes"],"x-fern-ignore":true},"post":{"description":"Create an inbox. Accepts a client-supplied idempotency key (`Idempotency-Key` header or `client_id` body field): a retry with the same key returns the existing inbox; the same key with a different body is a 409.\n","operationId":"createInbox","parameters":[{"description":"When the paid-inbox feature flag is on, requests the x402 payment path (HTTP 402).","in":"query","name":"paid","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInboxRequest"}}}},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Inbox"}}},"description":"Created. `password` is shown once."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"x402 payment required (feature-flagged)."},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/IdempotencyConflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"AgentKey":["mailbox:create"]}],"summary":"Create an inbox","tags":["inboxes"],"x-fern-ignore":true}},"/v1/inboxes/{inbox_id}":{"delete":{"operationId":"deleteInbox","responses":{"204":{"description":"deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:delete"]},{"AgentKey":["mailbox:create"]}],"summary":"Delete an inbox (tears down the mailbox + authenticated sender)","tags":["inboxes"],"x-fern-ignore":true},"get":{"operationId":"getInbox","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Inbox"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Get an inbox","tags":["inboxes"],"x-fern-ignore":true},"parameters":[{"$ref":"#/components/parameters/InboxID"}],"patch":{"description":"Update cheap inbox metadata (e.g. the sender display name) without delete+recreate. Owner-scoped: a cross-tenant or cross-agent target is a 404. Returns the updated inbox.\n","operationId":"updateInbox","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateInboxRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Inbox"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:create","mailbox:read"]},{"AgentKey":["mailbox:quota","mailbox:read"]}],"summary":"Update an inbox (rename the sender identity / metadata in place)","tags":["inboxes"],"x-fern-ignore":true}},"/v1/inboxes/{inbox_id}/credentials":{"get":{"description":"Paid-plan only. Re-checks ownership and unseals the mailbox password so an agent can configure a real mail client.","operationId":"getInboxCredentials","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxCredentials"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:credentials"]}],"summary":"Get IMAP/SMTP connection settings + login for an owned mailbox","tags":["inboxes"],"x-fern-ignore":true},"parameters":[{"$ref":"#/components/parameters/InboxID"}]},"/v1/inboxes/{inbox_id}/lists":{"get":{"description":"List the allow/block entries that govern this inbox: the inbox-specific entries plus any account-wide entries.\n","operationId":"listContactListEntries","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactListPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"List the contact-list entries governing an inbox","tags":["messaging"],"x-fern-ignore":true},"parameters":[{"$ref":"#/components/parameters/InboxID"}],"post":{"description":"Add one allow/block entry (address or domain) to this inbox's contact lists. A `block` entry rejects a matching recipient on send; when any `allow` entry exists, sends from this inbox are restricted to recipients that match one of them (allowlist mode). Account-wide entries (registered on any inbox the agent owns) also apply.\n","operationId":"addContactListEntry","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddContactListRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactListEntry"}}},"description":"Created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Add an allow/block entry to an inbox's contact lists","tags":["messaging"],"x-fern-ignore":true}},"/v1/inboxes/{inbox_id}/lists/{id}":{"delete":{"operationId":"deleteContactListEntry","responses":{"204":{"description":"deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Delete a contact-list entry by id","tags":["messaging"],"x-fern-ignore":true},"parameters":[{"$ref":"#/components/parameters/InboxID"},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}]},"/v1/inboxes/{inbox_id}/messages":{"get":{"operationId":"listMessages","parameters":[{"$ref":"#/components/parameters/Folder"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Offset"},{"description":"Filter on From.","in":"query","name":"from","schema":{"type":"string"}},{"description":"Filter on To.","in":"query","name":"to","schema":{"type":"string"}},{"description":"Filter on Subject.","in":"query","name":"subject","schema":{"type":"string"}},{"description":"Unread-only when \"true\".","in":"query","name":"unread","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagePage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"List messages in an inbox","tags":["messaging"],"x-fern-ignore":true},"parameters":[{"$ref":"#/components/parameters/InboxID"}]},"/v1/inboxes/{inbox_id}/messages/batch":{"parameters":[{"$ref":"#/components/parameters/InboxID"}],"patch":{"description":"Mark read/unread and/or move folder for a list of message ids that all belong to this inbox. At least one of `read` / `folder` must be set. Partial failures (an id that is malformed or not owned by this inbox) are reported in `failed` rather than failing the whole batch. A folder move additionally requires the mailbox:create (or :delete) scope.\n","operationId":"batchUpdateMessages","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchUpdateMessagesRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchUpdateResult"}}},"description":"Per-id outcome."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Batch update messages (mark read/unread and/or move folder)","tags":["messaging"],"x-fern-ignore":true}},"/v1/inboxes/{inbox_id}/messages/search":{"get":{"operationId":"searchMessages","parameters":[{"description":"Search query (required).","in":"query","name":"q","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Folder"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Offset"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagePage"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Full-text search messages in an inbox","tags":["messaging"],"x-fern-ignore":true},"parameters":[{"$ref":"#/components/parameters/InboxID"}]},"/v1/inboxes/{inbox_id}/messages/{id}":{"delete":{"description":"Move a message to the Trash folder (a recoverable soft delete). Pass `?expunge=true` to permanently remove it instead. A message already in Trash is always expunged. Requires mailbox:read plus mailbox:create (or mailbox:delete); the owning agent's default key carries both capabilities.\n","operationId":"deleteMessage","parameters":[{"description":"Permanently remove instead of moving to Trash.","in":"query","name":"expunge","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResult"}}},"description":"Delete outcome."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read","mailbox:delete"]},{"AgentKey":["mailbox:read","mailbox:create"]}],"summary":"Delete a message (move to Trash, or expunge)","tags":["messaging"],"x-fern-ignore":true},"parameters":[{"$ref":"#/components/parameters/InboxID"},{"$ref":"#/components/parameters/MessageID"}],"patch":{"operationId":"markMessage","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkMessageRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}},"description":"The updated message."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Mark a message read or unread","tags":["messaging"],"x-fern-ignore":true}},"/v1/inboxes/{inbox_id}/messages/{id}/attachments":{"get":{"operationId":"listAttachments","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachmentPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"List a message's attachment metadata","tags":["attachments"],"x-fern-ignore":true},"parameters":[{"$ref":"#/components/parameters/InboxID"},{"$ref":"#/components/parameters/MessageID"}]},"/v1/inboxes/{inbox_id}/messages/{id}/attachments/{attId}":{"get":{"operationId":"getAttachment","responses":{"200":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}},"description":"The attachment bytes (Content-Type + Content-Disposition set)."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Download one attachment's bytes","tags":["attachments"],"x-fern-ignore":true},"parameters":[{"$ref":"#/components/parameters/InboxID"},{"$ref":"#/components/parameters/MessageID"},{"$ref":"#/components/parameters/AttachmentID"}]},"/v1/inboxes/{inbox_id}/messages/{id}/forward":{"parameters":[{"$ref":"#/components/parameters/InboxID"},{"$ref":"#/components/parameters/MessageID"}],"post":{"description":"Forward an existing message to new recipients. The subject and the quoted parent are materialized at SUBMIT time, so a queued forward shows the human the exact forwarded content and an approved forward delivers the reviewer's edit rather than a body re-derived from the live parent. A forward carries no `In-Reply-To`: its recipients were never part of the parent conversation.\nThe resolved account/inbox review policy is authoritative on every send. Omitting fields does not bypass it. Read `effective_review_policy` on `GET /v1/inboxes/{inbox_id}` to know which branch you are on:\n- `require_review` (the default for every account): a request WITHOUT an\n  `intent` is rejected with `422 intent_required`. Nothing is sent or queued.\n  A request WITH an intent returns `202 queued_for_review`. Then monitor the\n  review until you receive a `sent` or `send_failed` review event.\n- `allow_direct`: a bare request (no mode/intent/category_id) still sends\n  immediately and returns the legacy `202` body, now plus `review_id`.\n  Supplying an intent or `mode: review` queues it for a human.\n- `auto_send_graduated`: a categorized message that clears the graduation\n  gates auto-sends; everything else is queued.\n\nContact lists, list-unsubscribe suppression and the billing quota are all enforced at SUBMIT time, so a rejected recipient fails fast rather than after a human has already approved the draft.\nForward uses the same review policy as send. Any other behavior would create a bypass, especially because it exfiltrates a received thread.\n","operationId":"forwardMessage","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForwardRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentResult"}}},"description":"Sent immediately (policy-permitted direct or graduated path)."},"202":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/QueuedForReviewResult"},{"$ref":"#/components/schemas/SendResult"}]}}},"description":"Accepted; either queued for review or accepted for delivery."},"400":{"$ref":"#/components/responses/SendBadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/ReviewConflict"},"422":{"$ref":"#/components/responses/SendUnprocessable"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"AgentKey":["mailbox:send"]}],"summary":"Forward a message to new recipients","tags":["messaging"],"x-fern-ignore":true}},"/v1/inboxes/{inbox_id}/messages/{id}/raw":{"get":{"operationId":"getRawMessage","responses":{"200":{"content":{"message/rfc822":{"schema":{"format":"binary","type":"string"}}},"description":"The full message source."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Download the raw RFC822 (.eml) bytes of a message","tags":["messaging"],"x-fern-ignore":true},"parameters":[{"$ref":"#/components/parameters/InboxID"},{"$ref":"#/components/parameters/MessageID"}]},"/v1/inboxes/{inbox_id}/reply":{"parameters":[{"$ref":"#/components/parameters/InboxID"}],"post":{"description":"Reply in-thread. Recipients, subject and threading headers are derived from the parent at SUBMIT time, so a queued reply shows the human the real envelope and the pre-flight screens the real recipients.\nThe resolved account/inbox review policy is authoritative on every send. Omitting fields does not bypass it. Read `effective_review_policy` on `GET /v1/inboxes/{inbox_id}` to know which branch you are on:\n- `require_review` (the default for every account): a request WITHOUT an\n  `intent` is rejected with `422 intent_required`. Nothing is sent or queued.\n  A request WITH an intent returns `202 queued_for_review`. Then monitor the\n  review until you receive a `sent` or `send_failed` review event.\n- `allow_direct`: a bare request (no mode/intent/category_id) still sends\n  immediately and returns the legacy `202` body, now plus `review_id`.\n  Supplying an intent or `mode: review` queues it for a human.\n- `auto_send_graduated`: a categorized message that clears the graduation\n  gates auto-sends; everything else is queued.\n\nContact lists, list-unsubscribe suppression and the billing quota are all enforced at SUBMIT time, so a rejected recipient fails fast rather than after a human has already approved the draft.\n","operationId":"replyMessage","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplyRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentResult"}}},"description":"Sent immediately (policy-permitted direct or graduated path)."},"202":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/QueuedForReviewResult"},{"$ref":"#/components/schemas/SendResult"}]}}},"description":"Accepted; either queued for review or accepted for delivery."},"400":{"$ref":"#/components/responses/SendBadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/ReviewConflict"},"422":{"$ref":"#/components/responses/SendUnprocessable"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"AgentKey":["mailbox:send"]}],"summary":"Reply in-thread (recipients + threading derived)","tags":["messaging"],"x-fern-ignore":true}},"/v1/inboxes/{inbox_id}/send":{"parameters":[{"$ref":"#/components/parameters/InboxID"}],"post":{"description":"Send a message.\nThe resolved account/inbox review policy is authoritative on every send. Omitting fields does not bypass it. Read `effective_review_policy` on `GET /v1/inboxes/{inbox_id}` to know which branch you are on:\n- `require_review` (the default for every account): a request WITHOUT an\n  `intent` is rejected with `422 intent_required`. Nothing is sent or queued.\n  A request WITH an intent returns `202 queued_for_review`. Then monitor the\n  review until you receive a `sent` or `send_failed` review event.\n- `allow_direct`: a bare request (no mode/intent/category_id) still sends\n  immediately and returns the legacy `202` body, now plus `review_id`.\n  Supplying an intent or `mode: review` queues it for a human.\n- `auto_send_graduated`: a categorized message that clears the graduation\n  gates auto-sends; everything else is queued.\n\nContact lists, list-unsubscribe suppression and the billing quota are all enforced at SUBMIT time, so a rejected recipient fails fast rather than after a human has already approved the draft.\n","operationId":"sendMessage","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentResult"}}},"description":"Sent immediately (policy-permitted direct or graduated path)."},"202":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/QueuedForReviewResult"},{"$ref":"#/components/schemas/StatusResult"}]}}},"description":"Accepted; either queued for review or accepted for delivery."},"400":{"$ref":"#/components/responses/SendBadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/ReviewConflict"},"422":{"$ref":"#/components/responses/SendUnprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"AgentKey":["mailbox:send"]}],"summary":"Send a message from the inbox (authenticated sender)","tags":["messaging"],"x-fern-ignore":true}},"/v1/inboxes/{inbox_id}/stream":{"get":{"description":"Watch one owned inbox live instead of polling wait. Returns a `text/event-stream` that emits a `message.received` event (and any other webhook event types) as each message arrives; sourced from the same new-inbound-message detection the webhook delivery engine uses. Each SSE frame's `id:` is a monotonic resume token: on reconnect, pass it as `Last-Event-ID` (or the `last_event_id` query param) and the server replays every event after it. Heartbeat comments keep the connection alive while idle. MCP cannot hold an open stream; call this endpoint directly (or use the SDK `stream`/`subscribe` helper).\n","operationId":"streamInbox","responses":{"200":{"content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/StreamEvent"}}},"description":"An open SSE stream of events."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Stream events for one inbox (Server-Sent Events)","tags":["messaging"],"x-fern-ignore":true},"parameters":[{"$ref":"#/components/parameters/InboxID"},{"$ref":"#/components/parameters/LastEventID"},{"$ref":"#/components/parameters/LastEventIDQuery"}]},"/v1/inboxes/{inbox_id}/threads":{"get":{"operationId":"listThreads","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"List conversation threads (newest-first)","tags":["messaging"],"x-fern-ignore":true},"parameters":[{"$ref":"#/components/parameters/InboxID"}]},"/v1/inboxes/{inbox_id}/threads/search":{"get":{"operationId":"searchThreads","parameters":[{"description":"Search query (required).","in":"query","name":"q","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadPage"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Full-text search conversation threads","tags":["messaging"],"x-fern-ignore":true},"parameters":[{"$ref":"#/components/parameters/InboxID"}]},"/v1/inboxes/{inbox_id}/threads/{id}":{"delete":{"description":"Remove every message in the thread (across all folders), moving them to the Trash folder (recoverable). Pass `?expunge=true` to permanently remove them. Requires mailbox:read plus mailbox:create (or mailbox:delete).\n","operationId":"deleteThread","parameters":[{"description":"Permanently remove instead of moving to Trash.","in":"query","name":"expunge","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResult"}}},"description":"Delete outcome (count = messages removed)."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read","mailbox:delete"]},{"AgentKey":["mailbox:read","mailbox:create"]}],"summary":"Delete a thread (every message; move to Trash or expunge)","tags":["messaging"],"x-fern-ignore":true},"get":{"operationId":"getThread","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadDetail"}}},"description":"The thread and its messages (oldest-first)."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"description":"Thread exceeds the 1,000-message detail safety limit."}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Get one thread with its messages","tags":["messaging"],"x-fern-ignore":true},"parameters":[{"$ref":"#/components/parameters/InboxID"},{"description":"Thread id.","in":"path","name":"id","required":true,"schema":{"type":"string"}}]},"/v1/inboxes/{inbox_id}/wait":{"parameters":[{"$ref":"#/components/parameters/InboxID"}],"post":{"description":"The killer primitive. Blocks (IMAP poll) until the next matching message arrives in this inbox or the timeout elapses, returning the message plus an extracted OTP code / verification link.\n","operationId":"waitForEmail","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitRequest"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitResult"}}},"description":"Matched or timed out."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Block until a matching message arrives (wait_for_email)","tags":["messaging"],"x-fern-ignore":true}},"/v1/jobs/{job_id}":{"get":{"description":"Poll the status of an async job the agent enqueued (currently the domain-offboard teardown returned by `DELETE /v1/domains/{domain}`). Status is terminal on `succeeded`, `failed`, or `cancelled`. Tenant-scoped: another customer's (or an unknown) job id is a 404.\n","operationId":"getJob","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"created_at":{"format":"date-time","type":"string"},"finished_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"object":{"example":"job","type":"string"},"status":{"type":"string"},"type":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["object","id","type","status","created_at","updated_at"],"type":"object"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["domain:manage"]}],"summary":"Poll an async job's status","tags":["jobs"],"x-fern-sdk-group-name":["jobs"],"x-fern-sdk-method-name":"get"},"parameters":[{"in":"path","name":"job_id","required":true,"schema":{"type":"string"}}]},"/v1/messages/{id}":{"get":{"operationId":"getMessage","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Get one message by id (owning inbox resolved from the id)","tags":["messaging"],"x-fern-sdk-group-name":["messages"],"x-fern-sdk-method-name":"get"},"parameters":[{"$ref":"#/components/parameters/MessageID"}]},"/v1/projects/{project_id}/inboxes":{"get":{"operationId":"listInboxesInProject","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/List"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"List inboxes in a project (or the org subtree with `-`)","tags":["inboxes"],"x-fern-sdk-group-name":["projects","inboxes"],"x-fern-sdk-method-name":"list"},"parameters":[{"description":"Project id, or `-` for the org-wide wildcard (org keys only).","in":"path","name":"project_id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"createInboxInProject","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInboxRequest"}}}},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Inbox"}}},"description":"Created. `password` is shown once."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/IdempotencyConflict"}},"security":[{"AgentKey":["mailbox:create"]}],"summary":"Create an inbox in a project","tags":["inboxes"],"x-fern-sdk-group-name":["projects","inboxes"],"x-fern-sdk-method-name":"create"}},"/v1/projects/{project_id}/inboxes/{inbox_id}":{"delete":{"operationId":"deleteInboxInProject","responses":{"204":{"description":"deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:delete"]},{"AgentKey":["mailbox:create"]}],"summary":"Delete an inbox in a project","tags":["inboxes"],"x-fern-sdk-group-name":["projects","inboxes"],"x-fern-sdk-method-name":"delete"},"get":{"operationId":"getInboxInProject","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Inbox"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Get an inbox in a project","tags":["inboxes"],"x-fern-sdk-group-name":["projects","inboxes"],"x-fern-sdk-method-name":"get"},"parameters":[{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/InboxID"}],"patch":{"operationId":"updateInboxInProject","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateInboxRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Inbox"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:create","mailbox:read"]},{"AgentKey":["mailbox:quota","mailbox:read"]}],"summary":"Update an inbox in a project","tags":["inboxes"],"x-fern-sdk-group-name":["projects","inboxes"],"x-fern-sdk-method-name":"update"}},"/v1/projects/{project_id}/inboxes/{inbox_id}/credentials":{"get":{"description":"Paid-plan only. Re-checks ownership before returning portable mail-client credentials.","operationId":"getInboxCredentialsInProject","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxCredentials"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:credentials"]}],"summary":"Get IMAP/SMTP settings for an inbox in a project","tags":["inboxes"],"x-fern-sdk-group-name":["projects","inboxes"],"x-fern-sdk-method-name":"credentials"},"parameters":[{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/InboxID"}]},"/v1/purchase":{"post":{"description":"Performs the x402 handshake: a request with no `X-PAYMENT` / `PAYMENT-SIGNATURE` header returns `402` with payment requirements; a signed retry runs verify → settle → provision. Only available when paid inboxes are enabled (otherwise `404`).\n","operationId":"purchaseInboxes","parameters":[{"description":"base64(JSON) of the signed EIP-3009 payload. `PAYMENT-SIGNATURE` is also accepted.","in":"header","name":"X-PAYMENT","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseRequest"}}}},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseResult"}}},"description":"Settled and provisioned."},"400":{"$ref":"#/components/responses/BadRequest"},"402":{"description":"Payment required (handshake step 1) or verify/settle failed."},"404":{"description":"Paid purchase is not enabled."},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"AgentKey":["mailbox:create"]}],"summary":"x402 paid purchase of one or more inboxes","tags":["inboxes"],"x-fern-sdk-group-name":["inboxes"],"x-fern-sdk-method-name":"purchase"}},"/v1/reputation":{"get":{"description":"Read-only deliverability status for the caller's own org: the derived status badge, per-provider/tenant sending status, the latest Sends/Bounces/Complaints window, and the open-finding count. Advisor findings degrade to `unavailable_vdm_disabled` when VDM is off. Strictly org-scoped.\n","operationId":"getReputation","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReputationRollup"}}},"description":"The org reputation rollup."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"The caller's org deliverability rollup","tags":["reputation"],"x-fern-sdk-group-name":["reputation"],"x-fern-sdk-method-name":"get"}},"/v1/reputation/findings":{"get":{"description":"The caller's org deliverability findings, newest-first. Supports ?status=, ?severity=, ?domain=, ?sender= filters and limit/cursor paging. Read-only; strictly org-scoped.\n","operationId":"listDeliverabilityFindings","parameters":[{"in":"query","name":"status","schema":{"enum":["open","resolved"],"type":"string"}},{"in":"query","name":"severity","schema":{"enum":["low","high","unknown"],"type":"string"}},{"in":"query","name":"domain","schema":{"type":"string"}},{"in":"query","name":"sender","schema":{"type":"string"}},{"$ref":"#/components/parameters/Limit"},{"description":"Opaque list pagination cursor.","in":"query","name":"cursor","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReputationFindingsPage"}}},"description":"A page of deliverability findings."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"List the org's deliverability findings","tags":["reputation"],"x-fern-sdk-group-name":["reputation"],"x-fern-sdk-method-name":"listFindings"}},"/v1/reviews":{"get":{"description":"List the customer's review requests so a sending agent can monitor its submissions. Filter by state (repeatable / comma-separated), category_id, and inbox. Customer-scoped; human-authority actions are console-only.\n","operationId":"listReviews","parameters":[{"description":"Filter by state (repeatable or comma-separated, e.g. needs_review).","in":"query","name":"state","schema":{"type":"string"}},{"description":"Filter by opaque category id (cat_…).","in":"query","name":"category_id","schema":{"type":"string"}},{"description":"Filter by composer inbox address.","in":"query","name":"inbox","schema":{"type":"string"}},{"$ref":"#/components/parameters/Limit"},{"description":"Opaque page cursor.","in":"query","name":"page","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"List review requests (Review Loop, agent plane)","tags":["reviews"],"x-fern-sdk-group-name":["reviews"],"x-fern-sdk-method-name":"list"}},"/v1/reviews/events":{"get":{"description":"Non-blocking drain of the next un-acked review nudges for the calling agent, in strict-FIFO-per-review seq order (best-effort across reviews), with the per-review cursors. The durable nudge queue is the authoritative liveness source; webhook/SSE are best-effort fast paths on top of it. Side-effect free and idempotent; re-calling returns the same frontier until an ack advances the cursor. Customer-scoped.\n","operationId":"listReviewEvents","parameters":[{"description":"Restrict the drain to one review's events (rr_…).","in":"query","name":"review_id","schema":{"type":"string"}},{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewEventsResponse"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Drain review events (non-blocking)","tags":["reviews"],"x-fern-sdk-group-name":["reviews","events"],"x-fern-sdk-method-name":"list"}},"/v1/reviews/events/ack":{"post":{"description":"Advance the agent's per-(agent, review) cursor(s) to the supplied through_seq and/or mark broadcast nudges done. Idempotent and monotonic; an older seq is a no-op (exactly-once effect, spec §6). Customer-scoped.\n","operationId":"ackReviewEvent","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AckReviewEventRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AckReviewEventResponse"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Ack review events (advance cursor)","tags":["reviews"],"x-fern-sdk-group-name":["reviews","events"],"x-fern-sdk-method-name":"ack"}},"/v1/reviews/events/wait":{"get":{"description":"Long-poll (~25–55s) that blocks until a new review nudge is available OR the deadline elapses, then returns like list_review_events (empty events on timeout, never an error). Cancel-safe: a client disconnect returns promptly. Customer-scoped.\n","operationId":"waitForReviewEvent","parameters":[{"description":"Restrict the wait to one review's events (rr_…).","in":"query","name":"review_id","schema":{"type":"string"}},{"description":"Long-poll budget in seconds (default ~30, capped ~55).","in":"query","name":"wait_seconds","schema":{"type":"integer"}},{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewEventsResponse"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Long-poll for a review event","tags":["reviews"],"x-fern-sdk-group-name":["reviews","events"],"x-fern-sdk-method-name":"getWait"}},"/v1/reviews/{id}":{"get":{"operationId":"getReview","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Get one review request (current draft + intent + state)","tags":["reviews"],"x-fern-sdk-group-name":["reviews"],"x-fern-sdk-method-name":"get"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}]},"/v1/reviews/{id}/cancel":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"The composing agent withdraws its own pending review to the terminal cancelled state (M5; spec §3.2 \"agent withdraws\"). Only the composer may cancel its own review (a foreign id, or another agent's draft, 404s; no cross-agent existence leak). A terminal review 409s (you cannot withdraw a sent message; D17).\n","operationId":"cancelReview","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}},"description":"ok (the review, now cancelled)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"AgentKey":["mailbox:send"]}],"summary":"Withdraw a pending review (composing agent)","tags":["reviews"],"x-fern-sdk-group-name":["reviews"],"x-fern-sdk-method-name":"cancel"}},"/v1/reviews/{id}/chat":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"Append an agent_question turn to the review's append-only thread (M5; spec §3.2/§4.2/§5.2). When the draft is in_review it transitions to chatting (a state_change turn is written atomically); a feedback_added nudge is enqueued to the OTHER party (the human reviewer, via the journal/console stream) and a review.chat event is emitted. Idempotent on the Idempotency-Key (parity v21) so a retried POST never doubles the turn. $0 LLM; the agent composes the question. Human chat (the console human_comment side-panel) is console-only (D17).\n","operationId":"postReviewChat","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostReviewChatRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"AgentKey":["mailbox:send"]}],"summary":"Post a chat turn on a review's thread (agent question)","tags":["reviews"],"x-fern-sdk-group-name":["reviews"],"x-fern-sdk-method-name":"chat"}},"/v1/reviews/{id}/decision":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"The reviewer's decision on a draft it holds (D5; §9). approve/edit → the PLATFORM performs the authenticated send using the COMPOSER's inbox credentials (the reviewer holds review:act, NEVER mailbox:send on an inbox it doesn't own; the credential boundary); send_path becomes reviewer_approved and terminal success is written post-delivery only. reject → the draft returns to the composer (needs_review) and hop_count is incremented. escalate → the draft goes to the human queue with an escalation_reason. revision + version are the optimistic CAS; a mismatch is 409 STALE with NO mutation (the human/composer moved the draft; the human always wins, D17). The two circuit breakers (hop_count ≥ max_hops, or the hard review_deadline) FORCE a reject to the human regardless of intent; forced_by_breaker names the tripped breaker. An unknown action is 400; a cross-tenant id is 404; a non-reviewer is 403. $0 LLM; the reviewer agent judged; we route, send, and enforce the breakers.\n","operationId":"reviewerDecide","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewerDecisionRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewerDecisionResult"}}},"description":"ok (sent via the composer's creds, or returned to the human queue)"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"AgentKey":["review:act"]}],"summary":"Submit a reviewer decision (approve/edit/reject/escalate)","tags":["reviews"],"x-fern-sdk-group-name":["reviews"],"x-fern-sdk-method-name":"decision"}},"/v1/reviews/{id}/decision-context":{"get":{"description":"The reviewer's read-only decision surface (D5; §9): the intent + current draft + the append-only thread + the two-circuit-breaker budget (hop_count vs max_hops, and the hard review_deadline). The reviewer is an AGENT granted review:act, authorized for THIS review ONLY via a matching ACTIVE review_link (per-inbox beats account-wide); review:act alone is necessary, not sufficient. force_to_human is true when EITHER breaker has tripped; the reviewer's next reject would be FORCED to the human regardless of intent (the human is the only terminal authority, D17). A cross-tenant id is 404 (no existence leak); a non-reviewer is 403. No mutation, no LLM.\n","operationId":"getReviewDecisionContext","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewDecisionContext"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["review:act"]}],"summary":"Get the reviewer's decision context for a review (BYO review-agent plane)","tags":["reviews"],"x-fern-sdk-group-name":["reviews"],"x-fern-sdk-method-name":"getDecisionContext"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}]},"/v1/reviews/{id}/feedback":{"get":{"description":"Assemble the human's feedback for a review (M5; spec §5.2/§11): the unified + structured diff of the human edit, the human comments / rejection feedback, the decision, and the rules born from this review (rule_ ids whose source_review_id is this review). Read-only; tenant-scoped (a foreign id 404s). $0 LLM; pure assembly over already-stored turns + rules.\n","operationId":"getReviewFeedback","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewFeedback"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Get the human's assembled feedback for a review (diff + comments + decision + new rules)","tags":["reviews"],"x-fern-sdk-group-name":["reviews"],"x-fern-sdk-method-name":"getFeedback"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}]},"/v1/reviews/{id}/restamp":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"The D19/§8 re-stamp-without-redraft escape valve. The agent asserts \"I reviewed this draft against rules vX and no change is needed\", and the server advances the draft's composed_* rules-versions to vX WITHOUT a new draft (no revision bump, no body change, no nudge); the cheap counterpart to submit_revision. A born-stale draft re-stamped to the current version becomes current-enough and releasable on the next reconciliation sweep. against_version above the category's current rules-version is 400; a terminal/sent draft is 409; a foreign id (or another agent's draft) is 404. $0 LLM; the agent judged; we only record.\n","operationId":"restampReview","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestampReviewRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}},"description":"ok (the review with advanced composed_* versions, body unchanged)"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"AgentKey":["mailbox:send"]}],"summary":"Re-stamp a draft's rules-version without redrafting ($0 escape valve)","tags":["reviews"],"x-fern-sdk-group-name":["reviews"],"x-fern-sdk-method-name":"restamp"}},"/v1/reviews/{id}/revision":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"Post a NEW agent draft for a review (M5; spec §5.2; D17 \"the human always wins\"). parent_revision must equal the draft's current revision, else 409 STALE with NO mutation (a human/inbound actor moved the draft; it becomes a learning / front-run signal). On a clean CAS the proposed_* body is re-rendered in place (revision++), the draft returns to needs_review, and the reviewer nudge + review event fire (all atomic in one WithTx). rules_version_seen is pinned on the new draft. $0 LLM; the agent composes the redraft.\n","operationId":"submitRevision","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitRevisionRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Review"}}},"description":"ok (the redrafted review, now needs_review at revision+1)"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"AgentKey":["mailbox:send"]}],"summary":"Post a new agent draft (redraft) under a parent_revision CAS","tags":["reviews"],"x-fern-sdk-group-name":["reviews"],"x-fern-sdk-method-name":"revision"}},"/v1/reviews/{id}/turns":{"get":{"operationId":"getReviewTurns","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewTurnPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Get a review's append-only thread turns","tags":["reviews"],"x-fern-sdk-group-name":["reviews"],"x-fern-sdk-method-name":"getTurns"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}]},"/v1/risk-dial":{"get":{"description":"Return the effective brand-risk dial: the account-wide default plus every category's per-category overrides, each with its resolved effective value. The override applies over the account default; null means inherit (D12). Read-only; agents may read but NEVER flip the dial (D16/D6); setting the dial is a console (human) action. Customer-scoped.\n","operationId":"getRiskDial","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RiskDial"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Read the effective risk dial (Review Loop, agent plane)","tags":["categories"],"x-fern-sdk-group-name":["riskDial"],"x-fern-sdk-method-name":"get"}},"/v1/rules":{"get":{"description":"Return the ORDERED active rule list with the deterministic §7 precedence ladder applied SERVER-SIDE (NO LLM on our side): hard before soft; specificity per-agent \u003e category \u003e general/house-style; human before agent; newest rev/created_at; higher priority. Includes the general/house-style layer (D2) IN ADDITION to the named category's rules, plus a soft return cap (≈25/category + 25 general, dropping the least-specific general first). The agent reconciles the ordered list semantically; we never apply a rule. Rules are CUSTOMER-scoped and agent-attributed (the cross-agent exception).\n","operationId":"getRules","parameters":[{"description":"Category id (cat_…). Empty returns ONLY the house-style/general layer.","in":"query","name":"category_id","schema":{"type":"string"}},{"description":"Narrow to one layer (general | category). Default returns both.","in":"query","name":"scope","schema":{"enum":["general","category"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RulePage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Get the ordered writing-rule set (precedence ladder applied)","tags":["rules"],"x-fern-sdk-group-name":["rules"],"x-fern-sdk-method-name":"list"},"put":{"description":"Write or edit a rule (D11; ANY agent may write shared/house-style rules; the audit/undo log is the safety net). scope='general' iff category_id is empty (house-style, D2). With supersedes_id the write is an EDIT: a new rev (same lineage) is inserted and the prior is flipped to superseded; else a new lineage is created. Writes a create/supersede audit row, bumps the rule high-water, and emits rule_changed nudges to affected in-flight drafts (born-stale, never silently invalidated).\n","operationId":"saveRule","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveRuleRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rule"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Save a writing rule (append-only by supersession)","tags":["rules"],"x-fern-sdk-group-name":["rules"],"x-fern-sdk-method-name":"update"}},"/v1/rules/audit":{"get":{"description":"The append-only change/undo audit log spanning rules AND categories (D11), optionally narrowed to one entity. Read-only and agent-visible (the audit log is the shared safety net). Each row carries the before/after snapshot enabling an undo via POST /v1/rules/audit/{udo_id}/undo.\n","operationId":"getRuleAudit","parameters":[{"description":"Narrow to one entity kind.","in":"query","name":"entity_kind","schema":{"enum":["rule","category"],"type":"string"}},{"description":"Narrow to one entity (rule_… or cat_…).","in":"query","name":"entity_id","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuleAuditPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Read the rule/category change audit log (agent plane, read-only)","tags":["rules"],"x-fern-sdk-group-name":["rules","audit"],"x-fern-sdk-method-name":"list"}},"/v1/rules/audit/{udo_id}/undo":{"parameters":[{"in":"path","name":"udo_id","required":true,"schema":{"type":"string"}}],"post":{"description":"Restore the prior version recorded in an audit row (D11; agents may undo too). UNDO = a NEW forward supersession that re-inserts the before snapshot as the new active head (action='restore'); the source audit row is marked undone. Idempotent: a re-undo of an already-undone row is a clean 409. Safe under concurrent edits (the restore CASes on the lineage head). The udo_id is an AUDIT row id, hence the nesting under the audit subtree.\n","operationId":"undoRuleChange","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rule"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Undo a rule change (restore the prior version)","tags":["rules"],"x-fern-sdk-group-name":["rules","audit"],"x-fern-sdk-method-name":"undo"}},"/v1/rules/{id}/promote":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"Move a rule between the category and general/house-style layers via a supersession (a new rev with the changed scope). Writes a supersede audit row and re-checks affected in-flight drafts. Promoting to category requires the rule to already carry a category.\n","operationId":"promoteRule","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteRuleRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rule"}}},"description":"ok"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Promote a rule between the category and general/house-style layers","tags":["rules"],"x-fern-sdk-group-name":["rules"],"x-fern-sdk-method-name":"promote"}},"/v1/rules/{id}/retire":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"description":"Soft-delete a rule (status='retired') via a supersession-style flip; there is NO hard delete; the history survives as training data. Writes a retire audit row and re-checks affected in-flight drafts.\n","operationId":"retireRule","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rule"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ReviewConflict"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Retire a rule (soft delete)","tags":["rules"],"x-fern-sdk-group-name":["rules"],"x-fern-sdk-method-name":"retire"}},"/v1/signup-status":{"get":{"description":"Returns the database-backed global free-signup switch. This response is never cacheable.","operationId":"getSignupStatus","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupStatus"}}},"description":"Current signup availability.","headers":{"Cache-Control":{"schema":{"example":"no-store","type":"string"}}}},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Signup availability could not be determined (`signup_gate_unavailable`)."}},"security":[],"summary":"Read current free-signup availability","tags":["enrollment"]}},"/v1/suppressions":{"get":{"description":"With ?recipient= this is the read-only PRE-CHECK: does the CALLER'S OWN ORG suppress this recipient, and which org rows match (returns SuppressionPrecheck). Without ?recipient= it is the paged list of the caller's own org suppression rows (returns SuppressionPage). Both are strictly scoped to the key's customer: global/shared_domain/cross-tenant rows are NEVER returned (R4 non-leakage).\n","operationId":"listSuppressions","parameters":[{"description":"Present ⇒ pre-check that address; absent ⇒ list. Canonicalized server-side.","in":"query","name":"recipient","schema":{"type":"string"}},{"description":"Optional list filter (only 'org' rows are visible here).","in":"query","name":"scope","schema":{"enum":["org"],"type":"string"}},{"description":"List: include soft-revoked rows (default active-only).","in":"query","name":"include_revoked","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/Limit"},{"description":"Opaque list pagination cursor.","in":"query","name":"cursor","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/SuppressionPage"},{"$ref":"#/components/schemas/SuppressionPrecheck"}]}}},"description":"A SuppressionPrecheck (when ?recipient= is set) or a SuppressionPage."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"Pre-check a recipient or list the org's suppression rows","tags":["suppressions"],"x-fern-sdk-group-name":["suppressions"],"x-fern-sdk-method-name":"list"}},"/v1/suppressions/{id}/revoke":{"post":{"description":"Owner-decided revoke (plan §7): an agent may revoke ONLY an org-scope row of its OWN org. The reason is required and audit-logged. A foreign/global/shared id is a 404 (no cross-tenant existence oracle); an empty reason is a 400.\n","operationId":"revokeSuppression","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokeSuppressionRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Suppression"}}},"description":"The revoked row."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["mailbox:send"]}],"summary":"Revoke (un-suppress) one org-scope suppression row","tags":["suppressions"],"x-fern-sdk-group-name":["suppressions"],"x-fern-sdk-method-name":"revoke"}},"/v1/unsubscribe/{token}":{"get":{"description":"Public, unauthenticated. Returns a self-contained HTML page with a confirm button (\"stop emails from {org}\"), a narrower \"only this sender\" option, and an address-confirm field for multi-recipient (digest) tokens. This endpoint NEVER mutates state (scanner defense); an invalid/expired token yields a graceful static page (still 200, never an enumeration oracle).\n","operationId":"unsubscribePage","responses":{"200":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"The unsubscribe page (or a graceful invalid-link page)."},"429":{"description":"Throttled (per-IP/token rate limit)."}},"security":[],"summary":"Render the unsubscribe confirmation page","tags":["unsubscribe"]},"parameters":[{"description":"Opaque, stateless AEAD unsubscribe token placed in the `List-Unsubscribe` header of an outbound message. Carries tenant/origin context plus either the single recipient (one-click tokens) or truncated per-recipient digests (multi-recipient tokens); no recipient PII is in the URL.\n","in":"path","name":"token","required":true,"schema":{"type":"string"}}],"post":{"description":"Public, unauthenticated. Accepts `application/x-www-form-urlencoded` and `multipart/form-data`. A body carrying `List-Unsubscribe=One-Click` is the RFC 8058 one-click path (single-recipient tokens only); it is idempotent, returns a plain 200 with NO redirects and no cookies. Otherwise it is the preferences-page form: a `scope` field (`narrow` selects the \"just this sender\" opt-out; anything else is org-wide) and, for multi-recipient tokens, an `email` field validated against the token's digests before suppressing. Invalid/expired tokens and unverified addresses return a 200 page, never a status-code enumeration oracle.\n","operationId":"unsubscribe","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"properties":{"List-Unsubscribe":{"description":"Set to \"One-Click\" for the RFC 8058 one-click POST.","type":"string"},"email":{"description":"Visitor-confirmed address (multi-recipient tokens only).","type":"string"},"scope":{"description":"\"narrow\" for a just-this-sender opt-out; else org-wide.","type":"string"}},"type":"object"}},"multipart/form-data":{"schema":{"properties":{"List-Unsubscribe":{"type":"string"},"email":{"type":"string"},"scope":{"type":"string"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"text/html":{"schema":{"type":"string"}},"text/plain":{"schema":{"type":"string"}}},"description":"Opt-out recorded (or a graceful invalid/unverified page)."},"400":{"description":"Malformed request body."},"429":{"description":"Throttled (per-IP/token rate limit)."}},"security":[],"summary":"Record an unsubscribe (RFC 8058 one-click or preferences form)","tags":["unsubscribe"]}},"/v1/wait":{"post":{"description":"Same as the inbox-scoped wait, but the mailbox is supplied in the `address` field.","operationId":"waitForEmailLegacy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitResult"}}},"description":"Matched or timed out."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"AgentKey":["mailbox:read"]}],"summary":"wait_for_email (legacy body-addressed form)","tags":["messaging"],"x-fern-ignore":true}},"/v1/webhooks":{"get":{"operationId":"listWebhooks","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookPage"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"AgentKey":["webhook:write"]},{"AgentKey":["mailbox:read"]}],"summary":"List the agent's webhooks (secrets redacted)","tags":["webhooks"],"x-fern-sdk-group-name":["webhooks"],"x-fern-sdk-method-name":"list"},"post":{"description":"Register an inbound webhook. Accepts a client-supplied idempotency key (`Idempotency-Key` header or `client_id` body field): a retry with the same key replays the original registration; the same key with a different body is a 409. New keys should grant `webhook:write`; `mailbox:read` remains accepted for older keys.\n","operationId":"registerWebhook","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterWebhookRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}},"description":"Registered. `secret` is shown once."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/IdempotencyConflict"}},"security":[{"AgentKey":["webhook:write"]},{"AgentKey":["mailbox:read"]}],"summary":"Register an inbound HMAC-signed webhook","tags":["webhooks"],"x-fern-sdk-group-name":["webhooks"],"x-fern-sdk-method-name":"create"}},"/v1/webhooks/{id}":{"delete":{"operationId":"deleteWebhook","responses":{"204":{"description":"deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["webhook:write"]},{"AgentKey":["mailbox:read"]}],"summary":"Delete a webhook","tags":["webhooks"],"x-fern-sdk-group-name":["webhooks"],"x-fern-sdk-method-name":"delete"},"get":{"operationId":"getWebhook","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}},"description":"ok"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["webhook:write"]},{"AgentKey":["mailbox:read"]}],"summary":"Get one webhook (secret redacted)","tags":["webhooks"],"x-fern-sdk-group-name":["webhooks"],"x-fern-sdk-method-name":"get"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"patch":{"operationId":"updateWebhook","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}},"description":"Updated (secret redacted)."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"AgentKey":["webhook:write"]},{"AgentKey":["mailbox:read"]}],"summary":"Update a webhook (url, events, inbox filter, active)","tags":["webhooks"],"x-fern-sdk-group-name":["webhooks"],"x-fern-sdk-method-name":"update"}}},"security":[{"AgentKey":[]}],"servers":[{"description":"Production","url":"https://api.extrovert.dev"},{"description":"Local","url":"http://localhost:8090"}],"tags":[{"description":"Health probes and the machine-readable API description.","name":"ops"},{"description":"Bootstrap an agent identity from an enrollment token or self-signup.","name":"enrollment"},{"description":"Create, list, get, update, and delete inboxes. Paid plans can also fetch mail-client credentials.","name":"inboxes"},{"description":"Send, reply, forward, read messages and threads, and wait for inbound mail.","name":"messaging"},{"description":"List and download message attachments.","name":"attachments"},{"description":"Register HMAC-signed inbound delivery webhooks.","name":"webhooks"},{"description":"Agent-facing domain management (privileged, domain:manage scope): list, get, onboard, verify, and offboard the customer's domains over the shared onboarding infrastructure.\n","name":"domains"},{"description":"Agent-safe quotes and human-controlled purchase or plan-change requests.","name":"commerce"},{"description":"Clerk-authenticated console / admin plane (customer-scoped).","name":"admin"},{"description":"Extrovert subscription billing and Stripe webhook ingestion.","name":"billing"},{"description":"Public, unauthenticated List-Unsubscribe endpoints (RFC 8058 one-click POST and the preferences page) backing recipient-driven suppression.\n","name":"unsubscribe"},{"description":"Recipient opt-out (suppression) management: the agent-plane pre-check + list + revoke and the console/admin list/search/export/revoke. Reads and revoke are strictly org-scoped; global/shared-domain rows are operator-only and never exposed.\n","name":"suppressions"}]}