x402 v2: the payment status code nobody used
HTTP 402, finally answered
HTTP has carried a 402 Payment Required status code since RFC 2068 defined HTTP/1.1 in January 1997, reserved for future use and unused ever since.
It is not in HTTP/1.0 at all: RFC 1945 goes straight from 401 to 403. x402 is an attempt to finally define what a server should say when it returns one, and version 2 has a v2 specification out for implementation.
The exchange, in four steps
The protocol is deliberately small:
- A client requests a resource.
- With no valid payment attached, the server answers 402, and the response carries what payment it would accept: which networks, which assets, how much, where to send it.
- The client pays and retries with proof attached.
- The server verifies and serves the resource.
The point is that it is one HTTP exchange with headers, not a redirect to a checkout page and back. There is no account to create, no API key to provision, no out-of-band flow.
A caller that can read a 402 and sign a payment can consume a paid endpoint it has never seen before. That is why this arrived alongside the agent tooling instead of before it.
Three roles: the client, the resource server that gates its endpoints with middleware, and a facilitator that handles the on-chain part so the resource server does not have to.
On the server side it stays declarative:
app.use(paymentMiddleware({
"GET /weather": {
accepts: [...],
description: "Weather data",
},
}));What v2 changed
The v2 announcement is explicit that it comes out of production experience rather than design taste, and that shows in what it addresses.
Sessions. In v1 every request was its own payment, which is correct and impractical. v2 adds wallet-based identity and reusable sessions, so a returning client authenticates once and stops paying per call. That is what makes subscription-shaped pricing expressible without leaving the protocol.
Headers instead of the body. The old X- prefixed headers are gone, replaced by PAYMENT-REQUIRED, PAYMENT-SIGNATURE and PAYMENT-RESPONSE. All payment data moved into headers, which frees the response body entirely. A 402 can now carry a human-readable page and machine-readable payment terms in the same response.
A plugin architecture. The specification, the SDK and the facilitators are separate concerns in v2, and chains and assets register through plugins instead of being patched into the core. The paywall moved out into its own package. That is the change that decides whether this ages well: adding a network should not require a spec revision.
Discovery. An extension exposes service metadata for facilitators to crawl, so an agent can find an endpoint, read its price and capabilities, and decide, without a human having read the documentation first.
Dynamic recipients, meaning a payment can split across several parties, which is what marketplace and platform-fee models need.
And notably: no breaking changes. New behaviour arrives as extensions rather than spec edits, and the reference SDKs stay backward compatible with v1.
The payments industry showed up first
The specification would have been a footnote. What happened at the start of April was not.
On April 2nd the Linux Foundation announced the x402 Foundation as a neutral home for the protocol, with Coinbase contributing it.
Read the membership sentence carefully, because it is more careful than the headlines were: “Membership will be comprised of participants from multiple verticals with initial intent and support being expressed by” a list that runs Adyen, Amazon Web Services, American Express, Cloudflare, Coinbase, Google, Mastercard, Microsoft, Shopify, Stripe and Visa.
Intent and support, not membership. Nobody has joined anything yet. But a list containing three card networks, two cloud providers and Stripe is not a list you assemble by accident.
Visa had moved a fortnight earlier, in a direction worth noting.
On March 18th it published a card specification and SDK for the Machine Payments Protocol, the standard Stripe and Tempo announced for machine-to-machine payments. Its framing of x402 is one sentence and it is the interesting one: “While remaining protocol-agnostic, Visa built its card-based MPP specification to complement existing emerging agent payment standards, including protocols like x402.”
Complement, and protocol-agnostic. A card network is not betting on x402, it is making sure that whichever standard agents settle on, a card can sit behind it.
That is what changed in six months. x402 went from a clever use of a forgotten status code to something the institutions whose business is settling payments are positioning around, which moves the question from “will anyone implement this” to “what does my API do when an agent asks for a price”.
What I think of it
The honest summary is that the interesting part is not the payments, it is the shape.
Machine-to-machine access control has always meant provisioning: someone creates an account, generates a key, configures a quota. x402 replaces that with an exchange the caller can complete on its own. Whether the settlement is a stablecoin, a card or an internal ledger is an implementation detail of the facilitator, and v2 explicitly leaves room for the traditional rails.
The caution is equally plain. This is a protocol whose reference implementations are young, whose facilitators are third parties you are trusting, and whose economics on very small amounts depend entirely on settlement costs staying low. “No breaking changes” is a promise made at v2, not a track record.
What makes it worth reading now is that it is the first serious answer to a question HTTP/1.1 left open in 1997. A status code with no semantics is a strange thing to carry for nearly thirty years, and it turns out the missing piece was not the code but a client that could act without a human.
← → jump to the previous / next post