Agents are good at deciding what data they need. They’ve learned to do what humans do – sign up for accounts, store API keys, manage credit cards – but this is far from ideal. Imitating humans is error prone, introduces unnecessary security risks, and simply copies economic inefficiencies.
Why sign up for an API subscription if only a little data is needed now? Why pay for more than you can use because you might need it later, or because the vendor doesn’t give you any other options? Why can’t an agent decide where to buy data each time it needs some?
x402 is an open payment standard that fixes this. No signups, no API key, no credit cards. Each transaction is independent of all others. It’s a payment standard that is completely in line with our emerging agentic economy.
This post explains the standard in plain terms and then shows how Testril, our pay-per-call blockchain indexer for agents, uses it.
x402 in one minute
x402 takes its name from HTTP status code 402, "Payment Required", which was reserved decades ago and barely used. The standard turns it into a simple handshake:
- A client asks for a resource.
- The server replies that payment is required, listing the price, who gets paid and which payment options it accepts.
- The client signs a payment, usually in USDC, and repeats the request with that proof attached (over HTTP, in a PAYMENT-SIGNATURE header).
- The server, often through a third party called a facilitator, verifies the payment, does the work, settles the payment and returns the result.
There are no accounts and no API keys. The standard is network-agnostic and transport-agnostic: the same messages can travel over plain HTTP or inside an agent protocol such as MCP. It also supports more than one payment "scheme". exact pays one quote with one transfer. batch-settlement lets a buyer deposit once and then sign cheap vouchers for many small payments.
How Testril uses it
Testril is an MCP server, so agents talk to it through tool calls, not raw HTTP. It speaks x402's MCP form directly: a paid tool is paid on the call itself, and a standard x402 client can pay it.
Ask for the work and get a quote. An agent calls materialize (index a block range) or read (fetch indexed data). If payment is due, the call returns an MCP error result. Its
structuredContentand first content block hold x402PaymentRequired, including the accepted payment options; its second content block holds Testril's itemised{quote_id, amount, lines}quote. Nothing has been computed or charged yet. The quote freezes the price and the work for 120 seconds.Repeat the call with the payment. The agent signs one of the offered options and sends the same call and arguments again, with the signed x402 payment in
_meta["x402/payment"]. Testril verifies and settles it through an x402 facilitator and does the work in that same call, returning the receipt in_meta["x402/payment-response"]. There's no separate pay step and no payment ID to carry around. A retried call with the same spent payment or x402payment-identifieris served again without a second charge; reusing an identifier for different work is refused aspayment_identifier_conflict.
A paid materialize answers materializing straight away with a job handle; the
agent follows it with inspect until it's done. A paid read returns its rows
directly. If you use Testril from Claude Code, Codex or Grok Build, the
published testril CLI holds your key and pays within budgets you set.
Here is an illustrative exchange for a 15-block materialize. Amounts are in USDC atoms (1 USDC = 1,000,000 atoms); IDs and addresses are placeholders.
// 1. request (illustrative)
{ "tool": "materialize",
"arguments": { "bound_function_id": "sha256:<id>", "from_block": 1000, "to_block": 1015 } }
// 1. response: x402 payment required (isError: true; illustrative)
{ "isError": true,
"structuredContent": {
"x402Version": 2,
"error": "payment_required",
"resource": { "url": "mcp://tool/materialize", "mimeType": "application/json" },
"accepts": [ {
"scheme": "batch-settlement",
"network": "eip155:84532",
"asset": "<USDC address>",
"payTo": "<receiver>",
"amount": "1800",
"maxTimeoutSeconds": 3600,
"extra": { "name": "USDC", "version": "2", "minDeposit": "10000",
"receiverAuthorizer": "<address>", "withdrawDelay": 3600 } } ] },
"content": [
{ "type": "text", "text": "<the PaymentRequired JSON above>" },
{ "type": "text", "text": "{\"quote_id\":\"quote:<uuid>\",\"amount\":{\"atoms\":\"1800\",\"usd\":\"$0.0018\"},\"lines\":[{\"label\":\"materialize_blocks\",\"units\":15,\"unit_price\":{\"atoms\":\"120\",\"usd\":\"$0.00012\"},\"amount\":{\"atoms\":\"1800\",\"usd\":\"$0.0018\"}}]}" }
] }
// 2. the same call again, with the signed payment attached
{ "tool": "materialize",
"arguments": { "bound_function_id": "sha256:<id>", "from_block": 1000, "to_block": 1015 },
"_meta": { "x402/payment": { "x402Version": 2, "accepted": { /* the accepts row, copied whole */ },
"payload": { /* signature */ } } } }
// 2. response: the work starts, with an x402 receipt
{ "outcome": "success", "result": "materializing",
"job": { "job_id": "job:<id>", "quote_id": "quote:<uuid>", "blocks_total": 15, "state": "running" },
"_meta": { "x402/payment-response": { "success": true, "network": "eip155:84532", "payer": "0x<wallet>" } } }
If settlement may have happened but Testril could not finish recording the
purchase, the result is outcome: "error" with
kind: "payment_recovery_pending" and a payment summary. Do not sign a new
payment. Retry the original paid call; Testril retains it and retries completion
even after restart. Quote expiry alone does not settle an unknown outcome.
The bound function's REST data URL uses the HTTP spelling of the same flow:
unpaid GET returns 402 with PAYMENT-REQUIRED and the quote body; paid GET sends
the base64 JSON PaymentPayload in PAYMENT-SIGNATURE and receives
PAYMENT-RESPONSE.
What things cost
Prices are in US dollars and settle in USDC. Today's rates are:
- Indexing: $0.00012 per block, including 24 hours of cache. If part of your range is already cached, you pay only for the missing blocks. Functions that track state from a contract's creation are billed from that block.
- Longer cache: $0.000001 per block per extra day, bought on the same quote.
- Reading: $0.00002 per query, plus $0.000001 per block returned. A 100-block read costs $0.00012.
These are currently hard-coded amounts that mirror industry standards for index creation and data reads, but they will soon be much more dynamic and mirror actual costs. Pre-AI this wasn’t possible, but when agents manage costs and are able to price small amounts of work on a continuous basis, the impossible becomes possible. Early modeling indicates that our hard-coded fees are too high!
Even today, most of these amounts are far below a cent. Quotes of $0.01 or more can be paid with exact: one USDC transfer per quote. Every quote can be paid with batch-settlement, which is how nearly every read is paid: the agent deposits at least $0.01 of USDC into an escrow once, then signs a cheap voucher for each call, and Testril collects many vouchers in one onchain transaction. That way an agent isn't paying network fees on a payment worth a fraction of a cent.
The NFT: cache, earnings and claims
Your first indexing purchase on a payment network gives your wallet an NFT there: a transferable ERC-721 that records your purchases and what you've earned. It is minted just after your purchase is served, so your data never waits for it. If you sell the NFT, its history goes with it, and your next purchase creates a new one.
When you index a range, you're supplying data that other agents may want. When someone later pays to read blocks you cached, part of the per-block read fee is credited to you as earned, and another slice extends how long your cache is kept. Popular data stays cached and keeps earning. Data nobody reads expires.
The NFT shows lifetime totals: paid, refunded, cost, earned, claimed, unclaimed and profit and loss. You withdraw earnings with claim_rewards, naming the NFT. Payouts go in USDC to whoever owns the NFT, once its unclaimed balance reaches $0.01. Below that, the claim succeeds but pays nothing, so dust doesn't cost more in fees than it's worth.
Where we are today
The reviewed development server reports Testril 0.14.0 and configured data
chains, but payment offers are request- and deployment-specific. Read the
connected server's accepts rows instead of inferring a testnet or mainnet,
asset, or receiver from this illustration. Prices are early and may change.
Closing
For an agent, the whole loop is three steps: see the price, pay exactly that, get the data. x402 provides the payment handshake, and Testril adds per-block pricing, refunds for the unspent part of a stopped materialize job, and an NFT that pays you when your cached data gets used. If you're building agents that need onchain data, see testril.si.