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

Use cases

What Tollstile is used for, what works today without waiting for anyone else, and what it is the wrong tool for.

Public Beta · early access

Tollstile prices a route or a tool and records what was charged. Who is calling — a person's browser, an agent with a wallet, a crawler, another team's service — changes what you configure, not the line you write.

The order below is deliberate: the first three need nothing from anyone else to work today.

Meter a paid product per call, and take the money once

The objection to per-call pricing is fees: nobody can charge a card for $0.01. So do not charge a card for $0.01.

Sell credits — $20 through your normal Stripe checkout, once — and meter calls against the balance. credits() reserves before the handler and commits or releases after, so a crash never loses or double-spends value, and the ledger shows every draw.

toll.price("$0.01", { access: [subscriber({ active }), credits({ balance }), payPerCall()] })

That line is the whole ordering: subscribers pass free, credit holders draw down, everyone else is asked to pay. No rail has to move money for a single call. This works today, with ordinary customers and ordinary cards.

See Add credits and Add subscriptions.

Cap and charge back your own agents, with no money moving at all

An internal agent that loops costs real money at the model provider, and the bill arrives as one number a month later. Tollstile gives every team a balance and every call a ledger row, with no payment involved: the "price" is an internal rate, the "payer" is the team.

toll.price("$0.004", {
  access: [credits({ balance, account: (context) => context.principal?.id })],
  require: [limit({ perPayer: "600/hour", spendPerDay: "$50" })],
})

A team over its cap is refused with 429 before the handler runs, not warned afterwards. Every draw is a charge in the ledger, settled against that team, so chargeback is a query rather than an estimate — spendSince() backs the dashboard.

Nothing here waits on a payment protocol, a wallet, or an agent standard. It is the ledger and the limits, used on their own.

Nothing to pay with, by construction

A route whose access list has no payPerCall() admits nobody by payment: a caller holding a perfectly valid proof is refused with access_denied before any rail is consulted. createTollstile() still wants a rail in its configuration — it is never reached here — so keep the test rail out of the instance you deploy, in case a later route does add payPerCall().

Charge AI crawlers instead of blocking them

Publishers have two answers to crawlers today: block them, or absorb them. A third is to sell access — the same content, on your terms, with a record of who took what.

  • verifiedAgent() admits only crawlers that sign their requests (Web Bot Auth), so "who is this" is answered by a signature, not a user agent string.
  • Sell each crawler operator a prepaid balance and meter requests against it, exactly as above. An AI company that will not wire up a wallet will still sign a contract and pay an invoice.
  • Price per route: an archive page and a live index are not worth the same.

The part that needs no one's cooperation is the metering and the audit trail. The part that does — a crawler that meets a 402 and pays it unattended — is real but early; see x402.

If Cloudflare's marketplace terms suit you, use it. Tollstile is for keeping your own terms, your own ledger, and your own relationship with the operator — or for not being behind Cloudflare at all.

Sell an API or an MCP tool to agents

The case Tollstile was built for. An agent meets 402 (or a payment-required tool result), pays with a rail you both support, and the call runs. Quotes bind to the request, so a cheap quote cannot pay for a bigger one; retries are answered from the ledger instead of charged twice.

paidTool(server, "forecast", { description: "Tomorrow in one word" }, toll.price("$0.01"), handler);

When the call is expensive, ask a person. A client approves the tool, not the amount, and "always allow" removes even that. approval puts the amount in front of whoever is at the client, and charges only if they accept — see Consent. For work a human fulfils later, authorize now and settle when it is done: the charge stays reserved until payment.fulfill(), and a call that could not be completed is released rather than refunded.

What is early here is the calling side: most MCP clients give a model no way to attach a payment at all, so paying is the client's job and few clients do it yet. Ship the merchant side now if your callers are your own agents, or if you are pricing for the clients that do.

Charge for what the work actually cost

Token counts, pages processed, seconds of audio — priced after the fact, not guessed before it.

toll.price(upTo("$0.50"))          // the payer authorizes a ceiling
await payment.fulfill({ amount })  // the handler settles what it used

The payer is never charged past what they authorized, and the difference is released. See Charge for usage.

When not to use Tollstile

  • Selling to people, not agents. A subscription, a one-off purchase, a cart — use Stripe, Paddle, or Lemon Squeezy directly. Tollstile would be a layer with nothing to do.
  • You want a payments provider. Tollstile never holds funds, never routes them through its own accounts, and settles nothing itself. It asks a rail's provider and records what happened. You still need a provider.
  • One price, one product, no metering. If nothing is counted per call, the ledger is overhead.
  • You need a hosted dashboard today. The ledger is yours, in your database. There is no console.

On this page