npm packages are not installable yet: [email protected] can be published after 2026-09-16 10:30 UTC. Details
Tollstile

Consent

Who agreed to a charge when an agent is the one calling, and which of those agreements a merchant can actually enforce.

Public Beta · early access

When a person buys something, one agreement covers everything: they saw the price and they paid it. When an agent calls a paid API, that single agreement splits into three, and they are easy to confuse.

AgreementWho makes itCan the merchant see it?
The money may be spentThe payer, when they signed the proof or funded the credentialYes — it is the proof, and its limit
This call is worth paying forThe client, against a budget its owner setNo
A person agreed to this amountWhoever is at the client, if anyone asksOnly if the merchant asks

Tollstile is the merchant's side of this. It can hold the first agreement to its terms and it can ask for the third. It has no view of the second, and it never holds the wallet.

What the merchant enforces

  • The server decides the price. Amount, asset, network, and recipient come from the route and the signed quote — never from the client's payload.
  • A quote is bound to the request it priced. A cheap quote cannot pay for a bigger request.
  • A proof is spent once. Replay is refused at the ledger, not in memory. See Authorizations and charges.
  • A maximum, then what was used. upTo() authorizes a ceiling and settles the amount the handler reports; the payer is never charged past what they authorized.
  • Caps per payer. Spend limits refuse calls over a rate or an amount, whatever the payer's credential allows.
  • A retry is not a second charge. Idempotency answers a repeat from the ledger.

None of that requires a person to be present. It is what makes an unattended agent safe to charge.

Asking a person

A client approves the tool, not the amount — and "always allow" removes even that. So a paid call can be charged repeatedly without anyone seeing a price.

Over MCP, a server can ask. paidTool(..., { approval }) puts the amount in front of the person at the client, after the payment is verified and reserved and before the handler runs, and charges only if they accept. Anything else releases the reservation and charges nothing.

What clients do today, measured rather than assumed. A server learns what a client can do from its initialize, and the answers are not what the published matrices say: Claude Code 2.1.186 declares elicitation: { form: {} } — asked to approve $0.25, it showed the person an Accept / Decline dialog, and the charge settled only after they accepted. It declares no url, so it cannot be sent to a page. OpenAI's codex-mcp-client declares both, and does open the page. Claude Desktop declares neither. So a merchant who needs the person to see something should assume the plainest channel: the text the model reads. The demo publishes what every client that connects to it declared, at /api/clients.

Ask for what is worth interrupting someone over. above keeps small calls quiet; a maximum a person approves once, through upTo(), beats a question per call.

HTTP has no equivalent today. A 402 goes to the agent, which is the party that pays; there is no channel from the merchant to the person behind it. A payer who wants a human in that loop puts them in the wallet, not in the API.

What Tollstile does not know

  • Whether a person exists behind a call at all.
  • Whether the client's owner set a budget, or what it is.
  • Whether a client that declares it can ask a person will really show them anything.
  • On a stateless HTTP server, whether a person answered: the answer arrives on a later request that the server which asked is no longer waiting for. Such a server refuses the charge rather than guessing.

A merchant who needs the charge to be approved must require the approval and refuse without it. Anything softer is a charge nobody agreed to.

On this page