Confirmation Contract
A Write Stops for a Human
Archie does the work, but he never posts an irreversible entry on his own. When a write crosses a risk threshold he pauses and hands you a structured prompt. Every framework (REST, MCP, LangGraph, the agent SDKs) gets human-in-the-loop for free.
When a Confirmation Fires
Confirmation fires when a tool would take an action above a risk threshold. The current triggers are:
- Journal entries above the auto-approval monetary limit for the key.
- Any write tool on a key carrying the
write:confirmscope. - Bulk modifications, and irreversibly, bulk deletions.
Read-only tools never trigger confirmation. Test keys use lower thresholds, so you can exercise the flow without posting real data.
The Confirmation Object
When a tool defers, Archie creates a confirmation record and returns its confirmation_id. Fetch the full record at any time with GET /api/v1/confirmations/{confirmation_id}.
{
"confirmation_id": "conf_01ABC...",
"status": "pending",
"action_type": "journal_entry",
"action_name": "Post journal entry",
"action_description": "Dr Plant & Equipment USD 12,500 / Cr Bank USD 12,500 (Q1 forklift)",
"affected_count": 1,
"risk_level": "medium",
"reversible": true,
"created_at": "2026-04-29T10:00:00Z",
"expires_at": "2026-04-29T10:05:00Z",
"prompt_markdown": "**Approve journal entry?**\n\nDr Plant & Equipment $12,500 \n Cr Bank $12,500 \n\nMemo: Q1 forklift"
}Render prompt_markdown directly to the user. It is the canonical, human-readable description of what will happen. Surface action_name and risk_level alongside it if your UI needs structure.
Approve or Deny
# Approve, which executes the action
POST /api/v1/confirmations/{confirmation_id}/approve
{ "reason": "Verified against PO 4421" } # body optional
# Deny, which cancels the action
POST /api/v1/confirmations/{confirmation_id}/deny
{ "reason": "Wrong client account" } # body optionalRecords are single-use, scoped to the caller that issued the original tool call, and expire after five minutes by default. A denied confirmation cannot be re-approved; call the original tool again to retry.
Lifecycle
Poll GET /api/v1/confirmations/{confirmation_id} to check status. The status field moves through:
pending: awaiting a decision.approved: the caller approved, so the action executes.denied: the caller denied, so the action is cancelled.expired: the five-minute window elapsed.
To cancel a pending confirmation outright, use DELETE /api/v1/confirmations/{confirmation_id}.
Framework Adapters Handle This for You
With the Python or TypeScript SDK and a framework adapter, the confirmation surfaces natively.
LangGraph
The adapter raises a NodeInterrupt carrying prompt_markdown and pauses the graph. Resume with graph.ainvoke(None, config) once the user approves.
OpenAI Agents SDK
The tool raises a ConfirmationRequiredError. Catch it, surface err.prompt_markdown, then call tool.approve(err.confirmation_id).
Vercel AI SDK
The tool returns a confirmation result type that triggers the SDK's native confirmation UI.
prompt_markdown to the user before you decide whether to call /approve or /deny. The human sees what posts before it posts.Security
- Records are single-use, so replay is bounded to the five-minute window.
- Records are scoped to the user or key that issued the original call.
- The audit log records both the original call and the approve or deny decision.
- The
correlation_idon the original response links the full audit trail.