Skip to content

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.

id
required
string

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
to

Replace this recipient group; omit to preserve, [] to clear. Quota changes atomically with the draft; insufficient quota preserves the previous draft and reservation.

Array<string>
<= 50 items
cc

Replace this recipient group; omit to preserve, [] to clear. Quota changes atomically with the draft; insufficient quota preserves the previous draft and reservation.

Array<string>
<= 50 items
bcc

Replace this recipient group; omit to preserve, [] to clear. Quota changes atomically with the draft; insufficient quota preserves the previous draft and reservation.

Array<string>
<= 50 items
parent_revision
required

The revision the agent composed against (PRIMARY CAS).

integer
recheck_through_seq

Highest committed, available recheck event sequence actually handled. Completion commits with the revision; newer work remains pending. Omit for legacy mutations without completion.

integer
>= 1
expected_context_version

Required for reply revisions. Obtain from a fresh complete thread read before reconsidering the draft. A changed conversation returns reply_context_changed (409) without replacing the draft.

string
>= 1 characters
version

Optional row-version CAS (defense in depth).

integer
subject
string
text

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.

string
body

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.

string
html
string
built_at

When the agent built this draft (informational).

string format: date-time
rules_version_seen

Rule high-water this draft was composed against (born-stale basis).

integer
composition_token
required

Opaque token from a fresh, unfiltered GET /v1/rules for the review’s category.

string
attachments

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.

Array<object>
<= 20 items

An outbound attachment on send/reply/forward.

object
filename
string
content_type
string
content_base64
required

Standard base64-encoded attachment bytes. Up to 20 attachments share the 1,800,000-byte encoded email limit with headers and both bodies.

string

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
category_name

Human-readable category name; absent when unavailable.

string
recheck_status

Pending reconsideration; does not assert that the composer is online.

string
Allowed values: queued
recheck_completed_through_seq

Durable composer completion watermark independent of acknowledgement.

integer
recheck_outstanding_seq

Highest available unresolved recheck event sequence.

integer
recheck_reason

Cause of pending reconsideration.

string
id
required
string
state
required
string
Allowed values: needs_review in_review chatting stale approved sent auto_sent rejected stalled cancelled failed
mode
required
string
Allowed values: review direct
review_path

Console path to this draft. Sign in and claim the workspace if prompted before reviewing.

string
effective_mode
required
string
Allowed values: review direct
kind
required
string
Allowed values: send reply forward
from_address
string
from_display_name

Captured sender name for this review; empty means bare address. Absent on legacy reviews.

string
agent_id
string
category_id
string
intent_summary
string
intent_meta
object
key
additional properties
any
revision
required
integer
version
required
integer
proposed_subject
string
proposed_body_text
string
proposed_body_html
string
proposed_to
Array<string>
proposed_cc
Array<string>
proposed_bcc
Array<string>
thread_ref

Mail conversation ID for fetching reply or forward context; distinct from reviewer feedback.

string
context_version

Conversation snapshot used for this draft. Absent on legacy drafts whose composition context is unknown.

string
context_last_message_id

Newest message observed when composing this draft.

string
context_message_ids

Message selectors in the conversation snapshot used for this draft; does not certify semantic comprehension.

Array<string>
in_reply_to_message_id

Opaque parent message ID for replies; raw RFC5322 Message-ID for plain sends.

string
sent_subject
string
sent_body_text
string
diff_unified
string
sent_message_id
string
gate_outcome
string
stale_reason
string
decision_feedback
string
closed

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.

boolean
send_error

Vendor-scrubbed delivery failure, present on a failed review.

string
send_path

How the message was released, once sent.

string
Allowed values: human_reviewed delegated_reviewed reviewer_approved graduated_auto agent_direct human_recipient_auto project_recipient_auto organization_recipient_auto
created_at
string format: date-time
updated_at
string format: date-time
decided_at
string format: date-time
sent_at
string format: date-time

Invalid request.

The canonical error envelope. error is a stable machine code.

object
error
required

Stable error code (e.g. unauthorized, forbidden, not_found, invalid, quota_exceeded, rate_limited).

string
Example
forbidden
message

Human-readable detail (never leaks internals).

string
Example
missing required scope
reason

Machine-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.

string
used

Consumed plus reserved units.

integer format: int64
delta

Requested additional units.

integer format: int64
limit
integer format: int64
remaining
integer format: int64
consumed
integer format: int64
reserved
integer format: int64
next_reset_at

Next UTC usage-period boundary; pending reservations survive this boundary.

string format: date-time
upgrade_required
boolean

Missing or invalid credential.

The canonical error envelope. error is a stable machine code.

object
error
required

Stable error code (e.g. unauthorized, forbidden, not_found, invalid, quota_exceeded, rate_limited).

string
Example
forbidden
message

Human-readable detail (never leaks internals).

string
Example
missing required scope
reason

Machine-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.

string
used

Consumed plus reserved units.

integer format: int64
delta

Requested additional units.

integer format: int64
limit
integer format: int64
remaining
integer format: int64
consumed
integer format: int64
reserved
integer format: int64
next_reset_at

Next UTC usage-period boundary; pending reservations survive this boundary.

string format: date-time
upgrade_required
boolean

Authenticated but lacking the required scope, or out of quota.

The canonical error envelope. error is a stable machine code.

object
error
required

Stable error code (e.g. unauthorized, forbidden, not_found, invalid, quota_exceeded, rate_limited).

string
Example
forbidden
message

Human-readable detail (never leaks internals).

string
Example
missing required scope
reason

Machine-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.

string
used

Consumed plus reserved units.

integer format: int64
delta

Requested additional units.

integer format: int64
limit
integer format: int64
remaining
integer format: int64
consumed
integer format: int64
reserved
integer format: int64
next_reset_at

Next UTC usage-period boundary; pending reservations survive this boundary.

string format: date-time
upgrade_required
boolean

Resource not found.

The canonical error envelope. error is a stable machine code.

object
error
required

Stable error code (e.g. unauthorized, forbidden, not_found, invalid, quota_exceeded, rate_limited).

string
Example
forbidden
message

Human-readable detail (never leaks internals).

string
Example
missing required scope
reason

Machine-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.

string
used

Consumed plus reserved units.

integer format: int64
delta

Requested additional units.

integer format: int64
limit
integer format: int64
remaining
integer format: int64
consumed
integer format: int64
reserved
integer format: int64
next_reset_at

Next UTC usage-period boundary; pending reservations survive this boundary.

string format: date-time
upgrade_required
boolean

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
reason

Structured support failure reason without changing the existing code.

string
next_action

Suggested recovery action within existing access.

string
projects
object
object
required
string
Allowed values: list
data
required
Array<object>
object
id
required
string
org_id
required
string
name
required
string
has_more
required
boolean
next_cursor
required
string
current_state
object
id
required
string
number
required
string
project_id
required
string
title
required
string
status
required
string
Allowed values: received working waiting_on_customer resolved
impact
required
string
Allowed values: blocked workaround_available recovered unknown
version
required
integer format: int64
created_ms
required
integer format: int64
updated_ms
required
integer format: int64
resolved_ms
integer format: int64
customer_confirmed_ms
integer format: int64
resolution_kind
string
resolution_summary
string
feedback_id
required
string
org_id
string
console_url
string
latest_update
object
id
required
string
sequence
required
integer format: int64
kind
required
string
actor_kind
required
string
Allowed values: customer staff
body
required
string
created_ms
required
integer format: int64
observed_runtime
object
source
string
package_version
string
profile
string
profile_version
string
build
string
transport
string
catalog_digest
string
instance_id
string
request_id
string
observed_ms
integer format: int64
truncated
required
boolean
unsent_text

Retained text after a concurrent case change.

string
type
required
string format: uri
title
required
string
status
required
integer
detail
string
code
required

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.

string
Allowed values: bad_request unauthorized forbidden_scope not_found conflict support_record_deleted idempotency_conflict breadth_required quota_exceeded rate_limited domain_not_allowed recipient_blocked recipient_suppressed not_configured domain_unavailable internal reply_context_required reply_context_changed reply_workflow_required reply_already_pending intent_required wrong_state terminal stale born_stale send_needs_reconciliation graduation_locked maturity_gate_unmet scope_taken unavailable
request_id
string
errors
Array<object>
object
field
string
code
string
detail
string