Test x402 payment flows locally.
A pricing bug in production charges real money or gives work away free. Test the 402 challenge, the payment, and the receipt on your laptop and a testnet before a single mainnet cent moves.
x402 development has a property most API work doesn't: bugs are financial. Quote the wrong amount and you overcharge agents or undercharge yourself; gate the handler wrong and you serve unpaid requests. The flow deserves the same test rigor as a checkout page.
The good news is the whole protocol is inspectable with tools you already have. A 402 challenge is an HTTP response with JSON payment requirements, and Base has a testnet — so every layer can be exercised locally before real USDC is involved.
Layer 1: inspect the challenge with curl
Start your server locally and hit a priced endpoint with no payment attached. You should get HTTP 402 and a payment-requirements payload — the amount, the asset, the network, and where to pay. This single request catches the most common integration bugs: a wrong price, a missing 402 on a route you meant to gate, or a 402 on a route you meant to leave open.
Check every priced route this way, including error paths. A route that returns 500 before issuing its 402 leaks information about your handler running unpaid.
curl -i -X POST http://localhost:3000/api/lookup \
-H 'content-type: application/json' \
-d '{"query":"test"}'
# Expect:
# HTTP/1.1 402 Payment Required
# { "accepts": [ { "maxAmountRequired": "10000", <- $0.01 in USDC base units
# "network": "base-sepolia", ... } ] }Layer 2: end-to-end on Base Sepolia
Base Sepolia is the testnet twin of Base: same mechanics, worthless tokens. Point your server's payment configuration at the testnet, fund a throwaway wallet with test USDC from a faucet, and run a paying client against your local server. Most facilitators support a testnet mode — check your facilitator's docs for the exact configuration.
Now assert the full loop: the client pays, settlement completes, the handler runs exactly once, and the response carries a signed receipt. This is also where you verify amounts precisely — USDC has six decimals, and unit confusion (a $0.01 price encoded as 10000 base units, not 0.01) is the classic first-integration bug.
Layer 3: test the failure paths on purpose
The unpaid path is the one that costs you money if it's wrong. Send requests with no payment, a malformed payment payload, an amount below the quote, and a previously used payment — every one must be rejected without your handler executing. Put a counter or log line inside the handler so 'did not run' is observable, not assumed.
Replay deserves its own test case: capture a successful payment payload from one request and resubmit it. If the second attempt returns a result instead of a 402-class rejection, you have a replay hole to close before launch.
Make it a regression suite, not a ritual
Everything above scripts cleanly: the curl checks become integration tests asserting status codes and quoted amounts, the Sepolia loop becomes a CI job with a funded test wallet, and the failure-path battery runs on every change to payment code. Pricing config has a way of drifting during refactors; tests that pin the quoted amount catch it.
Keep a small assertion on the receipt too — that it exists and verifies against the signing key. Receipts are your audit trail in production, so a change that silently drops them should fail CI, not surface in a dispute.
Going live: the switch list
Cutover is configuration, not code: switch the network from Base Sepolia to Base, point settlement at your real wallet, and confirm the production price — minimum $0.01 per call on Loomal — is what your 402 actually quotes. Then make one real paid call yourself and reconcile it: the response succeeded, the receipt verifies, and the USDC arrived in your wallet on Base.
That single mainnet call, checked end to end, is the cheapest insurance available: from that point on, settlement is final and there are no chargebacks to undo a misconfiguration.
FAQ
Can I test without touching a blockchain at all?
Mostly, yes. The 402 challenge, route gating, amount quoting, and rejection paths are pure HTTP and test fine with curl or any HTTP test framework. Only the settlement step itself needs a network, and Base Sepolia with faucet USDC covers that without real money.
Where do I get test USDC for Base Sepolia?
From a testnet faucet — Circle operates one for test USDC, and Base ecosystem faucets cover Sepolia funds. Amounts are tiny but per-call prices are too: a faucet allocation funds hundreds of $0.01-scale test payments.
What's the most common bug local testing catches?
Amount encoding. USDC uses six decimal places, so $0.01 is 10000 in base units — off-by-a-factor errors quote prices 100x or 1,000,000x off. The second most common is a handler reachable without settled payment, which is why 'handler did not run' needs to be a tested assertion.
Do testnet and mainnet behave identically?
The protocol mechanics do — same challenge format, same signing, same settlement flow on a chain with Base's behavior. What differs is configuration: network name, USDC contract, facilitator endpoint, and your payout wallet. Keeping those in environment config makes the cutover a variable change you can review.
Test it, then price it.
When the flow passes on Sepolia, go live and get paid per call.