require_approval; clients do not create approvals directly.
The surrounding authorization path depends on the action being reviewed.
Two different governance paths
Connected and platform ToolInvocations
A governed Connection or platform ToolInvocation keeps the complete ladder:allow, require_approval, or deny. An ActionApproval records the human decision only for the exact action that reached the approval branch.
Custom tools declared by the admitted Agent
A Custom-tool call has no Connection, ToolSource, provider credential, or PermissionAssignment in its invocation path. The admitted Agent already declares the Tool. Checkfu evaluates ActionPolicy directly:run.action_authorized is the durable fact that the exact call may be executed. An ActionApproval does not execute customer code, mint a provider-effect proof, or post the result.
Reviewer authorization is separate from the Custom-tool invocation path. A trusted backend that asserts an end-user reviewer with acted_as must prove that the Principal holds an active approve PermissionAssignment on the resource mapped from the approval subject and survives the current ActionPolicy ladder. That does not add PermissionAssignment to the Tool call itself.
What is frozen
The ActionApproval binds the decision to the exact action that requested it. A ToolInvocation review can name the Session, Run, acting Principal, Agent version, Connection and Connection revision, ToolSource and Tool versions, schema hash, and the permitted outbound destination. A Custom-tool review instead names the admitted Agent, logical Tool name,tool_use_id, Session, Run, and optional surface coordinate. It does not invent a Connection, ToolSource, outbound request, or thread coordinate.
The public ActionApproval resource exposes argument identity in its top-level arguments_hash, not argument values. Its context_summary carries the kind-specific frozen coordinates. Query strings, headers, request bodies, and custodied Credential values are not returned in the review resource.
For a Custom tool, the exact arguments already appear in the preceding agent.tool_use event. Prove that the payload shown to a reviewer is the frozen payload before presenting it as such:
The resource and event use different field names in the current wire contract: the ActionApproval resource carries top-level
arguments_hash, while action_approval.pending carries overlapping authority under frozen_context with arg_hash. Match the surface you are reading.Lifecycle
A connected ToolInvocation approval is time-bounded and single-use. The approve response can carry a deterministic proof token; redemption moves the ActionApproval to
consumed. GET /v1/action-approvals/{id} never reveals that proof.
A Managed-tool purchase approval carries no redeemable provider-effect proof or provider credential. The decision stays bound to its original invocation, selection, quoted terms and expiry; execution and result release still require their separate current authority.
A Custom-tool approval carries no provider-effect proof. Its approved decision advances the exact wait and produces run.action_authorized; the application then supplies user.custom_tool_result.
Responding
The public resource exposes:GET /v1/action-approvalsfor backfill and reconciliation;GET /v1/action-approvals/{id}for one frozen decision; andPOST /v1/action-approvals/{id}/responsesforapproveordenywith optimistic concurrency.
version as expected_version. Optional instructions are recorded with the resolution. Use one stable Idempotency-Key for the logical response and reuse it only for an exact retry.
A keyed retry can replay the captured HTTP response. It does not extend approval expiry, make a consumed proof reusable, or turn a proof-free Custom-tool response into a bearer credential.
For CMA-shaped clients, the reviewer may instead send user.tool_confirmation to the ordinary Session event endpoint with the same tool_use_id. allow moves the same wait into its Custom-result phase; it does not authorize the platform to execute customer code or replace the later user.custom_tool_result. Authenticated server context supplies event attribution; clients do not send authored_by.
Handle an approval
Build the event-driven queue, distinguish the two action paths, and continue safely.
Who may respond
A root or admin API key can respond under the role path. The audit record names the authenticated key. A trusted control-plane backend can instead includeacted_as to assert an end-user Principal. The current responder contract then verifies that the backend may assert people and that the Principal has live approval authority on the resource mapped from the approval subject. A matching ActionPolicy denial still wins. Runner and model credentials cannot approve their own work.
This responder check answers who may make the human decision. It does not change whether the underlying Custom-tool invocation uses PermissionAssignment; it does not.
Standing approvals
An eligible connected ToolInvocation approval can mint a bounded StandingApproval for future matching calls. It is a separate, listable, revocable resource. A StandingApproval can only downgraderequire_approval to allow for its exact subject, Connection, Tool, scope, revision, and expiry. It never:
- overrides
deny; - fills in a missing PermissionAssignment;
- applies to a Custom-tool call;
- survives Connection rotation; or
- widens beyond its recorded argument scope.
Revocation after approval
Connected ToolInvocations recheck live authority immediately before provider I/O. Any of these changes can refuse an already-approved action:
Approval records what a person decided. It does not preserve stale authority.
After a connected ToolInvocation completes, the gateway checks current Run
authority before returning its result or offering a spill, and again after a
spill wait. When the Run is canceled, expired, or its authority service is
unavailable, the gateway withholds its response and spill sidecar. The
Run-authority error explains that the provider call completed; retries of that
ToolInvocation cannot repeat the effect. A spill implementation owns authority
enforcement during its own asynchronous write. This Run check does not
establish permission to share the result with another audience.
A Custom-tool approval has no provider-side recheck because Checkfu does not perform that effect. Your application must still enforce its own tenant, account, and row-level authorization immediately before executing the handler.
Audit and uncertain effects
The Session event log records when an ActionApproval becomes pending and when it resolves. Audit records the authenticated responder, optional asserted Principal, frozen coordinates, policy path, and trusted effect outcome where Checkfu owns the effect. Neither surface returns custodied Credential values. A ToolInvocation can settle as completed, denied, or indeterminate.indeterminate means Checkfu cannot prove whether the provider accepted the effect. Recovery must reconcile that uncertainty instead of treating it as a safe automatic retry.
For a Custom tool, the customer application owns effect safety. Use provider-supported idempotency, a durable effect ledger, or explicit reconciliation before retrying an ambiguous remote result.
Questions are not approvals
A Question asks a person for ordinary input. It grants no authority, has no approval proof, and is answered withuser.question_answer. Both Questions and ActionApprovals can park a Run, so branch on the action kind rather than treating every wait as permission to act.