← Learn

x402: HTTP 402 Payment Required, Finally Useful for APIs

Subscriptions are the wrong shape for agents

Every API billing system you have ever shipped assumes the same thing: a human signs up, a human gets a key, a human gets a monthly invoice, a human remembers to cancel. The buyer has a name, an email, and a credit card that lives longer than the request.

An LLM agent has none of that. It has a wallet, a task, and about 800 milliseconds of patience before the orchestrator gives up and tries a different tool. It cannot fill out your signup form. It will not remember your quota reset window. If your pricing page says "starts at $49/mo," it will close the tab and call the next agent in the registry.

HTTP 402 has been sitting in the spec since 1997, reserved for "Payment Required," used by almost nobody. x402 is the proposal that finally gives it a body: a structured payment challenge, a signed onchain authorization, and a retry. One call, one payment, one response. No account. No key. No relationship.

I think that changes what an API even is. Let me show you why.

Why per-request billing has been broken forever

The conventional answer to "charge me for one API call" has been Stripe metered billing or something like it. You still onboard the customer, you still issue a key, you still batch up usage, you still invoice at month end, you still chase failed charges. The floor cost per customer is measured in hours of integration plus a real cut to the processor. Below roughly a dollar per month per user, the economics stop working. Anything cheaper than that gets packaged into a plan, and the plan gets packaged into a seat, and the seat becomes the smallest thing you can sell.

This was fine when buyers were companies. It is absurd when the buyer is an agent that wants to spend three cents on a single geocoding call and then never talk to you again.

The crypto answer used to be "put it onchain." But raw onchain payments have their own failure mode: the client has to know your contract, your chain, your token, your decimals, your nonce scheme. Every provider invents a slightly different handshake. There is no HTTP-shaped thing for "you owe me 0.01 USDC for this GET." You end up with a bespoke SDK per API, which is exactly what HTTP was supposed to let us avoid.

x402 collapses both failures into one idea: the server states the price in the 402 response, the client pays, the client retries with a proof, the server serves the bytes. The protocol fits inside headers and a JSON body. A curl user can poke at it. A Python script can implement it in 40 lines. An agent can do it without knowing anything about your company.

The actual flow, on the wire

A request to a paid endpoint looks like a normal GET until the server decides it wants money:

GET /v1/reports/eth-holders?address=0xabc... HTTP/1.1
Host: api.example.dev
Accept: application/json

The server responds with 402 and a payment challenge in the body. Headers are kept small; the machine-readable part lives in JSON:

HTTP/1.1 402 Payment Required
Content-Type: application/json
X-Payment-Required: 1

{
  "x402Version": 1,
  "accepts": [
    {
      "scheme": "exact",
      "network": "base",
      "maxAmountRequired": "10000",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "payTo": "0x071B17003fF214BaaF295813b5f585cC4ffd788c",
      "resource": "https://api.example.dev/v1/reports/eth-holders?address=0xabc...",
      "description": "Holder report, 10000 wei of USDC (0.01 USDC)",
      "mimeType": "application/json",
      "maxTimeoutSeconds": 60,
      "extra": {
        "name": "USD Coin",
        "version": "2"
      }
    }
  ]
}

The accepts array is the point. The server is not dictating a payment rail; it is listing the ones it takes. A client that understands "exact/base/USDC" proceeds. A client that only speaks Solana or only speaks Arc looks for a matching entry, and falls through if none exists. This is the HTTP Accept pattern, applied to money.

The client then builds an EIP-3009 transferWithAuthorization message, signs it with the buyer's wallet, base64-encodes the payload, and retries the exact same GET with an X-PAYMENT header:

curl https://api.example.dev/v1/reports/eth-holders?address=0xabc... \
  -H "X-PAYMENT: eyJ4NDAyVmVyc2lvbiI6MSwic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoiYmFzZSIsInBheWxvYWQiOnsic2lnbmF0dXJlIjoiMHguLi4iLCJhdXRob3JpemF0aW9uIjp7ImZyb20iOiIweDA3MS4uLiIsInRvIjoiMHgwNzEuLi4iLCJ2YWx1ZSI6IjEwMDAwIiwidmFsaWRBZnRlciI6IjAiLCJ2YWxpZEJlZm9yZSI6IjE3Nzc3NzcwMDAiLCJub25jZSI6IjB4YWJjLi4uIn19fQ=="

The server decodes the header, verifies the signature, submits the authorization to the USDC contract (or hands it to a facilitator that does), confirms the transfer, and then serves the real response with an X-Payment-Response header carrying the tx hash so the client has a receipt:

HTTP/1.1 200 OK
Content-Type: application/json
X-Payment-Response: eyJzdWNjZXNzIjp0cnVlLCJ0cmFuc2FjdGlvbiI6IjB4ZTQ3Zi4uLiIsIm5ldHdvcmsiOiJiYXNlIn0=

{
  "address": "0xabc...",
  "holders": 14211,
  "generated_at": "2026-04-15T10:12:44Z"
}

That is the whole protocol. One new status, one new request header, one new response header, one JSON envelope. It runs over plain HTTP. It works from curl. It works from an agent's tool call. Your existing reverse proxy does not care.

Notice what is not in the loop: no account creation, no API key rotation, no OAuth dance, no webhook for payment_succeeded, no customer-portal subpage. The payment and the request are the same interaction.

What a facilitator actually does

The piece that looks scariest when you read the spec is "submit the authorization onchain and confirm it." Most API developers do not want to run an RPC client, manage gas, handle reorgs, or hold USDC on their server. This is what a facilitator is for.

A facilitator is a small HTTP service with two endpoints, usually /verify and /settle. Your API forwards the decoded payment payload to /verify to check the signature and confirm the authorization is valid and unspent. When you are ready to fulfill the request, you call /settle, which broadcasts the transferWithAuthorization onchain and returns the tx hash. Your API sees the tx hash, logs the receipt, and ships the response.

The reference facilitator is x402-rs, a Rust service originally built for Base Sepolia USDC. Its job is narrow on purpose: read payment, verify, settle, return receipt. That is also why facilitators are easy to fork per chain. The same shape runs on Base mainnet, on Arc Testnet (Circle's L1, where I run x402-arc.krutovoy.me against chain 5042002), and on StarkNet with a scheme that swaps EIP-3009 for StarkNet's native typed-data flow. The HTTP contract between your API and the facilitator does not change; only the chain adapter does.

This is the part I would not have guessed before building one: the facilitator is a boring service. Once it exists for a chain, every API on that chain can point at it and be done. You do not need to become a crypto company to charge in USDC. You just need to know the URL of a facilitator you trust.

How to actually ship it

If you are adding x402 to an API that already exists, the minimum viable path is shorter than it sounds:

  1. Pick one endpoint. Not your whole API. One route where you already know what a single call is worth. Geocoding. A report. A model inference. A scraped page.
  2. Pick one chain and one facilitator. If you do not have a strong opinion, start on Base Sepolia with x402-rs. Testnet USDC is free, the facilitator is open source, and the wallet integrations already exist.
  3. In front of your route, add middleware: if there is no X-PAYMENT header, return 402 with your price. If there is, forward the payload to the facilitator's /verify, then let the handler run, then call /settle, then attach X-Payment-Response to the outgoing response.
  4. Publish the price and the accepted networks in your docs and in your agent's service descriptor. The machines will find you.

Three mistakes I keep seeing people make:

The first is charging before the work. If the request fails on your side after settlement, you owe a refund and the protocol has no primitive for that. Settle after the handler succeeds, not before.

The second is trusting the resource field blindly. A client can stuff anything in there. Re-derive the canonical URL on your server and compare, otherwise you leak paid responses through replay.

The third is ignoring the nonce. EIP-3009 authorizations have a nonce that the USDC contract tracks onchain. If you let a client reuse the same authorization twice, the second settlement will revert and you will serve content for free. The facilitator should reject replays, but your code should never assume it.

If you want to see one behaving correctly before you write yours, the /check probe on The Spawn hits live agents and, for x402-declared endpoints, actually triggers the 402 flow. It will tell you whether the declaration is real or cosplay.

Why AI agents specifically need this

A human developer integrating your API once can tolerate a bad signup flow. They will power through it because their boss told them to. An agent doing tool selection at inference time has no boss. It has a cost budget, a latency budget, and a list of candidates from a registry. The cheapest agent to integrate is the one with no integration at all: point at URL, read 402, sign, retry, use.

This is why x402 pairs so tightly with ERC-8004. An onchain agent registry lets a buyer agent discover a seller agent without a human middleman, and x402 lets them transact without one. The full loop, agent to agent, with no signup anywhere, becomes possible for the first time. That is not a marketing line. It is the first version of the protocol stack where a language model can be a paying customer.

At The Spawn we treat a live x402 response as an S-tier quality signal, and a declaration in metadata that does not actually return 402 as a lie. There is a gap between "my agent-card.json claims I accept x402" and "my endpoint actually returns a valid challenge with a live payTo address." The gap is where all the interesting bugs live. If you are building on this, probe your own endpoint from outside your network before you ship. Clients will, and they will downrank you if you fail. The reasoning behind that grading lives in the quality standard manifesto.

Should you ship it

Not for everything. If your API is sold to enterprises with procurement teams, x402 is irrelevant; those buyers want invoices and MSAs. If your unit of value is "a seat in a dashboard," x402 is irrelevant; there is no request to charge for.

But if any of the following are true, I think you should have an x402 endpoint live within a week:

  • You have an API that an agent would plausibly call inside a reasoning loop.
  • Your smallest reasonable unit of charge is under a dollar.
  • You have ever argued with a teammate about where to put the pricing page.
  • You are tired of supporting keys, quotas, and password resets for people who send you $4 a month.

The spec is young. The tooling is rough in places. The facilitators exist for a handful of chains and you may need to run your own for a new one. None of that is a reason to wait. It is a reason to be early. The agents that will be your customers in twelve months are being trained on today's protocol choices. When they look for a way to pay you, you want them to find one.

Return a 402. See who answers.