Post a chat turn on a review's thread (agent question)
POST /v1/reviews/{id}/chat
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).
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”Header Parameters
Section titled “Header Parameters ”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.
Request Body required
Section titled “Request Body required ”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.
object
The agent’s question/comment for the human reviewer.
Responses
Section titled “ Responses ”Ok
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.
object
Human-readable category name; absent when unavailable.
Pending reconsideration; does not assert that the composer is online.
Durable composer completion watermark independent of acknowledgement.
Highest available unresolved recheck event sequence.
Cause of pending reconsideration.
Console path to this draft. Sign in and claim the workspace if prompted before reviewing.
Captured sender name for this review; empty means bare address. Absent on legacy reviews.
object
Mail conversation ID for fetching reply or forward context; distinct from reviewer feedback.
Conversation snapshot used for this draft. Absent on legacy drafts whose composition context is unknown.
Newest message observed when composing this draft.
Message selectors in the conversation snapshot used for this draft; does not certify semantic comprehension.
Opaque parent message ID for replies; raw RFC5322 Message-ID for plain sends.
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.
Vendor-scrubbed delivery failure, present on a failed review.
How the message was released, once sent.
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 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.
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.