Core Concepts
The X402 protocol — HTTP 402 flow, PaymentRequirements, the X-PAYMENT header, schemes, and facilitators.
X402 Core Concepts
X402 is an open standard for paying for HTTP resources with on-chain settlement. It uses the long-unused HTTP 402 Payment Required status code as the signal for "this resource costs money — here's how to pay."
This page covers the protocol itself: the wire format, the objects, the schemes. If you just want to call a paid endpoint, skip to X402 Fetch.
The HTTP 402 Flow
┌─────────┐ ┌─────────┐
│ Client │ 1. GET /resource │ Server │
│ │ ──────────────────────────────>│ │
│ │ │ │
│ │ 2. 402 + PaymentRequirements │ │
│ │ <──────────────────────────────│ │
│ │ │ │
│ │ 3. Sign authorization │ │
│ │ (EIP-712 / partial tx) │ │
│ │ │ │
│ │ 4. GET /resource │ │
│ │ X-PAYMENT: <base64> │ │
│ │ ──────────────────────────────>│ │
│ │ │ 5. Verify
│ │ │ (+ settle
│ │ │ via facilitator)
│ │ 6. 200 OK + resource │ │
│ │ X-PAYMENT-RESPONSE: <b64> │ │
│ │ <──────────────────────────────│ │
└─────────┘ └─────────┘Two request/response cycles, one signature. No accounts created, no keys exchanged.
The PaymentRequirements Object
When an X402 server returns 402, the body is a JSON document describing what it accepts:
{
"x402Version": 1,
"error": "Payment required",
"accepts": [
{
"scheme": "exact",
"network": "base",
"maxAmountRequired": "250000",
"resource": "https://api.example.com/v1/generate",
"description": "AI image generation",
"mimeType": "application/json",
"payTo": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb7",
"maxTimeoutSeconds": 300,
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"extra": {
"name": "USD Coin",
"version": "2"
}
}
]
}Top-level fields
| Field | Type | Description |
|---|---|---|
x402Version | number | Protocol version |
error | string | Human-readable reason for the 402 |
accepts | array | One or more PaymentRequirement entries — client picks one |
accepts[] entry
| Field | Type | Description |
|---|---|---|
scheme | string | Authorization scheme: "exact" or "upto" |
network | string | Chain identifier, e.g. "base", "base-sepolia", "solana" |
maxAmountRequired | string | Max cost in atomic units (USDC has 6 decimals — 250000 = $0.25) |
resource | string | Canonical URL of the gated resource |
payTo | string | Recipient wallet address |
asset | string | Token contract address (USDC on the given network) |
maxTimeoutSeconds | number | How long the signed authorization remains valid |
extra | object | Scheme-specific metadata (e.g. EIP-712 domain name/version) |
description | string | Optional human-readable description |
mimeType | string | Optional content type of the resource |
Multiple entries in accepts let the server offer a choice — "pay $0.25 on Base, or $0.26 on Solana." The client picks one and signs for it.
The X-PAYMENT Header
The client's signed authorization is a base64-encoded JSON object sent in the X-PAYMENT header:
X-PAYMENT: eyJ4NDAyVmVyc2lvbiI6MSwic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoiYmFzZSIsInBheWxvYWQiOnsuLi59fQ==Decoded:
{
"x402Version": 1,
"scheme": "exact",
"network": "base",
"payload": {
"signature": "0x...",
"authorization": {
"from": "0xPayer...",
"to": "0xRecipient...",
"value": "250000",
"validAfter": "1734567890",
"validBefore": "1734568190",
"nonce": "0x<32 random bytes>"
}
}
}| Field | Description |
|---|---|
x402Version | Must match the server's version |
scheme | The scheme selected from accepts[].scheme |
network | The network selected from accepts[].network |
payload | Scheme-specific proof — see below |
On success, the server replies with X-PAYMENT-RESPONSE (also base64 JSON) containing the settlement transaction hash and payer address.
Authorization Schemes
exact — EVM (EIP-3009)
Uses EIP-3009 transferWithAuthorization, a gasless token-transfer primitive built into USDC. The client signs an EIP-712 typed-data structure; the server (or its facilitator) submits the signature on-chain and the token contract executes the transfer.
Authorization fields:
| Field | Description |
|---|---|
from | Payer address |
to | Recipient address (matches payTo) |
value | Amount in atomic units (matches maxAmountRequired) |
validAfter | Unix timestamp — earliest valid time |
validBefore | Unix timestamp — expiry |
nonce | 32 random bytes — prevents replay at the contract level |
The nonce is enforced by the token contract itself: replay is impossible even without server-side tracking.
upto — EVM (EIP-2612)
Uses EIP-2612 permit to pre-authorize a spending cap. The server charges the actual cost (≤ cap) at settlement. Useful when cost isn't known up-front — streaming responses, variable-token LLM calls.
Agnic auto-selects exact or upto based on the server's accepts array.
exact — Solana
On Solana, the payload is a partially-signed transaction (base64-encoded) with instructions in this exact order:
SetComputeUnitLimit(≤ 40,000)SetComputeUnitPrice(≤ 5 microlamports/unit)TransferChecked(the actual USDC transfer)- Optional Lighthouse assertions
The server/facilitator co-signs and submits.
Facilitators
X402 servers don't want to hold private keys or run chain infrastructure. That's what a facilitator is for — a third-party service that verifies and settles payments on the server's behalf. A facilitator exposes three endpoints:
| Endpoint | Purpose |
|---|---|
POST /verify | Check that an X-PAYMENT is valid, without moving any money |
POST /settle | Actually submit the transfer on-chain |
GET /supported | List the { scheme, network } pairs the facilitator handles |
A server's typical flow: verify first (fast, off-chain), serve the resource, then settle asynchronously.
Public facilitators exist for Base, Base Sepolia, Solana, Avalanche and others. Agnic runs its own verified settlement path for the networks it supports.
Networks
X402 is chain-agnostic. Current production deployments use:
| Network | Chain ID / CAIP-2 | USDC contract |
|---|---|---|
| Base | eip155:8453 | 0x8335...02913 |
| Base Sepolia | eip155:84532 | 0x036C...CF7e |
| Solana Mainnet | solana:mainnet | EPjF...Dt1v |
| Solana Devnet | solana:devnet | Gh9Z...fmjy |
| Avalanche | eip155:43114 | (native USDC) |
accepts[].network uses short names ("base", "solana") in the wire format; CAIP-2 is used by facilitators' /supported.
Replay & Expiry Protection
Every authorization carries three safety properties:
- Nonce — 32 random bytes, enforced by the token contract on EVM. One-shot.
- Time window —
validAfter/validBeforebound when the authorization is usable. - Amount cap —
value(exact) or permit allowance (upto) bounds how much can move.
A signature leaked after the time window is useless; a replay of a consumed nonce reverts at the contract.
Error Codes
Standard error strings returned by facilitators and servers:
insufficient_fundsinvalid_schemeunsupported_schemeinvalid_networkinvalid_x402_versioninvalid_exact_evm_payload_signatureinvalid_exact_svm_payload_transaction_instructions_lengthinvalid_transaction_state
How Agnic Implements This
You never touch the wire format unless you want to. Agnic's client library (and /api/x402/fetch) does all of the above — parse 402, pick a scheme, sign EIP-712 or build a Solana tx, attach X-PAYMENT, retry, surface the result.
If you need the raw header for a custom middleware, /api/sign-payment returns it directly.
Further Reading
- X402 Fetch — the one-call proxy
- Sign Authorization — raw header signing
- External: payai x402 reference, EIP-3009, EIP-2612