Every call,
paid for.
Tollstile is open-source payment middleware for APIs and MCP tools. Price a route in one line, accept any 402 protocol, and keep every receipt in your own database.
$ npx create-tollstileimport { NextResponse } from "next/server";
import { paid } from "@tollstile/next";
import { toll } from "@/lib/toll";
export async function POST(request: Request) {
export const POST = paid(toll.price("$0.04"), async (request) => {
const result = await generate(await request.json());
return NextResponse.json(result);
}
});Two imports and one wrapper. The body of your route handler stays as it is.
- gate
- closed
- ledger state
- — (the quote is signed, not stored)
Challenge. No payment yet. One signed quote, bound to this request, offered on every rail you accept.
HTTP/1.1 402 Payment Required { "error": { "code": "payment_required", "action": "pay" }, "price": "$0.04", "accepts": [{ "rail": "x402" }, { "rail": "mpp-stripe" }]}Simplified exchange. Real challenges follow each rail’s specification. Run the real thing on demo.tollstile.com.
Seven parts, one gate.
Protocols decide how a payment is proven. Everything around that — who pays, when money moves, what happens when your handler fails — is what every merchant ends up building. Tollstile is that part.
- 01
Price
A signed quote fixes it. Never the client.
toll.price("$0.04") - 02
Access
Decide who has to pay at all.
access: [subscriber(), …] - 03
Verify
Check the proof on any rail you accept — once.
rails: [x402(…), mppStripe(…)] - 04
Settle
Choose when money moves, out loud.
flow: "authorization" - 05
Fulfill
Mark the moment the service actually exists.
payment.fulfill() - 06
Refund
Handler failed? Release or refund. Never twice.
automatic - 07
Record
Every transition, in your own database.
ledger: postgresLedger(…)
The whole policy fits next to the handler.
import {
createTollstile, subscriber, credits, payPerCall, limit,
} from "tollstile";
import { paidTool } from "@tollstile/mcp";
import { x402 } from "@tollstile/x402";
import { mppStripe } from "@tollstile/mpp";
import { postgresLedger } from "@tollstile/postgres";
const toll = createTollstile({
rails: [x402(x402Options), mppStripe(stripeOptions)],
ledger: postgresLedger({ query, transaction }),
secret: process.env.TOLLSTILE_SECRET,
});
paidTool(server, "generate_image", { inputSchema },
toll.price("$0.04", {
access: [
subscriber({ active }),
credits({ balance }),
payPerCall(),
],
require: [limit({ spendPerDay: "$20" })],
}),
async (input, { payment }) => ({ content: await generateImage(input) }),
);- L10
Rails
How agents can pay. Add or remove one without touching a handler.
- L11
Ledger
Where the truth lives. Your database, your schema.
- L16
Price
Declared by the server, checked against every proof.
- L17
Access
Tried in order. Subscribers pass, credits draw down, the rest pay per call.
- L22
Require
Conditions every request must meet, like a daily spend cap per payer.
Rails, now and next.
Every rail declares what it can do. A route that needs a capability its rail lacks refuses to start.
Full roadmap| Rail | Pays with | Use | Target |
|---|---|---|---|
| test | Local rail | 402 → 200 without a wallet | v0.1 |
| x402 exact | Stablecoin | Fixed price per call | v0.1 |
| mpp charge | Stablecoin · card | One payment per call | v0.1 |
| x402 upto | Stablecoin | Authorize a ceiling, settle what ran | v0.1 |
| mpp session | Stablecoin | Many calls, one channel (experimental) | v0.1 |
| l402 | Lightning | Bitcoin over Lightning | v0.1 |
| kyapay | Stablecoin | Agent identity with payment | v0.1 |
The fine print, printed large.
Tollstile guarantees
- A priced handler never runs without granted access or a verified payment.
- Retries, replays, and crash recovery never settle or refund twice.
- Every transition is written to your ledger before it is acknowledged.
- When an outcome is unclear, the payment is marked unknown and reconciled.
Tollstile does not promise
- Your handler running exactly once.
- The response reaching the client.
- Recovering costs your handler already incurred.
- How a rail’s provider behaves.
Stripe moves the money.
Tollstile works the gate.
Use Stripe, Coinbase, or any provider behind a rail. Tollstile sits in your app, decides who gets through, and keeps the record. It charges nothing and never holds funds.
How Tollstile compares