Idempotent by default
A retry with the same payment gets the stored response, not a second charge. Agents with flaky networks stop costing you support tickets.
{ never twice }
for sellers · apis + mcp tools
Put a USDC price on any route or MCP tool. Agents pay over x402 and the money settles to your wallet through Coinbase CDP, PayAI or thirdweb, from any country. We never touch it.
npm i @coinslot/paywallpackages land on npm with v0.1 — until then install from the repo
{ pay per call }
app.use("/v1/*", paywall({
payTo: process.env.WALLET!,
routes: {
"GET /v1/fact": "$0.001",
"POST /v1/search": "$0.01",
},
}))One price for a whole prefix, or a price per route. Prices are dollar strings and settle in USDC.
app.use("/v1/*", paywall({
payTo: process.env.WALLET!,
routes: {
"GET /v1/fact": "$0.001",
"POST /v1/search": "$0.01",
},
}))payTo is your address. The facilitator settles each payment straight to it. Nothing sits in between.
paywall({ price: "$0.002", payTo: "0xYourAddress", network: "base", facilitator: "cdp" })Run your server with network "base-sepolia" and make one real paid request with test USDC. You'll see the 402, the payment and the 200.
npx @coinslot/cli test http://localhost:3000/v1/factSwitch the network to base or solana. Add a receipts key if you want the hosted dashboard. Ship.
paywall({
price: "$0.002",
payTo: process.env.WALLET!,
network: "base",
receipts: { apiKey: process.env.COINSLOT_API_KEY },
})for sellers · apis + mcp tools
Put the middleware in front of any route or MCP tool. Agents get a 402 with your price, pay in USDC and get the response. The money settles to your wallet through the facilitator you choose.
{ pay per call }
import { Hono } from "hono"
import { paywall } from "@coinslot/paywall/hono"
const app = new Hono()
app.use("/v1/*", paywall({
payTo: process.env.WALLET!, // your address: USDC settles here
network: "base-sepolia", // "base" when you go live
routes: {
"GET /v1/fact": "$0.001",
"POST /v1/search": "$0.01",
},
}))
app.get("/v1/fact", (c) => c.json({ fact: "Octopuses have three hearts." }))
export default appimport express from "express"
import { paywall } from "@coinslot/paywall/express"
const app = express()
app.use("/v1", paywall({ price: "$0.002", payTo: process.env.WALLET! }))
app.get("/v1/fact", (req, res) => {
res.json({ fact: "A day on Venus is longer than its year." })
})
app.listen(3000)// app/api/fact/route.ts
import { withPaywall } from "@coinslot/paywall/next"
export const GET = withPaywall(
{ price: "$0.001", payTo: process.env.WALLET! },
async (req) => Response.json({ fact: "Bananas are berries. Strawberries aren't." }),
)import { paidTool } from "@coinslot/paywall/mcp"
import { z } from "zod"
server.tool(
"search",
{ query: z.string() },
paidTool({ price: "$0.002", payTo: process.env.WALLET! }, async ({ query }) => ({
content: [{ type: "text", text: await search(query) }],
})),
)The facilitator submits the transaction, and its own pricing applies. Coinbase CDP, for example, gives a free monthly allowance and then bills the seller a small fee per transaction. Coinslot takes no fee.
The default. CDP sets its own pricing: a free monthly allowance, then a small fee per transaction, billed to the seller. Coinslot adds nothing on top.
paywall({ price: "$0.002", payTo, facilitator: "cdp" })A retry with the same payment gets the stored response, not a second charge. Agents with flaky networks stop costing you support tickets.
{ never twice }
Cap each paying wallet, say 60 calls a minute, so one agent with a full wallet can't crowd out the rest.
{ 60 / min / payer }
Send each settled payment to the hosted dashboard: revenue per endpoint, payers, errors and responses that never got delivered.
{ every cent, logged }
Optionally list your endpoint in the x402 Bazaar so agents can discover it. One description string.
{ get found }
Telegram or email when errors spike or a paid call goes unanswered. Part of the hosted dashboard.
{ know first }
Every row is a settled payment with a link to the explorer. Filter by endpoint, payer or status, and see which paid calls failed to deliver.
| Endpoint | Price | Calls | Revenue | Delivered |
|---|---|---|---|---|
| POST /v1/search | $0.01 | 1,904 | $19.04 | 99.7% |
| POST /v1/summarize | $0.005 | 2,210 | $11.05 | 99.8% |
| GET /v1/fact | $0.001 | 9,812 | $9.81 | 99.9% |
| GET /weather/now | $0.001 | 5,322 | $5.32 | 100% |
| mcp · pdf.extract | $0.003 | 1,230 | $3.69 | 99.4% |
faq
{ pay per call }
No. You need a wallet address that can receive USDC. The facilitator verifies each payment and settles it on-chain.
Yes. Paywall speaks plain x402 V2. Any x402 client can pay, with or without Coinslot on its side.
The facilitator submits the transaction, and its own pricing applies. Coinbase CDP, for example, gives a free monthly allowance and then bills the seller a small fee per transaction. Coinslot takes no fee.
Yes. There's no country gate in the SDK. You need a wallet and a facilitator that serves you.
The dashboard shows paid calls that didn't get a successful response, per endpoint, so you see them before your users do. One-click refunds from your own wallet are planned for v0.2.
Yes. Wrap a tool handler in paidTool({ price, payTo }) and every call to that tool requires payment.
{ pay per call }