---
title: "Capability: Human approvals"
canonical_url: "https://tokenobserve.com/platform/human-approvals"
published: 2026-09-02
last_updated: 2026-10-21
---

# Capability: Human approvals

One human decision, bound to one exact payload, spendable once.

## What it is

Human approvals park one exact action on a named person before it happens. A require_approval policy refuses the request with a 403, mints an approval bound to the SHA-256 of the canonicalised action plus the execution context it was proposed in, and holds the trace open until somebody decides. That approval authorises that payload and nothing else: change one argument and the hash no longer matches, so the retry is refused rather than allowed as near enough. It is single-use and it expires, at 60 minutes by default. Approving pushes nothing to the agent: the agent redeems it by repeating the identical request with its id.

## Facts

- Binding: SHA-256 of the canonical action plus its context
- Lifetime: 60 minutes by default; 1 minute to 7 days per policy
- Refusal: 403 with the approval id, a status URL and a resume contract
- Redemption: Repeat the identical request with the approval id, once

## The limit

Nothing tells the agent: An approval takes effect only when the agent retries

## Why it exists: An approval not bound to a payload is a rubber stamp.

You added a human gate because somebody should look before an agent moves money. The failure mode is not that nobody approved — it is that the thing approved and the thing that ran were different things. An approval authorising a refund, rather than this refund of £240 on this order, is a standing licence for every refund that agent proposes afterwards.

The second failure is what makes a team switch the gate off. An agent waiting on a human has no callback, so it re-submits, and a gateway minting a fresh approval per re-submission buries the reviewer under duplicates of the one thing they are being asked to decide. The queue fills with rows that are individually valid and collectively unusable.

## How it works

- A policy asks for a human, and the action is hashed: The first require_approval match is held; a block anywhere in the same pass wins outright, so nobody is asked to approve what another rule already refuses. The action and its execution context are hashed into one canonical object, the trace is parked, and the request is refused with a 403 carrying the approval id, a status URL and a resume object.
- A human decides, with a reason: Deciding needs the operator role or above and an evidence scope covering the trace’s team, and the console requires a written reason. The write is a compare-and-set on the pending state, so when two people decide at once only one is recorded as the decider.
- The agent retries the identical request: The retry is hashed again and compared. Consumption is a guarded update, so a second retry is refused as already consumed and a pending re-poll takes no second reservation. Anything undecided expires, and expiring the row and releasing what it held are one transaction.

## Where it runs in the request path

Step 7 of the request path

## What it does not do

- Token Observe cannot call an agent back. Approving unblocks nothing on its own, and an agent that never retries leaves the action undone with an approval nobody spent.
- There is no approver routing. Any operator whose evidence scope covers the trace’s team can decide any approval in it: no per-policy approver list, no escalation path, no two-person rule. The mandatory written reason is a console rule: the decision endpoint takes it as optional, so an install driving decisions through the API enforces that itself.
- The reviewer reads a summary, not the payload. It is the tool or model name plus the policy’s own reason, mask-redacted and capped at 240 characters, beside sixteen characters of the payload fingerprint; no model-proposed arguments reach the approvals table or the approval.requested webhook on any path. The linked trace holds what was recorded of the request rather than the request: tool arguments through the tool gateway, and prompt text only where conversation capture has been switched from its metadata default to redacted.
- Offline approvals on a developer seat cannot be single-use. A signed bundle records consumption as of the moment it was issued and nothing on the device can change that, so within one bundle’s freshness window a granted approval can be spent twice.
- The gate binds only the calls Token Observe sees. Tool rules are enforced on the tool gateway and on tool calls a model proposes; an agent executing a tool without routing it here is a matter for the shadow-AI radar.

## Read next

- https://tokenobserve.com/platform/policy-engine
- https://tokenobserve.com/platform/spend-controls
- https://tokenobserve.com/platform/mcp-gateway

## Questions and answers

Q: What is an approval bound to?
A: The SHA-256 of one canonical object holding the action and its execution context: the subject with its team, tags and effective role grants, the ordered delegation chain, the on-behalf-of identity and the caller’s session id. Request ids, trace ids and credentials are excluded, so a reconnect does not invalidate a reviewed action while a widened permission does.

Q: Does approving in the console make the agent carry on?
A: No. Token Observe has no channel that reaches an agent; event delivery goes to webhooks, Slack, Teams and email, all human channels. An approval is a permission the agent redeems by repeating the identical request with the approval id, so clicking approve moves nothing until it tries again. The console says so, and shows an approved-but-unspent approval in its own state.

Q: Can the same approval be used twice?
A: No. Consumption is a guarded update stamping the row only if it is still approved, unspent and unexpired; the loser changes nothing, is told the approval was already consumed, and executes nothing.

The long-form detail on this capability (the anchored sections, the worked policies and the error envelopes) is on the page itself at https://tokenobserve.com/platform/human-approvals.
