This is the practical companion to What Is x402? — actual code for the client side: catching a 402, choosing how to pay, settling it, and retrying successfully.
The shape of the problem
Handling x402 correctly means treating 402 as an expected, structured response — not an error to catch and give up on. The response body tells you everything you need:
{
"x402Version": 2,
"accepts": [
{ "scheme": "exact", "network": "eip155:8453", "payTo": "0x...",
"asset": "0x...USDC", "amount": "10000", "maxTimeoutSeconds": 120 }
]
}JavaScript: a minimal client
async function callX402Resource(url, wallet) {
let res = await fetch(url);
if (res.status !== 402) return res; // already free, or an unrelated error
const { accepts } = await res.json();
// Pick the first option your wallet can actually settle — in practice,
// filter by network (does your wallet hold funds there?) and by asset.
const option = accepts.find((a) => wallet.supportsNetwork(a.network));
if (!option) throw new Error('no payable option for this wallet');
// Settling is wallet/library-specific. A facilitator-backed client
// (see the x402 protocol guide) reduces this to a sign + submit call —
// you are not writing raw transaction construction code here.
const paymentSignature = await wallet.pay(option);
res = await fetch(url, {
headers: { 'PAYMENT-SIGNATURE': paymentSignature },
});
return res; // 200 with the resource, or another 402 if payment didn't verify
}Python equivalent
import httpx
def call_x402_resource(url: str, wallet) -> httpx.Response:
res = httpx.get(url)
if res.status_code != 402:
return res
accepts = res.json()["accepts"]
option = next((a for a in accepts if wallet.supports_network(a["network"])), None)
if option is None:
raise RuntimeError("no payable option for this wallet")
payment_signature = wallet.pay(option)
return httpx.get(url, headers={"PAYMENT-SIGNATURE": payment_signature})Real-world details that matter
- The quote expires.
maxTimeoutSecondsmeans the amount and any embedded reference are only valid for that long. If your agent evaluates a bunch of options before deciding, re-fetch the 402 right before paying rather than using a stale quote. - Retry once, not in a loop. A second 402 after you paid usually means the payment didn't verify (wrong amount, wrong network, expired quote) — not that you should keep retrying the same broken payment. Surface the error.
- Pick the cheapest viable option, not the first one. Multi-network resources often list the same USD price across several chains; if your wallet holds funds on more than one, compare actual gas/settlement cost, not just the listed amount.
- Budget checks belong before the request, not after. If your agent has a per-task spending limit, check the resource's price via the JSON record or an MCP
get_pricingcall before making the first request at all — don't rely on catching the 402 as your only price discovery.
Using the MCP tool instead of raw HTTP
If your agent already speaks MCP, get_pricing on Agent Bazaar's MCP server gives you a resource's accepts[] without an extra round trip:
curl -X POST https://bazaar.saylorinnovations.com/mcp \
-H "content-type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"get_pricing","arguments":{"slug":"solana-token-security-intelligence"}}}'You still pay directly against the resource's own endpoint, not through MCP — the tool call just saves you a lookup.
Testing without spending real money
Start with the free discovery endpoints (/discovery/search costs nothing) to confirm your agent's HTTP plumbing works, then move to a low-cost resource like Solana Token Price ($0.001) to validate the full payment round trip before wiring up anything expensive.