Every call,
paid for.
Tollstile is open-source payment middleware for APIs and MCP tools. Price a route in one line. Decide who pays, when the money moves, and what happens when the work fails. Accept x402, MPP or any rail underneath, 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