What Is x402 and How Do You Implement It in 2026?
x402 puts a price on a single HTTP request, so an agent can pay for one API call instead of onboarding for a key. This page covers the v2 wire format, three ways to ship it, and the cases where it is the wrong tool.
x402 (HTTP 402 payments for agents) is an open payment standard that attaches a price to an HTTP request: the server answers 402 Payment Required with a machine-readable list of what it accepts, the client retries with a signed payment authorisation, and a facilitator verifies and settles it. Settlement is onchain today, in stablecoins such as USDC on Base or Solana, which makes it a fit for machine-to-machine API access and per-request pricing rather than consumer checkout. Coinbase contributed the protocol and it is now stewarded by the x402 Foundation under the Linux Foundation, which launched operationally on 14 July 2026.
Why x402 matters for AI visibility
An agent cannot fill in a signup form, confirm an email and paste an API key into a dashboard. Anything gated behind that flow is effectively invisible to it, which is why agent traffic concentrates on the small set of endpoints that are open. x402 removes the account entirely: the server answers 402 with a price the client can parse, the client attaches a signed authorisation and retries, and the whole negotiation fits into two round trips with no prior relationship between the parties. For a data or compute provider, that is the difference between being reachable by an agent and being skipped.
The trade-off is the rail. Settlement is onchain, so the buyer needs a funded wallet on a supported network and the seller needs a facilitator, and both sides are accepting a payment method most finance teams have not signed off on. x402 suits metered API access, inference, bulk data and compute, where amounts are fractions of a cent and no human is present to approve anything. It does not suit consumer checkout, refunds and chargebacks, or anything carrying a regulated payment obligation, and it is not the only agent payment design: AP2 takes the opposite approach with signed user mandates settled on card rails. Adoption is also early. Public x402 volume is dominated by testing and sub-dollar API calls and swings hard month to month, so treat it as something to prototype on a paid API, not a rail to migrate existing revenue onto.
Where the spec lives
The specification moved out of the Coinbase repository when the foundation launched, and the v2 rewrite renamed the HTTP headers, so check which copy and which version you are reading before you copy anything into production.
- x402-foundation/x402 - the canonical repository and reference implementations. The old
coinbase/x402repo now carries a notice pointing here, and issues and pull requests were transferred across. - x402 protocol specification v2 - the core data structures (
PaymentRequired,PaymentPayload,SettlementResponse), the facilitator interface, the payment flow models and the error codes. Read this before the docs site. - HTTP transport specification - the exact header names and encodings for the HTTP binding. This is the file to check when a payment header is being ignored.
- MCP transport specification - how the same payment objects travel over Model Context Protocol tool calls, using
_metakeys instead of headers. - bazaar discovery extension - the optional block that lets a facilitator catalogue your paid endpoint, including its input parameters and an example response.
- Quickstart for sellers - the current package names and framework middleware for TypeScript, Python and Go, plus the testnet and mainnet facilitator options.
Three ways to implement x402
The middleware route is the shortest path if you are already on a supported Node framework and only need to price a few routes. Writing the protocol by hand is worth it at the edge, in a language with no SDK, or when you want to see exactly what is on the wire. The MCP route is for teams whose agent-facing surface is a tool server rather than a REST API. All three use the same objects and the same facilitator endpoints, so you can move between them without changing what clients pay.
Price a single route with the Express middleware
Use this when you have an existing Node API and want one endpoint metered. The middleware handles the 402 response, the header encoding and the facilitator calls, so the route handler stays unchanged. Packages moved to the @x402/ scope for v2: the older unscoped x402-express package is still on npm but is stuck on protocol v1.
// npm install express @x402/core @x402/evm @x402/express
import express from "express";
import { paymentMiddleware, x402ResourceServer } from "@x402/express";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { HTTPFacilitatorClient } from "@x402/core/server";
const app = express();
// Public facilitator, testnet only. See the guidelines below for mainnet.
const facilitator = new HTTPFacilitatorClient({
url: "https://x402.org/facilitator",
});
app.use(
paymentMiddleware(
{
"GET /v1/prices": {
accepts: [
{
scheme: "exact",
price: "$0.001",
network: "eip155:84532", // Base Sepolia, CAIP-2
payTo: process.env.EVM_ADDRESS as `0x${string}`,
},
],
description: "Latest reference price, one symbol per call",
mimeType: "application/json",
},
},
new x402ResourceServer(facilitator).register(
"eip155:84532",
new ExactEvmScheme(),
),
),
);
app.get("/v1/prices", (req, res) => {
res.json({ symbol: req.query.symbol, price: 101.25 });
});
app.listen(4021);
What this does: an agent that calls /v1/prices with no payment gets a 402 carrying the price, the network and the address to pay, retries with a signed authorisation, and gets the JSON back on the second request. Every other route on the server stays free, which is what you want if the rest of the site is content you would like models to cite.
Speak the wire protocol yourself at the edge
Reach for this when there is no SDK for your runtime, when you want the 402 answered at the CDN edge rather than at origin, or when you need to see every field. The protocol is small: three base64 JSON headers and two POSTs to a facilitator. The example below is a Cloudflare Worker, but the same twenty lines port to any request handler.
const FACILITATOR = "https://x402.org/facilitator";
// amount is atomic units. USDC has 6 decimals, so "10000" is $0.01.
const ACCEPTS = {
scheme: "exact",
network: "eip155:84532",
amount: "10000",
asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
payTo: "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
maxTimeoutSeconds: 60,
extra: { name: "USDC", version: "2" },
};
const NO_STORE = { "cache-control": "no-store" };
const b64 = (o) => btoa(JSON.stringify(o));
const call = (path, body) =>
fetch(FACILITATOR + path, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(body),
}).then((r) => r.json());
export default {
async fetch(request) {
const url = new URL(request.url);
const required = {
x402Version: 2,
error: "PAYMENT-SIGNATURE header is required",
resource: { url: url.href, mimeType: "application/json" },
accepts: [ACCEPTS],
};
const deny = (b) =>
new Response(b, { status: 402, headers: { "PAYMENT-REQUIRED": b64(required), ...NO_STORE } });
const sig = request.headers.get("PAYMENT-SIGNATURE");
if (!sig) return deny("{}");
const args = { x402Version: 2, paymentPayload: JSON.parse(atob(sig)), paymentRequirements: ACCEPTS };
const verified = await call("/verify", args);
if (!verified.isValid) return deny(JSON.stringify(verified));
// Default authorization flow: verify, run the work, then settle.
const payload = JSON.stringify({ symbol: url.searchParams.get("symbol"), price: 101.25 });
const settled = await call("/settle", args);
if (!settled.success) return deny(JSON.stringify(settled));
return new Response(payload, {
headers: { "content-type": "application/json", "PAYMENT-RESPONSE": b64(settled), ...NO_STORE },
});
},
};
What this does: it implements the full v2 HTTP binding by hand, so you can see that the entire protocol is PAYMENT-REQUIRED going out, PAYMENT-SIGNATURE coming back, and PAYMENT-RESPONSE carrying the receipt. Because settlement runs after the work succeeds and before the body is returned, an agent never pays for a response it did not receive.
Charge per MCP tool call
Use this when your agent-facing surface is an MCP server rather than a REST API. There is no 402 status code in MCP, so the same payment objects travel as a tool result with isError: true on the way out and a _meta["x402/payment"] entry on the way back in. Keep at least one free tool so a client can discover the server before it decides whether to pay.
// npm install @modelcontextprotocol/sdk @x402/core @x402/evm @x402/mcp zod
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { HTTPFacilitatorClient } from "@x402/core/server";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { createPaymentWrapper, x402ResourceServer } from "@x402/mcp";
import { z } from "zod";
const server = new McpServer({ name: "Reference Prices", version: "1.0.0" });
const resourceServer = new x402ResourceServer(
new HTTPFacilitatorClient({ url: "https://x402.org/facilitator" }),
);
resourceServer.register("eip155:84532", new ExactEvmScheme());
await resourceServer.initialize();
const accepts = await resourceServer.buildPaymentRequirements({
scheme: "exact",
network: "eip155:84532",
payTo: process.env.EVM_ADDRESS as `0x${string}`,
price: "$0.001",
extra: { name: "USDC", version: "2" }, // EIP-712 domain parameters
});
const paid = createPaymentWrapper(resourceServer, { accepts });
// Free: lets a client see what this server is before paying anything.
server.tool("list_symbols", "Symbols this server can price", {}, async () => ({
content: [{ type: "text", text: "AAPL, MSFT, NVDA" }],
}));
// Paid: state the price in the description so the agent can budget.
server.tool(
"get_price",
"Latest reference price for one symbol. Costs $0.001 per call.",
{ symbol: z.string() },
paid(async ({ symbol }: { symbol: string }) => ({
content: [{ type: "text", text: JSON.stringify({ symbol, price: 101.25 }) }],
})),
);
What this does: an unpaid call to get_price comes back as an error result carrying the payment requirements, which a payment-aware MCP client turns into a signed retry without asking the model anything. Naming the price in the tool description matters, because that string is what the model reads when it decides whether the call is worth making.
Implementation guidelines
These are the things that break once a paid route meets real clients, a CDN and a browser.
- Pin the protocol version and read it off the request. Version 2 moved the requirements out of the 402 response body into the base64
PAYMENT-REQUIREDheader, replacedX-PAYMENTandX-PAYMENT-RESPONSEwithPAYMENT-SIGNATUREandPAYMENT-RESPONSE, and switched network identifiers from names likebase-sepoliato CAIP-2 strings likeeip155:8453. Branch onx402Versionrather than assuming, and keep a v1 path only as long as you actually have v1 clients. - Decide your facilitator before you go to mainnet. The public
x402.orgfacilitator is for testnet and quickstarts, and the repository README says explicitly not to treat it as the default production path. Pick a production facilitator that supports your network, run your own, or self-facilitate inside the resource server, and note that a facilitator sees every payment you take. - Never cache a paid route. Send
Cache-Control: no-storeon both the 402 and the paid response. A cached 402 hands a stale nonce window to the next caller, and a cached 200 serves one client's settlement receipt in thePAYMENT-RESPONSEheader to another. - Expose the payment headers to browsers. Cross-origin JavaScript cannot read
PAYMENT-REQUIREDorPAYMENT-RESPONSEunless you list them inAccess-Control-Expose-Headers, and it cannot sendPAYMENT-SIGNATUREunless that name is inAccess-Control-Allow-Headers. Missing CORS config is the most common reason a browser client silently fails while curl works. - Settle only after the work succeeded. The default
authorizationflow is verify, run the handler, then settle. If the handler throws, skip/settleentirely. If settle returnserrorReason: "settlement_pending", treat it as non-terminal: the transaction hash in that response is broadcast and may still confirm, so reconcile before you retry and double charge. - Offer more than one way to pay.
acceptsis an array. Listing an EVM network and a Solana network in the same 402 means a client with either wallet type can complete the call, and clients are told to skip entries whose payment flow they do not recognise rather than fail. - Keep your citable content on the free side of the paywall. Price APIs, bulk exports and compute. Anything you want an assistant to read and attribute, including documentation, pricing pages and comparison content, should stay reachable without payment, because a crawler that hits a 402 does not pay, it leaves.
Do this, not that
Do
- Put the per-call price in the
descriptionfield and in your public docs, so an agent can decide before it spends. - Add the
bazaarextension block to your 402 so facilitators can catalogue the endpoint with its inputs and an example response. - Express
amountas a string in atomic units, or let the SDK convert a"$0.001"price using its default asset table. - Keep an unpaid route or tool that describes what the paid one returns, so discovery does not itself cost money.
Do not
- Do not send v1 header names in a v2 integration:
X-PAYMENTis not read by a v2 server. - Do not return the paid body when
/settlecame back withsuccess: false, even though the handler already ran. - Do not point mainnet routes at the public
x402.orgfacilitator. - Do not gate your llms.txt, sitemap, schema markup or article pages behind 402, which removes you from AI answers rather than monetising them.
How Glippy checks this
Glippy does not score x402 yet. There is no check that looks for a 402 response, the PAYMENT-REQUIRED header or a facilitator, so a page carrying a correct x402 integration and a page with none will score the same. What Glippy does test is the surface an agent reaches before any payment question arises: the agent accessibility checks look at whether an agent can find and act on your endpoints at all, and the machine readability checks look at whether the response it gets back can be parsed without a browser. Get those right first, because a paid endpoint nobody can discover earns nothing.
Check what agents can reach for free
Glippy runs 240+ checks across 16 categories on any page. x402 is not one of them yet, but agent accessibility and machine readability are, and they cover everything an agent hits before it is asked to pay. No sign-up required.
Frequently asked questions
Yes, in practice. As of August 2026 settlement happens onchain, most commonly in USDC on Base or Solana, so the paying client needs a funded wallet on a network the facilitator supports. The x402 documentation states that fiat and card payments are not supported natively and that a facilitator or gateway would have to wrap them around the flow. The protocol itself is written to be network and currency agnostic, and card networks including Visa, Mastercard and American Express are members of the x402 Foundation, so that may change, but nothing in the current specification gives you a card rail.
They solve different problems. x402 prices an individual HTTP request and settles it onchain in seconds, with no account and usually no human involved, which fits machine-to-machine API access. AP2 is built around signed mandates: a person authorises an agent to spend within limits, and settlement runs on existing card and bank rails with their dispute and chargeback machinery attached. If a human is buying something, AP2 is the closer fit. If software is buying data or compute by the call, x402 is.
Three, all carrying base64-encoded JSON. The server sends PAYMENT-REQUIRED alongside a 402 status, the client sends PAYMENT-SIGNATURE with its signed payment payload, and the server returns the settlement receipt in PAYMENT-RESPONSE. This changed in v2: version 1 put the requirements in the 402 JSON body and used X-PAYMENT and X-PAYMENT-RESPONSE. Both bindings are documented in the repository, under specs/transports-v1/ and specs/transports-v2/.
For anything you want cited, yes. Assistant crawlers do not carry wallets, so a 402 reads to them as an unavailable page, and the content stops being a candidate for citation. The workable split is to keep pages, documentation and structured data free and reachable, and to price the things an agent consumes rather than quotes: APIs, bulk exports, inference and compute. That way the free layer earns the mention and the paid layer earns the revenue.
Reviewed against the primary sources on . These standards move quickly, so check the linked specs before you ship.