Link a BYO review-agent to an inbox (console plane)
POST /v1/admin/orgs/{org_id}/projects/{project_id}/review-links
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).
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”Request Body required
Section titled “Request Body required ”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.
object
Empty = account-wide.
The reviewer agent (agt_…)
Defaults webhook.
Required for the webhook transport.
Write-only signing secret for webhook deliveries.
Responses
Section titled “ Responses ”Created
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).
object
Opaque review-link id (rvl_…).
Scope: a specific inbox; empty = account-wide.
The linked reviewer agent (agt_…).
Delivery URL (webhook transport only).
Whether an hmac signing secret is configured (the secret itself is never echoed).
Seconds before the reviewer-liveness sweeper auto-escalates to the human (default 300).
Circuit breaker: max reviewer hand-backs before the next action is forced to the human (default 3).
Circuit breaker: hard per-review deadline in seconds (default 86400).
Consecutive delivery failures; an unhealthy link is skipped by routing until recovery.
Invalid request.
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 scopeMissing 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 scopeAuthenticated 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 scopeA 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
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.