Skip to content

The x402 flow

x402 revives the dormant HTTP 402 Payment Required status into a real protocol: a server states its price in a structured challenge, a client answers with a proof, and the server verifies and delivers. This page is the wire-level view of that exchange — useful when you’re debugging a 402, or building a client or server by hand.

Every payment is three HTTP headers, exchanged across two requests. PipRail carries each as a lowercase, base64-JSON header — no X- prefix.

When a client hits a gated resource without payment, the server returns 402 with a payment-required header carrying a base64-JSON challenge. The challenge lists one or more accepts entries — each a rail it will take:

{
"x402Version": 2,
"resource": { "url": "https://api.example.com/report" },
"accepts": [
{
"scheme": "onchain-proof",
"network": "eip155:8453", // Base, as CAIP-2
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC
"amount": "100000", // base units (0.10 USDC, 6 decimals)
"payTo": "0xYourWallet",
"maxTimeoutSeconds": 120,
"extra": {
"nonce": "", // one-time, binds the proof to this challenge
"decimals": 6,
"minConfirmations": 1,
"amountFormatted": "0.10", // human-readable, so the client can render it
"symbol": "USDC"
}
}
]
}

2. The signature / proof (client → server)

Section titled “2. The signature / proof (client → server)”

The client pays on-chain, then re-requests the resource carrying a payment-signature header (PipRail also accepts the v1 x-payment header). For PipRail’s onchain-proof scheme the payload references the on-chain transaction — { nonce, txHash }, the challenge nonce plus the proof ref (an EVM tx hash, a Solana signature, a TON locator, …). For the standard exact scheme the payload carries a signed EIP-3009 authorization instead.

On success the server returns 200 plus a payment-response header (v1 fallback: x-payment-response) carrying a base64-JSON X402Receipt — a durable record of what settled:

{
"scheme": "onchain-proof",
"success": true,
"network": "eip155:8453",
"transaction": "0x…", // the settled on-chain tx (was `txHash` pre-v2)
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amount": "100000",
"payer": "0x…",
"payTo": "0xYourWallet",
"verifiedAt": "2026-06-10T12:00:00.000Z"
}

The settled tx lives in transaction, not the submit-time payload.txHash — they differ on TON/NEAR, where the proof ref is a composite locator rather than the final tx id.

PipRail speaks two payment schemes:

  • onchain-proof (default) — the payer broadcasts their own transfer and proves it. No facilitator, works on every family. This is PipRail’s native rail.
  • exact (opt-in) — the ratified x402 EVM scheme using EIP-3009 signed authorizations. Turn it on to pay any standard x402 server (see the exact buyer) or to get paid — optionally gasless, by delegating settlement to a free facilitator like PayAI that broadcasts on Base and pays the gas (see the exact rail seller).

CAIP-2 networks and chain-native asset ids

Section titled “CAIP-2 networks and chain-native asset ids”

x402 identifies the network with CAIP-2 (eip155:8453 for Base, solana:…, etc.). The asset, though, is the raw chain-native identifier, not CAIP-19: an ERC-20 0x… address on EVM, an SPL mint on Solana, a jetton master on TON, CODE:ISSUER on Stellar, or the literal 'native' for the chain’s coin. PipRail fills both in for you — you name a friendly chain and token, and it emits the right network + asset.

The high-level PipRailClient and createPaymentGate cover the 99% case. If you need the raw codecs — parseChallenge, buildChallengeHeader, buildSignatureHeader, parseReceipt, and the HEADER_* constants — they’re exported for hand-rolled clients and servers. See Wire format codecs.