# How an x402 payment works, step by step, from a real 402 response

## How an x402 payment works, step by step, from a real 402 response

An x402 payment is an ordinary HTTP exchange with one extra round trip. The client asks for a resource, the server answers `402 Payment Required` with a base64 `PAYMENT-REQUIRED` header describing the price, the client signs a USDC transfer authorization and repeats the request with a `PAYMENT-SIGNATURE` header, and the server settles the payment through a facilitator and returns the resource with a `PAYMENT-RESPONSE` receipt. This article decodes a real challenge from the Red Cup seller at market.561.group, captured on 2026-10-22 at 00:30 UTC, so every field below is observed rather than invented.

### What is the first request, and what does the seller answer?

The client sends a normal request. We use one of the cheapest offers, an RFC 6901 JSON Pointer lookup that costs $0.0012:

```bash
curl -s -i -X POST https://market.561.group/v1/data/json-pointer \
  -H 'content-type: application/json' \
  -d '{"value":{"a/b":[1,null]},"pointer":"/a~1b/1"}'
```

The response starts like this (other headers omitted):

```http
HTTP/2 402
content-type: application/json
cache-control: no-store
payment-required: eyJ4NDAyVmVyc2lvbiI6MiwiZXJyb3IiOiJQYXltZW50IHJlcXVpcmVkIiwi...
```

Three details matter. The status is `402`. The body is the placeholder `{}`; the real challenge is in the header, so a client that only reads bodies learns nothing. And `cache-control: no-store` keeps intermediaries from caching a quote.

### What is inside the PAYMENT-REQUIRED header?

Decode the header to see the challenge:

```bash
curl -s -i -X POST https://market.561.group/v1/data/json-pointer \
  -H 'content-type: application/json' \
  -d '{"value":{"a/b":[1,null]},"pointer":"/a~1b/1"}' \
  | grep -i '^payment-required' | cut -d' ' -f2 | tr -d '\r' | base64 -d | jq .
```

The decoded JSON, abbreviated to the load-bearing fields:

```json
{
  "x402Version": 2,
  "error": "Payment required",
  "resource": {
    "url": "https://market.561.group/v1/data/json-pointer",
    "mimeType": "application/json",
    "serviceName": "json-pointer",
    "tags": ["json", "rfc6901", "json-pointer"]
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "amount": "1200",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "payTo": "0x…(the seller's receiving address)",
      "maxTimeoutSeconds": 300,
      "extra": { "name": "USD Coin", "version": "2" }
    }
  ],
  "extensions": { "bazaar": { "...": "..." }, "sign-in-with-x": { "...": "..." } }
}
```

Reading it field by field:

| Field | Meaning |
| --- | --- |
| `x402Version: 2` | Protocol version. v2 uses the `PAYMENT-REQUIRED`, `PAYMENT-SIGNATURE` and `PAYMENT-RESPONSE` headers. |
| `scheme: "exact"` | The buyer authorizes exactly this amount; no more, no less. |
| `network: "eip155:8453"` | A CAIP-2 chain identifier. 8453 is Base mainnet. |
| `amount: "1200"` | Atomic units of the asset. USDC has 6 decimals, so 1200 is $0.0012. |
| `asset` | The USDC contract on Base (Circle's token), not a symbol. |
| `payTo` | Where the money goes. A buyer must not simply trust this field; see [Never trust the payee](https://engineering.561.group/verify-x402-payee-buyer-side/). |
| `maxTimeoutSeconds: 300` | How long a signed authorization may remain valid. |
| `extra.name`, `extra.version` | The EIP-712 domain parameters of the token, needed to sign correctly. |

The `extensions` object carries optional features. `bazaar` describes the input and output of the endpoint with a JSON Schema so a discovery index or an agent can see how to call it, and `sign-in-with-x` offers a wallet-login challenge, covered in [Sign-in-with-X](https://engineering.561.group/x402-sign-in-with-x/). The amounts are exact integers; the seller never converts between dollars and atomic units on the buyer's behalf, because rounding in a payment path is a defect.

### How does the client sign a payment?

USDC on Base implements EIP-3009 `transferWithAuthorization`. The buyer does not send a transaction. It signs an EIP-712 typed message that authorizes a transfer of exactly `amount` from the buyer to `payTo`, with a random 32-byte nonce and a validity window. The signature goes into a JSON payload that echoes the `accepted` requirement, base64-encoded as the `PAYMENT-SIGNATURE` header. Because the buyer signs rather than submits, the buyer needs no ETH for gas; a facilitator submits the transfer.

In code, the official client library does this for you. In outline:

```js
// Outline using the official x402 packages (see their docs for exact imports)
const client = /* x402 client registered with an exact-EVM scheme and your signer */;
const paymentPayload = await client.createPaymentPayload(paymentRequired);
const header = encodePaymentSignatureHeader(paymentPayload);
// repeat the original request with:  PAYMENT-SIGNATURE: <header>
```

A careful buyer inserts three checks between "read the challenge" and "sign": that the `payTo` equals an address the buyer's owner approved in advance, that `amount` is below a budget, and that the resource URL is the one requested. The Red Cup buyer library enforces all three and also detects *quote drift* (a second challenge that differs from the first accepted one) before signing.

### What does the seller do with the signature?

The seller's middleware decodes the header and asks a facilitator to verify it: is the signature valid for this payer, is the nonce unused, does the balance cover the amount, does the requirement match what the seller issued? Our seller uses the Coinbase CDP facilitator. If verification succeeds, the seller runs its handler. Only if the handler returns a success status does it ask the facilitator to settle, which submits the EIP-3009 transfer on Base. A handler that fails or throws causes the authorization to be cancelled instead (see [Refuse before you charge](https://engineering.561.group/refuse-before-you-charge-x402/)).

The successful response carries the resource and a `PAYMENT-RESPONSE` header containing the settlement result, including the network transaction hash. That receipt is what the buyer records. The Red Cup buyer calls `beforePayment` with the exact signed request before it is sent, and `onSettlement` with the facilitator's report before the delivery is read, so the buyer's own books show the intent even if the connection dies.

### What if the connection drops after the buyer pays?

The signature is single-use: the facilitator will reject a second submission of the same nonce. For ordinary API calls the buyer simply pays again for a new computation, which costs a fraction of a cent. For expensive digital goods the seller offers the [X-Payment-Recovery](https://engineering.561.group/x402-payment-recovery-header/) mechanism so the same signed request returns the same purchased bytes.

### How do I try this without spending anything?

Everything up to the signature is free. The unsigned probe above costs nothing and moves no funds. If you want to inspect any x402 v2 resource safely, the Apache-2.0 [x402 boundary reference](https://github.com/561-group/x402-boundary-reference) includes `observePublicX402Resource`, which fetches a public resource, refuses redirects and non-HTTPS targets, validates the challenge against the official schema, and returns a content-addressed digest of what it saw, all without paying or signing. To list what the market sells, read [`/.well-known/x402`](https://market.561.group/.well-known/x402) (130 resources at the time of writing) or the richer [`/v1/catalog`](https://market.561.group/v1/catalog).

### What should I remember?

An x402 challenge is a quote written by the seller, not an authorization from the buyer. The seller's address, the amount and the asset are all claims; the buyer's software decides which claims to honor. The rest of this series is about making both sides of that exchange careful: start with [what a seller should do beyond the spec](https://engineering.561.group/x402-seller-design/).
