A spend token only ever narrows. It cannot widen a policy, raise a cap, or authorize
something policy would refuse. It is a self-imposed constraint an agent commits to in advance,
not a grant of authority.
When you would use one
The pattern is a planning step that runs before an execution step, often in a different process or a different agent. A planner decides it will buy one thing from one vendor for at most $200. It mints a token pinned to that vendor at that ceiling and hands the token id to whatever does the buying. The executor cannot then spend more, spend it twice, or spend it somewhere else, even though it holds an agent key whose policy would allow all three. Without the token, the executor’s authority is whatever the policy allows for the rest of the budget. With it, the authority is what the planner actually intended.Minting one
201 Created
counterparty and expires_at are both optional. A token with neither is just a one-shot
ceiling, and one with no expires_at never expires: it sits issued until something spends it.
Set an expiry when the plan it encodes has a shelf life, which is most of the time.
Spending against one
Cite it by id on the payment:How it is evaluated
The token is checked first, and it can only refuse. If it refuses, the policy engine never runs.
If the token passes, normal policy evaluation runs on top. A token for 150 authorizes 200. The tighter constraint always wins.
Because the token short-circuits, a token refusal is the one denial that carries an empty
policy_snapshot and an empty headroom. No policy ran, so there is nothing to report.
On any non-denied outcome the token is consumed and moves to status: consumed. It cannot be
presented again.
Lifecycle
status moves from issued to consumed, or to expired when its expires_at passes.
Expiry is swept in the background and emits both a spend_token.expired audit event and a
spend_token.expired webhook, so you can react to a plan that was made and never executed.
There is no endpoint that cancels an unused token.
Consumption races safely: if two payments cite the same token at once, exactly one consumes it.
The loser releases its budget reservation and the intent moves to failed with
spend_token_unusable.
Reading them back
Minting is agent-side only. From the dashboard side the tokens are read-only:Next steps
Writing a policy
The limits a token narrows, rather than replaces.
Holding spend for a person
What an approver sees, including the token.