x402 explained: how an AI agent pays for an API in one request

A walk through the x402 exchange, from the 402 Payment Required response to the signed retry and the receipt, with real headers and a minimal client.

MinAgent Team8 min read

HTTP has had a status code for payments since 1997. 402 Payment Required was listed in the HTTP/1.1 spec as “reserved for future use”, and for almost thirty years nobody agreed on what that future looked like. x402 is the answer that finally stuck: an open standard that says exactly what a server sends with a 402, what the client sends back, and how the money moves.

For AI agents this matters more than it does for people. An agent can't fill in a checkout form or wait for an invoice. It needs a price it can read, a way to pay it, and a result, all inside the request it was already making. That is what x402 gives it.

The exchange, step by step

Here is the whole flow for an agent buying one article from a news API. Nothing happens before the first request: no sign-up, no API key.

1. The agent asks

Request
GET /v1/headlines HTTP/1.1
Host: news-feed.example

2. The server names its price

Instead of the content, the server answers 402 and puts its payment terms in a PAYMENT-REQUIRED header, as base64-encoded JSON:

Response
HTTP/1.1 402 Payment Required
PAYMENT-REQUIRED: eyJ4NDAyVmVyc2lvbiI6Miwi...

Decoded, the terms look like this (trimmed to the important fields):

PAYMENT-REQUIRED, decoded
{
  "x402Version": 2,
  "resource": { "url": "https://news-feed.example/v1/headlines" },
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "amount": "2000",
      "payTo": "0xSellerAddress",
      "maxTimeoutSeconds": 60
    }
  ]
}

Read it the way the agent does. The server accepts an exact payment on Base (chain ID 8453) in USDC. The amount is in the token's smallest unit: USDC has six decimals, so 2000 is 0.002 USDC. accepts is a list, so a server can offer several networks or tokens and let the client pick.

3. The agent signs and retries

The client builds a payment that matches one of those options, signs it with its wallet, and sends the same request again with the signed payload in a PAYMENT-SIGNATURE header. For USDC on EVM chains the exact scheme uses a signed transfer authorization, so the agent doesn't need to send a transaction itself or hold gas tokens.

Retry
GET /v1/headlines HTTP/1.1
Host: news-feed.example
PAYMENT-SIGNATURE: eyJ4NDAyVmVyc2lvbiI6Miwi...

4. The server verifies, settles, and delivers

The server checks the signature and settles the payment, usually through a facilitator: a service that verifies x402 payloads and submits them on-chain so the seller doesn't have to run that infrastructure. Then it returns the content with a PAYMENT-RESPONSE header that carries the settlement result, including the transaction reference. That header is the agent's receipt.

Response
HTTP/1.1 200 OK
Content-Type: application/json
PAYMENT-RESPONSE: eyJzdWNjZXNzIjp0cnVlLCJ0cmFu...

{ "headlines": [ ... ] }

A minimal client

The x402 project ships client and server libraries, and in production you should use them. But the core loop is small enough to read in one go, which helps when you're deciding where your own checks belong:

fetch-with-payment.ts
type PaymentOption = {
  scheme: string;
  network: string;
  asset: string;
  amount: string; // smallest token unit
  payTo: string;
};

interface AgentWallet {
  // Throws if the payment breaks the owner's rules.
  checkPolicy(option: PaymentOption, resource: string): Promise<void>;
  // Returns the base64 PAYMENT-SIGNATURE payload.
  sign(option: PaymentOption, resource: string): Promise<string>;
}

const decode = (header: string) => JSON.parse(atob(header));

export async function fetchWithPayment(url: string, wallet: AgentWallet, init: RequestInit = {}) {
  const first = await fetch(url, init);
  if (first.status !== 402) return first;

  const header = first.headers.get("PAYMENT-REQUIRED");
  if (!header) throw new Error("402 without payment terms");

  const terms = decode(header);
  const option: PaymentOption = terms.accepts[0];

  await wallet.checkPolicy(option, url); // the important line
  const signature = await wallet.sign(option, url);

  return fetch(url, {
    ...init,
    headers: { ...init.headers, "PAYMENT-SIGNATURE": signature },
  });
}

Notice where checkPolicy sits: after the price is known and before anything is signed. That one line is where an agent wallet earns its keep. We wrote a whole post on what that check should do.

Why this fits agents so well

  • No accounts. The agent can use a service the first time it finds it. There is no key to provision or rotate.
  • Prices a machine can read. The amount, token, and network are structured data, so the agent can compare offers and enforce limits without guessing.
  • Tiny payments that make sense. Stablecoin settlement on a low-fee network means charging 0.002 USDC for one request is practical, which card rails never allowed.
  • Receipts by default. Every paid response carries proof of payment, which makes auditing an agent's spending straightforward.

How MinAgent uses it

In MinAgent, the agent's wallet is the x402 client. When a request comes back with a 402, the wallet reads the terms, runs them through the owner's rules, signs if they pass, and stores the receipt alongside the task that triggered it. On the selling side, every API Store listing and marketplace agent sits behind the same exchange, so a person, a script, or another agent all pay the same way.

If you want to see the exchange animated, the How a payment happens section on our home page plays it step by step.

Give your agent a wallet.

The private beta is open by invitation.

Join the waitlist

Keep reading

Integrations

Giving Claude Code a wallet with MCP

What an MCP wallet server should expose, why it has no “send money” tool, and how scoped session keys keep the main wallet key out of every client.

6 min read