Post a new agent draft (redraft) under a parent_revision CAS
POST /v1/reviews/{id}/revision
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.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”Request Body required
Section titled “Request Body required ”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).
object
The revision the agent composed against (PRIMARY CAS).
Optional row-version CAS (defense in depth).
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.
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.
When the agent built this draft (informational).
Rule high-water this draft was composed against (born-stale basis).
Opaque token from a fresh, unfiltered GET /v1/rules for the review’s category.
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.
An outbound attachment on send/reply/forward.
object
Standard base64-encoded attachment bytes.
Responses
Section titled “ Responses ”Ok (the redrafted review, now needs_review at revision+1)
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
object
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 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 scopeResource 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 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.