x402 Payment
How the x402 Gateway handles on-chain USDC payment.
Overview
The x402 protocol extends HTTP with payment semantics using the 402 Payment Required status code. When the gateway requires payment, it returns a 402 response with a machine-readable payment quote. The client signs an on-chain USDC transfer and retries the request.
With the SDK (autoPayment: true), this entire flow is handled automatically. This document explains the protocol internals for advanced developers and debugging.
How x402 works
The x402 protocol relies on EIP-3009 (transferWithAuthorization), an extension of ERC-20 that enables gasless, off-chain authorized transfers:
- The payer (agent) signs a transfer authorization off-chain — specifying
from,to,value, expiration time, and a randomnonce. - The signed payload is sent to the payee (gateway) via HTTP header.
- The payee forwards it to a Facilitator, which verifies the signature and broadcasts the transaction on-chain.
- The ERC-20 transfer executes — tokens move from payer to payee — and the Facilitator bears the gas cost.
This design means:
- No prior token approval needed (unlike standard ERC-20
approve+transferFrom) - Payer never submits on-chain transactions — no gas costs for the agent
- Single-use authorization — each signature is nonce-bound and can only be used once
Protocol flow
Protocol headers
| Header | Direction | Description |
|---|---|---|
PAYMENT-REQUIRED | Response | Base64 JSON quote (amount, network, asset, payTo) |
PAYMENT-SIGNATURE | Request | Base64 JSON payload with signed authorization |
PAYMENT-RESPONSE | Response | Settlement confirmation details |
Two billing models
The gateway uses two distinct payment models depending on the service:
| Service | Model | When payment happens |
|---|---|---|
| ZAN Node Service (RPC) | Credit prepurchase | Buy credits upfront, deduct per call |
| ZAN AI Service (MaaS) | Rolling settlement | First call free, settle previous call's cost on next call |
Model 1: Credit prepurchase (RPC)
Credits are purchased via x402 payment, then consumed per RPC call based on method weight.
How it works:
- Agent requests
POST /credits/purchase/default→ Gateway returns 402 + PAYMENT-REQUIRED quote - SDK signs an EIP-3009
transferWithAuthorizationfor the quoted USDC amount - Agent retries with
PAYMENT-SIGNATUREheader → Gateway calls Facilitator to verify and settle on-chain - Credits are added to the agent's balance → Agent can now make RPC calls (credits deducted per method weight)
Credit bundles
| Network Type | Price | Credits | Approx. Calls |
|---|---|---|---|
| Mainnet | 0.015 USDC | 100,000 | 5,000 – 20,000 |
| Testnet | 1 USDC | 100,000 | 5,000 – 20,000 |
PAYMENT-REQUIRED quote (decoded)
{
"x402Version": "2",
"error": "payment_required",
"message": "Payment required to purchase default credits bundle",
"accepts": [
{
"scheme": "exact",
"network": "eip155:8453",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"payTo": "0xC26...",
"maxAmountRequired": "15000"
}
]
}maxAmountRequired is in USDC atomic units (6 decimals). "15000" = 0.015000 USDC.
PAYMENT-SIGNATURE payload
{
"x402Version": "2",
"scheme": "exact",
"network": "eip155:8453",
"payload": {
"signature": "<EIP-3009 TransferWithAuthorization signature>",
"authorization": {
"from": "<payer wallet address>",
"to": "<payee address>",
"value": "15000",
"validAfter": "0",
"validBefore": "<expiration timestamp>",
"nonce": "<random nonce>"
}
},
"domain": {}
}Model 2: Rolling settlement (AI)
AI calls use a pay-after-use model. The actual token cost is known only after the upstream model responds.
How it works:
- First call: Agent sends
POST /ai/{model}→ Gateway forwards to upstream (no payment needed) → Response returned, token usage recorded aspending - Subsequent calls: Agent sends
POST /ai/{model}→ Gateway checks previous record → Returns 402 requesting payment for previous call's token cost - SDK signs USDC payment for the exact token cost → Agent retries with
PAYMENT-SIGNATURE→ Gateway verifies, settles, then forwards the new request - New token usage is recorded as
pending→ cycle repeats
Billing formula
Cost (USDC) = input_tokens × input_price_per_token + output_tokens × output_price_per_token
Rounded to 6 decimal places.
Example: deepseek-v4-flash (input: 0.14 USDC/1M tokens, output: 0.28 USDC/1M tokens) with 500 input + 200 output tokens:
500 × 0.000000140 + 200 × 0.000000280 = 0.000070 + 0.000056 = 0.000126 USDC
Settlement states
| Status | Meaning | Next action |
|---|---|---|
| pending | Token cost recorded, not yet paid | Next call triggers 402 → payment |
| settled | Payment confirmed on-chain (terminal) | Next call proceeds freely |
| failed | Settlement attempt failed | Next call triggers 402 again for re-payment |
Transition: pending → settled (success) or pending → failed (failure) → settled (re-payment success)
Facilitator
The Facilitator is a service that processes x402 payments on behalf of the payee (gateway). It abstracts blockchain complexity so the gateway doesn't need to run its own nodes or develop custom payment validation.
Facilitator responsibilities
| Role | Description |
|---|---|
| Payment Verification | Confirms the payer's signed authorization is valid (correct signature, sufficient balance, valid nonce) |
| Payment Settlement | Broadcasts the transferWithAuthorization transaction on-chain |
| Result Reporting | Returns the transaction hash and settlement status to the gateway |
Facilitator API
The ZAN x402 Facilitator exposes three endpoints:
GET /supported
GET /supportedReturns the Facilitator's capabilities:
- Supported x402 protocol version(s)
- Accepted payment scheme (e.g.,
exact/transferWithAuthorization) - Supported blockchain networks and assets
POST /verify
POST /verifyValidates a payment without executing it on-chain.
- Receives the x402 payment payload
- Checks signature validity, nonce, value, and payer balance
- Returns
{ isValid: true/false }
The gateway calls /verify before processing the agent's request to ensure payment is valid.
POST /settle
POST /settleExecutes the payment on-chain after the request has been processed.
- Receives the same x402 payment payload
- Signs and broadcasts the
transferWithAuthorizationtransaction - Returns the on-chain transaction hash as proof of settlement
The gateway calls /settle after successfully handling the agent's request, ensuring tokens are only transferred when the service is delivered.
Verify-then-settle pattern
Gateway receives PAYMENT-SIGNATURE
│
▼
POST /verify → is payment valid?
│
├── invalid → reject request (402)
│
└── valid → process request
│
▼
POST /settle → broadcast on-chain
│
├── success → return response + txHash to agent
└── failure → retry settlement (async)
This two-phase approach ensures:
- Invalid payments are rejected immediately (no wasted compute)
- Funds are only transferred after service delivery
- Settlement failures don't block the agent (gateway retries asynchronously)
Supported payment networks
| Type | Network | USDC Contract |
|---|---|---|
| EVM | Base Mainnet (eip155:8453) | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 |
| EVM | Base Sepolia (eip155:84532) | 0x036CbD53842c5426634e7929541eC2318f3dCF7e |
| EVM | eip155:688689 | 0xcfC8330f4BCAB529c625D12781b1C19466A9Fc8B |
| EVM | eip155:1672 | 0xC879C018dB60520F4355C26eD1a6D572cdAC1815 |
| Solana | Mainnet (solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp) | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
| Solana | Devnet (solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1) | 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU |
The payment network is decoupled from the service network — you pay on Base but query Ethereum, Solana, or any other chain.
Payment signatures
EVM (EIP-3009 TransferWithAuthorization)
The SDK uses viem to sign an EIP-3009 transferWithAuthorization message. This function allows the payer to sign a transfer off-chain — the payload includes from, to, value, an expiration time, and a random nonce. The Facilitator then submits this to the blockchain, bearing all gas fees.
Key properties:
- No prior token approval needed (unlike ERC-20
approve+transferFrom) - Single-use authorization (nonce-based, cannot be replayed)
- Amount exactly matches the quote (cannot be altered)
- Payer pays zero gas (Facilitator submits the transaction)
Solana (SPL Token TransferChecked)
The SDK builds a Solana VersionedTransaction containing:
- SPL Token
TransferCheckedinstruction (exact USDC amount) - Associated Token Account creation (if needed)
- Fee payer set to the Facilitator's address (gas sponsored)
Security model
| Property | Mechanism |
|---|---|
| Payment verification | Facilitator verifies signature validity before gateway processes the request |
| On-chain settlement | Actual token transfer is broadcast on-chain — fully auditable |
| Idempotency | Each payment has a unique nonce — no double charges |
| Cost cap | Gateway enforces max-credits-per-request: 1000 |
| Automatic refund | If upstream returns 5xx after credit deduction, credits are refunded |
| Untrusted quotes | SDK only signs the exact amount in the gateway's quote |
| Single authorization | Each signature authorizes exactly one payment |
| Gas sponsorship | Agent never pays gas — Facilitator covers all on-chain fees |
SDK auto-payment behavior
With autoPayment: true, the SDK transparently handles:
- 402 detection — Recognizes payment-required responses
- Quote parsing — Decodes
PAYMENT-REQUIREDheader - Signature construction — Signs EIP-3009 (EVM) or SPL transfer (Solana)
- Retry — Resubmits the original request with
PAYMENT-SIGNATURE - JWT refresh — Re-authenticates if session expired during payment
The entire flow appears as a single await to your code.
// All of this happens inside one await:
const block = await client.call('eth', 'mainnet', 'eth_blockNumber');
// ↑ May internally: purchase credits → sign → settle → retryTroubleshooting
| Symptom | Cause | Solution |
|---|---|---|
InsufficientFundsError | Wallet doesn't have enough USDC | Fund your wallet with USDC on the payment network |
PaymentRejectedError | Facilitator rejected the signature | Check wallet has USDC, signature format is correct |
| Repeated 402 on AI calls | Previous settlement keeps failing | Check wallet balance; the pending amount may exceed available USDC |
| Payment succeeds but credits not updated | Settle transaction pending on-chain | Wait for block confirmation; gateway retries settlement |
Roadmap
ZAN is building the next generation of agentic payment infrastructure:
- Agent identity verification — A financial-grade identity framework powered by TEE and ZK, enabling secure and auditable identity anchoring for autonomous agents.
- Cross-protocol compatibility — Native compatibility with A2A, AP2, and x402, providing enhanced communication protection and cross-chain trust assurance.
- Developer-friendly integration — Lightweight options including ADK, APIs, and RESTful interfaces for scalable, low-latency, compliant agentic payments.
Next steps
- Quick Start — See payment in action
- SDK Reference —
purchaseCredits()and error types - AI Models — Rolling settlement in practice
Updated about 10 hours ago
