Demote a category one rung down (console plane, human authority)
POST /v1/admin/orgs/{org_id}/projects/{project_id}/categories/{id}/demote
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.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”Responses
Section titled “ Responses ”Demoted.
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).
object
Logical accepted messages created in the last 7 days in the authorized project.
Logical accepted messages created in the last 30 days in the authorized project.
Logical accepted messages created in the last 90 days in the authorized project.
Most recent accepted message creation time; absent when unused.
Current nonterminal reviews across composers in the authorized project.
Active category rules visible in the authorized project; excludes retired and superseded versions.
Opaque category id (cat_…).
Survivor category id when this one was merged/soft-deleted (cat_…).
Human lock pinning the category at supervised (no live auto-send; D16).
Clean human-approve-as-is count toward the maturity gate (D16).
Human edit/reject count in a graduated category toward drift auto-demote (K; §7).
When the category was last graduated (omitted if never).
Who last graduated it (‘human:’); empty if never/demoted.
Missing or invalid credential.
The canonical error envelope. error is a stable machine code.
object
Stable error code (e.g. unauthorized, forbidden, not_found, invalid, quota_exceeded, rate_limited).
Example
forbiddenHuman-readable detail (never leaks internals).
Example
missing required scopeMachine-readable quota reason. inbox_limit_exceeded means billing account inbox capacity across all organizations and projects sharing that account; enrollment_token_mailbox_budget_exhausted means the enrollment key lifetime creation allowance. Read message for recovery; inbox counts are separate from sending quotas.
Consumed plus reserved units.
Requested additional units.
Next UTC usage-period boundary; pending reservations survive this boundary.
Authenticated but lacking the required scope, or out of quota.
The canonical error envelope. error is a stable machine code.
object
Stable error code (e.g. unauthorized, forbidden, not_found, invalid, quota_exceeded, rate_limited).
Example
forbiddenHuman-readable detail (never leaks internals).
Example
missing required scopeMachine-readable quota reason. inbox_limit_exceeded means billing account inbox capacity across all organizations and projects sharing that account; enrollment_token_mailbox_budget_exhausted means the enrollment key lifetime creation allowance. Read message for recovery; inbox counts are separate from sending quotas.
Consumed plus reserved units.
Requested additional units.
Next UTC usage-period boundary; pending reservations survive this boundary.
Resource not found.
The canonical error envelope. error is a stable machine code.
object
Stable error code (e.g. unauthorized, forbidden, not_found, invalid, quota_exceeded, rate_limited).
Example
forbiddenHuman-readable detail (never leaks internals).
Example
missing required scopeMachine-readable quota reason. inbox_limit_exceeded means billing account inbox capacity across all organizations and projects sharing that account; enrollment_token_mailbox_budget_exhausted means the enrollment key lifetime creation allowance. Read message for recovery; inbox counts are separate from sending quotas.
Consumed plus reserved units.
Requested additional units.
Next UTC usage-period boundary; pending reservations survive this boundary.
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.
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.
object
Structured support failure reason without changing the existing code.
Suggested recovery action within existing access.
object
object
object
object
object
Retained text after a concurrent case change.
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.