Skip to content

x402: HTTP 402 in native USDC

x402 is HTTP 402 Payment Required: a resource answers unpaid requests with a quote, the client signs, and a facilitator settles on chain. No account, no API key, no gas token.

On POA the unit is native USDC, not an ERC-20. Stock ExactEvm would call transferWithAuthorization on Ethereum mainnet USDC (0xa0b86991…) or Permit2. That is the wrong scheme here. The on-chain method is the NativeTransferAuth precompile at 0x2D00…0006, which implements the same EIP-3009-shaped ABI against state.accounts. Permit2 is unused. The facilitator cannot mint. Public GET /faucet stays unpublished.

SurfaceURL
Demo resourceGET https://poa.net/77/x402/demo — unpaid is HTTP 402 with PAYMENT-REQUIRED
FacilitatorGET https://poa.net/77/x402/facilitator/supported
POST https://poa.net/77/x402/facilitator/verify
POST https://poa.net/77/x402/facilitator/settle

The explorer page is https://poa.net/77/docs/x402. This is not the Agent Gateway (/77/agent/v1) and not the invite faucet (POST /77/agent/v1/faucet).

Terminal window
curl -sS -D - https://poa.net/77/x402/demo -o /tmp/x402-demo.json

Requirements advertise scheme=exact, network=eip155:77, asset=0x2D00…0006, and extra of assetTransferMethod=eip3009, paymentFlow=authorization, kind=native, EIP-712 name USDC, version 2, 6 decimals.

The 402 JSON body is the quote; the PAYMENT-REQUIRED header is that same JSON in Base64 — use the body. It has resource and accepts. PAYMENT-SIGNATURE is Base64 of this envelope — not the EIP-712 digest and not payload.authorization alone. Copy resource from the 402 as-is. 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. Copy addresses from the 402 as-is; their case may include a checksum. Omitting 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": "https://poa.net/77/x402/demo", "mimeType": "application/json", "description": "" },
"accepted": {
"scheme": "exact",
"network": "eip155:77",
"asset": "0x2d00000000000000000000000000000000000006",
"amount": "10000",
"payTo": "0x…",
"maxTimeoutSeconds": 60,
"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…"
}
}
}

POST /77/x402/facilitator/verify and settle take { "x402Version": 2, "paymentPayload": <envelope>, "paymentRequirements": <accepted> }.

Works today: an EOA that holds native USDC and can EIP-712-sign.

  1. Hold native USDC on chain 77 (bridge in).
  2. Sign EIP-712 TransferWithAuthorization for NativeTransferAuth (name=USDC, version=2, verifyingContract=0x2D00…0006, chainId=77). Amounts are 6-decimal USDC units.
  3. Retry the resource with PAYMENT-SIGNATURE set to Base64 of the envelope above. The public facilitator at /77/x402/facilitator/* is the same in-process facilitator the demo uses; it broadcasts transferWithAuthorization from a settler key. The demo returns 200 only after the settler tx is included with receipt status 0x1. A missing receipt is settlement_pending (402), not success. Worker 502/504 after settle does not mean the payment failed — reconcile the tx hash / (from, nonce) before signing again.
  4. The same (from, nonce) cannot settle twice. The operator-pool address (the genesis bridge operator, blocked from ordinary transfers) cannot be the EIP-712 from.

Assigned wallets: call POST /77/agent/v1/x402/authorize with an API bearer token that has transfer capability. Send the quote as payment_required and a fresh 32-byte hex nonce; the signer returns the payment authorization. This requires x402 enablement and an operator-approved amount and recipient. The MCP adapter does not wrap this endpoint. See Agent Gateway.

POA has no token contract. A client pointed at Ethereum mainnet USDC would debit the wrong chain. NativeTransferAuth is a closed precompile in the 0x2D00… set, same model as HTLC and bridge mint: Elixir, operator-shipped, no bytecode. Details: Precompiles.