·9 min read·Technical

Anatomy of an x402 payment: every header, every signature, every settlement

Short answer: An x402 payment is four HTTP messages and one signed EIP-3009 authorization. The server quotes, the client signs locally, replays with X-PAYMENT, the facilitator settles on Base, the server returns data. End to end: ~600 ms.

The previous post — Why x402, not API keys — argued that autonomous agents need a different auth model. This post zooms into the wire. We trace exactly one paid call to Luxe Oracle and show what each side does at each step.

The four messages at a glance

  Agent                      Server                  Facilitator    Base
    │                          │                          │           │
    │   ① GET /api/v1/monitor  │                          │           │
    │ ───────────────────────► │                          │           │
    │                          │                          │           │
    │   ② 402 + quote JSON     │                          │           │
    │ ◄─────────────────────── │                          │           │
    │                          │                          │           │
    │  (sign EIP-3009 locally) │                          │           │
    │                          │                          │           │
    │   ③ GET ... + X-PAYMENT  │                          │           │
    │ ───────────────────────► │  verify+settle           │           │
    │                          │ ───────────────────────► │ broadcast │
    │                          │                          │ ────────► │
    │                          │ ◄─────────────────────── │  receipt  │
    │   ④ 200 OK + data        │                          │           │
    │ ◄─────────────────────── │                          │           │

① The unpaid request

The agent makes a vanilla GET. No auth header. No payment. The request is identical to a free endpoint:

GET /api/v1/monitor/sg/hermes/H086962CK0G HTTP/1.1
Host: api.luxe-oracle.com
Accept: application/json
User-Agent: my-agent/1.0

The server's middleware (in our case @x402/next) sees no X-PAYMENT header and short-circuits: it returns a quote instead of the data.

② The 402 quote

HTTP/1.1 402 Payment Required
Content-Type: application/json
Access-Control-Expose-Headers: WWW-Authenticate
WWW-Authenticate: x402

{
  "x402Version": 1,
  "accepts": [{
    "scheme": "exact",
    "network": "base",
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "maxAmountRequired": "1000", // 0.001 USDC, 6 decimals
    "payTo": "0xMerchant…",
    "resource": "https://api.luxe-oracle.com/api/v1/monitor/sg/hermes/H086962CK0G",
    "description": "Real-time Hermès stock query",
    "maxTimeoutSeconds": 300,
    "extra": { "name": "USD Coin", "version": "2" }
  }]
}

The fields the agent cares about:

  • scheme: "exact" — pay the exact amount; no overpayment, no haggling.
  • network + asset — Base mainnet, USDC contract address.
  • maxAmountRequired — already in token base units (USDC has 6 decimals, so 1000 = $0.001).
  • resource — the canonical URL bound into the signature; replay against a different URL fails.

③ Sign locally, replay with X-PAYMENT

The agent constructs an EIP-3009 transferWithAuthorization payload — the standard meta-transaction format USDC supports — and signs it with the agent's private key. Crucially, signing is local: no RPC call, no gas, no on-chain footprint yet.

// Authorization payload (EIP-712 typed data)
{
  from:        "0xAgentWallet…",
  to:          "0xMerchant…",
  value:       "1000",     // 0.001 USDC
  validAfter:  0,
  validBefore: 1714723200,
  nonce:       "0x…32-byte-random…"
}

// Signed → 65-byte signature, base64-encoded into the header

The agent replays the original GET, this time with the header:

GET /api/v1/monitor/sg/hermes/H086962CK0G HTTP/1.1
Host: api.luxe-oracle.com
X-PAYMENT: eyJ4NDAyVmVyc2lvbiI6MSwic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoiYmFzZSIs…

The header value is a base64-encoded JSON wrapper containing the scheme, network, the signed authorization, and the same resource URL. Bind-by-resource is what stops a leaked header from being replayed against a different endpoint.

Verify + settle: the facilitator's job

The server does not need a private key. Instead, it forwards the signed authorization to a facilitator— typically Coinbase's CDP. The facilitator does two checks before broadcasting:

CheckCatches
EIP-712 signature recovers fromTampering with amount, recipient, nonce
from has ≥ value USDCUnderfunded wallet, late settlement risk
nonce not yet used on-chainReplay of a previously settled authorization
resource matches request URLHeader lifted to a different (cheaper) endpoint

Verified, the facilitator broadcasts the transferWithAuthorization on Base. USDC moves from agent to merchant. The facilitator returns the tx hash to the API server, which now has cryptographic proof of payment.

④ The data response

HTTP/1.1 200 OK
Content-Type: application/json
X-Payment-Settlement: 0x9f1c…

{
  "status": "ok",
  "brand": "hermes",
  "region": "sg",
  "model": "H086962CK0G",
  "in_stock": true,
  "last_update": "2026-05-03T12:14:08Z"
}

The settlement tx hash echoes back in a custom header so the agent can prove on-chain it paid. From the agent's code, the entire two-round-trip dance is one call:

const res = await fetchWithPayment(url);

What latency actually looks like

Empirically, on Base mainnet with the CDP facilitator, a Luxe Oracle paid query has settled in 400–800 ms end-to-end. The breakdown:

StepTypical
① Initial GET → 402 quote~50 ms
Local EIP-712 signature< 5 ms
③ Replay GET → server~50 ms
Facilitator verify + broadcast~150 ms
Base inclusion (1 block ~2 s, but tx surfaces faster)~200–500 ms
④ 200 OK + data~50 ms

Sessions cut this drastically: pre-pay once, then every subsequent request takes the bottom row only (~50 ms — no settlement at all). That's why our session endpoint exists for high-volume agents.

Threats the protocol stops

  • Replay across endpoints. Resource binding in the signed payload means the same X-PAYMENT cannot be used against a more expensive route.
  • Replay against same endpoint. EIP-3009 nonces are recorded on-chain. A second settlement of the same authorization fails at the contract level.
  • Server with stolen funds. The server never holds the agent's key. Authorization specifies payTo; nothing else can be drained.
  • Quote tampering. The agent signs the quote it accepted. A man-in-the-middle that flipped the amount would invalidate the signature.

What to read next