Skip to main content

x402 flow

XDC AI uses the x402 protocol: HTTP-native, pay-per-request payments. Payment is an off-chain signed authorization that a relayer settles on-chain — so the paying agent never holds gas.

Sequence

Agent Service Relayer / XDC
│ GET /x402/resource │ │
├─────────────────────────────▶ │
│ 402 Payment Required │ │
│ { accepts: [ amount, asset,│ │
│ payTo, network ] } │ │
◀─────────────────────────────┤ │
│ │ │
│ sign EIP-3009 transferWith- │ │
│ Authorization (USDC → payTo)│ │
│ │ │
│ GET /x402/resource │ │
│ X-PAYMENT: base64(auth) ────▶ verify signature + amount │
│ ├──────── settle authorization ──▶ on-chain USDC
│ │ (relayer pays gas) │ transfer
│ 200 OK + data ◀───────── confirmed ───────────┤
◀─────────────────────────────┤ │

Steps in detail

  1. Request. The agent calls the service URL with no payment.
  2. Challenge. The service returns 402 Payment Required with the requirements: scheme (exact), network (xdc), USDC asset, maxAmountRequired (base units), and payTo.
  3. Authorize. The agent signs an EIP-3009 transferWithAuthorization — an off-chain EIP-712 signature authorizing exactly the required USDC to payTo. No gas, no on-chain tx yet.
  4. Resend. The agent repeats the request with X-PAYMENT: <base64 of the signed authorization>.
  5. Verify. The service (via a facilitator) checks the signature, amount, recipient, and network.
  6. Settle. A relayer/sponsor submits the transferWithAuthorization on XDC and pays the gas. The USDC moves from the agent's wallet to the provider's payTo.
  7. Respond. The service returns 200 OK with the data.

Protocol versions: v1 and v2

XDC AI speaks both x402 v1 and the newer x402 v2. The 402 challenge advertises both at once, so the published CLI and any older client keep working while newer clients use v2. v2 changes only the envelope - the EIP-3009 authorization and the EIP-712 signing are identical, so nothing about the money movement changes. v2 on XDC AI is mainnet only (eip155:50).

How to tell a v2 challenge from a v1 one

Signalv1v2
Version fieldx402Version: 1x402Version: 2
Amount fieldmaxAmountRequiredamount
networklabel, e.g. "xdc"CAIP-2, e.g. "eip155:50"
extra{ name, version }adds assetTransferMethod: "eip3009"
Payment header (request)X-PAYMENTPAYMENT-SIGNATURE
Receipt header (response)X-PAYMENT-RESPONSEPAYMENT-RESPONSE

The most reliable check is the shape of each accepts[] entry: an entry with amount and an eip155:<chainId> network is v2; an entry with maxAmountRequired and a plain label is v1.

Dual advertisement

A single XDC AI 402 returns both entries in accepts[] (v1 first for back-compat, v2 second), and emits both receipt headers on settlement. So a client should scan accepts[] for a v2-shaped entry and prefer it, rather than trusting the top-level x402Version:

{
"x402Version": 1,
"accepts": [
{ "scheme": "exact", "network": "xdc", "maxAmountRequired": "100", "payTo": "0x…", "asset": "0xfA29…", "maxTimeoutSeconds": 120, "extra": { "name": "USDC", "version": "2" } },
{ "x402Version": 2, "scheme": "exact", "network": "eip155:50", "amount": "100", "payTo": "0x…", "asset": "0xfA29…", "maxTimeoutSeconds": 120, "extra": { "assetTransferMethod": "eip3009", "name": "USDC", "version": "2" } }
]
}

The xdcai CLI and the MCP connector auto-negotiate this: they prefer the v2 entry, sign once, and send the PAYMENT-SIGNATURE header. You never pick a version by hand.

Why gasless

EIP-3009 lets a third party submit a token transfer on behalf of the signer. The agent only ever signs; a sponsor relayer broadcasts and covers gas. That's why an agent wallet needs only USDC, never native XDC. See Wallet & gasless.

For implementers

  • The 402 amount is in USDC base units (6 decimals): 10000 = 0.01 USDC. Read it from amount (v2) or maxAmountRequired (v1).
  • The payment header is base64 of the signed authorization payload: send it as PAYMENT-SIGNATURE for v2, X-PAYMENT for v1.
  • Read the settlement receipt from PAYMENT-RESPONSE (v2) or X-PAYMENT-RESPONSE (v1); XDC AI emits both.
  • Settlement should be idempotent per nonce to make retries safe.
  • Advertised price / asset / payTo must match the 402 challenge.

See also: Make an x402 endpoint · Constants.