---
title: Core Concepts
description: 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](/docs/x402/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:

```json
{
  "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:

```json
{
  "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:

1. `SetComputeUnitLimit` (≤ 40,000)
2. `SetComputeUnitPrice` (≤ 5 microlamports/unit)
3. `TransferChecked` (the actual USDC transfer)
4. 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:

1. **Nonce** — 32 random bytes, enforced by the token contract on EVM. One-shot.
2. **Time window** — `validAfter` / `validBefore` bound when the authorization is usable.
3. **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_funds`
- `invalid_scheme`
- `unsupported_scheme`
- `invalid_network`
- `invalid_x402_version`
- `invalid_exact_evm_payload_signature`
- `invalid_exact_svm_payload_transaction_instructions_length`
- `invalid_transaction_state`

## How Agnic Implements This

You never touch the wire format unless you want to. Agnic's client library (and [`/api/x402/fetch`](/docs/x402/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`](/docs/x402/sign-payment) returns it directly.

## Further Reading

- [X402 Fetch](/docs/x402/x402-fetch) — the one-call proxy
- [Sign Authorization](/docs/x402/sign-payment) — raw header signing
- External: [payai x402 reference](https://docs.payai.network/x402/reference), [EIP-3009](https://eips.ethereum.org/EIPS/eip-3009), [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612)
