What you will set up
A clear charging structure for an AI agent that sells one or more services, settled in USDC on Base. By the end you can charge a flat price for one service, charge different prices for different services, and run free routes alongside paid ones, all configured in one place. This page is about the mechanics of structuring charges, not the decision of whether to charge (that is how-to-monetize-ai-agent) or the full build (that is how-to-build-a-paid-ai-agent). The payment API product page is the broader reference.
The pricing table is the unit of charging
Everything about charging flows from one idea: the x402 server adapter charges by route, and the pricing table is where you declare what costs what. Each entry maps a METHOD path to a price, a payToAddress, and a paymentRequestId. A route in the table is paid; a route absent from it is free.
That single rule answers most charging questions. One price for everything on a path. Different prices mean different paths. A free tier is just routes you leave out of the table. There is no separate billing config, no per-customer plan, no metering engine, just a map of routes to prices that the adapter reads when it starts. Once you internalize that the table is the whole charging surface, structuring charges becomes a question of how you lay out your routes, which is a design decision you control completely.
Prerequisites
- A Blockchain0x account with an agent created, so it has a wallet to receive into.
- A
sk_test_key, the agent's wallet address (payToAddress), and apaymentRequestIdfor each priced route. - Node 18 or newer. The SDK targets
>=18.
export B0X_API_KEY=sk_test_...
export B0X_PAYTO_ADDRESS=0x...Charge for one service
Start with a single priced route. Register the adapter with one pricing entry.
import Fastify from "fastify";
import { createClient } from "@blockchain0x/node";
import { createX402Plugin } from "@blockchain0x/x402/server/fastify";
const sdk = createClient({ apiKey: process.env.B0X_API_KEY! });
const app = Fastify();
await app.register(createX402Plugin, {
sdk,
defaultNetwork: "testnet",
pricing: {
"POST /summarize": { amountUsdc: "0.02", payToAddress: process.env.B0X_PAYTO_ADDRESS!, paymentRequestId: "pr_summarize" },
},
});
app.post("/summarize", async (req) => runSummarize(req.body)); // runs only once paid
await app.listen({ port: 8080 });An unpaid call to /summarize gets a 402 quoting two cents; a paid call runs. That is charging for one service.
Charge different prices for different services
To charge different amounts, give each service its own route and its own pricing entry. The table holds as many as you need.
pricing: {
"POST /summarize": { amountUsdc: "0.02", payToAddress: PAY, paymentRequestId: "pr_summarize" },
"POST /research": { amountUsdc: "0.10", payToAddress: PAY, paymentRequestId: "pr_research" },
"POST /deep-report": { amountUsdc: "0.50", payToAddress: PAY, paymentRequestId: "pr_report" },
},Now a cheap summary, a mid-priced research call, and an expensive deep report each charge their own amount, and each quotes its own price in its 402. This is how you express tiers: not a plan a caller subscribes to, but a set of routes priced to match the work each one does. Price each route from its real cost and value, the way how-to-monetize-ai-agent describes, and let callers pick the route that fits their need.
Run a free tier alongside paid
A free tier is routes you leave out of the pricing table. Keep discovery, health, and any cheap helper on unpriced paths so callers can find and evaluate the agent without paying.
app.get("/capabilities", async () => listServices()); // free: never in the pricing table
app.post("/summarize", async (req) => runSummarize(req.body)); // paidThis freemium shape is the one that converts: callers reach the free routes, see what the agent does, and pay only for the premium work. Gating discovery behind a charge is the most common way to lose callers before they ever pay, so keep the front door free.
Design routes around what you charge for
Because charging is per route, the way you lay out routes is the way you structure your pricing, so design them on purpose rather than by accident.
A good rule: one route per unit a caller would think of as one purchase. If a caller would say "I bought a summary" or "I bought a research report", each of those is a route. Do not bundle a cheap and an expensive operation onto one path, because you can only put one price on it and one of them ends up mispriced. Equally, do not split a single logical purchase across two paid routes, because then a caller pays twice for what they think of as one thing and feels nickel-and-dimed.
Watch out for routes whose cost varies wildly with input. A summarize route that costs a fraction of a cent on a paragraph but dollars on a book is hard to price as one number. Either cap the input so the cost stays in a tight band, or split it into a standard route and a large route at different prices. The goal is that every priced route has a cost you can predict well enough to set a fair price, because a route you cannot price confidently is one you will either lose money on or overcharge for.
Confirm and test
Test the charging structure on Base Sepolia before going live. For each priced route, call it with no payment and confirm the 402 quotes the right amount; then pay it from a test wallet and confirm the handler runs. Confirm the free routes return without a 402. Watch the payment.received events to see which services actually earn.
import { webhooks } from "@blockchain0x/node";
// in a raw-body webhook route:
const r = webhooks.verify({ headers: req.headers, rawBody: req.body, secret: process.env.B0X_WEBHOOK_SECRET! });
if (r.ok && r.eventType === "payment.received") recordEarning(JSON.parse(req.body.toString("utf8")));When every route charges what you intended and the free routes stay free, swap to a sk_live_ key for Base mainnet and re-check the prices and wallet address on the live agent.
What the caller sees
It helps to picture the charge from the other side. A caller hits your priced route, gets a 402 that quotes the exact amount, network, and payee, settles it from their wallet, and retries with an X-Payment header to get the result. They never fill in a form, create an account, or store a card. From their runtime's view, your service is a route that costs a known amount per call, and paying it is one automatic step. That simplicity is the reason per-call charging reaches callers a signup funnel never would: the cost to a new caller of trying your service is one small, automatic payment rather than an onboarding flow.
Common pitfalls
Three traps when structuring charges.
One price for genuinely different work. Putting a cheap summary and an expensive report on the same path forces one price on both, so one subsidizes the other. Split them into routes.
Gating the free tier. Discovery and evaluation routes belong outside the pricing table. Charging for them costs you callers who would have paid for the real work.
Treating per-call as per-outcome. The adapter charges per request, so shape routes around units of value. If one call does wildly variable work, split it so each route's price matches its cost.
What to ship today
Register the adapter with one priced route, confirm an unpaid call gets the right 402 and a paid call runs, then add a second route at a different price to express a tier. Keep discovery free. Watch payment.received to see what earns. For pricing strategy, see how-to-monetize-ai-agent; for the full build, how-to-build-a-paid-ai-agent. Pricing for the platform is on the pricing page.