Docs / x402
x402
Pay for an HTTP resource with native USDC. No account, no API key, no gas token. Not the faucet and not write RPC.
Pay from a wallet
- Unpaid
GET https://poa.net/77/x402/demoreturns HTTP 402. The JSON body is the quote (PAYMENT-REQUIREDis that same JSON in Base64 — use the body). - Hold native USDC (bridge in, or the invite faucet for an assigned wallet).
- An EOA signs
TransferWithAuthorizationlocally againstNativeTransferAuthat0x2d00000000000000000000000000000000000006(EIP-712 nameUSDC, version2— not Ethereum mainnet USDC0xa0b86991…, not Permit2, not an ERC-20). - Retry the same URL with a
PAYMENT-SIGNATUREheader. The demo returns 200 only after the settler tx is included with status0x1.
curl -sS -D - https://poa.net/77/x402/demo -o /tmp/x402-demo.json
Network is CAIP-2 eip155:77, scheme exact. Flow flags: extra.assetTransferMethod=eip3009, paymentFlow=authorization, kind=native. x402 amount and extra.decimals are 6 (same as explorer balances: 10000 is 0.01 USDC). JSON-RPC eth_getBalance uses 18 decimals on the wire — 1 USDC is 10^18 there, 10^6 here. See Network.
Replay. A missing receipt is settlement_pending (402), not success. Worker 502/504 after settle does not mean the payment failed: the settler may already have broadcast. Public JSON-RPC does not allow eth_call, so do not probe authorizationState that way. Retry the same PAYMENT-SIGNATURE (or POST /facilitator/settle with the same payload). A replay of (from, nonce) cannot debit twice. Do not sign a fresh authorization until that retry returns 200, settlement_pending, or a definitive payment-failed reason.
PAYMENT-SIGNATURE envelope
PAYMENT-SIGNATURE is Base64 of this envelope — not the EIP-712 digest, and not payload.authorization alone. Copy resource from the 402 body as-is: resource.url is whatever the server put there and may not be the public poa.net URL you requested. Copy the selected accepts[i] object as accepted. authorization.to must equal accepted.payTo, authorization.value must equal accepted.amount. validAfter / validBefore are unix seconds; keep validBefore within accepted.maxTimeoutSeconds of now. nonce is 32 random bytes. Missing resource.url or accepted is invalid_payload in the 402 JSON error field (and in PAYMENT-RESPONSE after a failed settle).
{
"x402Version": 2,
"resource": { "url": "<from the 402 body>", "mimeType": "application/json", "description": "…" },
"accepted": {
"scheme": "exact",
"network": "eip155:77",
"asset": "0x2d00000000000000000000000000000000000006",
"amount": "10000",
"payTo": "0x…",
"maxTimeoutSeconds": 180,
"extra": {
"assetTransferMethod": "eip3009",
"paymentFlow": "authorization",
"kind": "native",
"name": "USDC",
"version": "2",
"decimals": 6,
"symbol": "USDC"
}
},
"payload": {
"signature": "0x…",
"authorization": {
"from": "0x…",
"to": "0x…",
"value": "10000",
"validAfter": "0",
"validBefore": "…",
"nonce": "0x…"
}
}
}
Facilitator
GET https://poa.net/77/x402/facilitator/supported POST https://poa.net/77/x402/facilitator/verify POST https://poa.net/77/x402/facilitator/settle
POST /77/x402/facilitator/verify and settle take {"x402Version":2,"paymentPayload":<envelope>,"paymentRequirements":<accepted>}. The facilitator cannot mint. Anyone may submit transferWithAuthorization to 0x2d…06: the signature binds to (payTo) and a one-use nonce, so a front-run cannot redirect funds. The HTTP resource still needs the PAYMENT-SIGNATURE header. validBefore farther than maxTimeoutSeconds from now is rejected at verify/settle. Default timeout is 180 seconds.
Assigned wallets
Assigned wallets sign through POST /77/agent/v1/x402/authorize (invite bearer; the key stays in 2d-hsm). Then retry the resource with that header.
The Agent Gateway MCP does not wrap x402 yet — it has network, balance, faucet, and transfer only.