An agent with a wallet and no account asks your API for one thing. For decades HTTP had a status code reserved for exactly this moment and no convention for using it. On 30 September 2026 Cloudflare moved a gateway into beta that answers with a price, takes a signed payment on the retry, and settles before the response leaves the edge. This is the architecture of that exchange: the headers, the order in which money moves, the billing models the protocol encodes, and what your origin has to verify, meter and log once the paywall lives in the proxy.
βββ ββββββββββββββββββββββββββββ
βββ βββββββββββββββββββββββββββββ
ββββββββ βββ βββ ββββββββ
ββββββββ βββ βββ βββββββ
βββ βββ βββ βββ βββ
βββ βββ βββ βββ βββ
βββ βββ βββββββ βββββββ
βββ ββββββββββββββββββββ
βββββββββββββββββ βββββββ
ββββββββββββββββββββββββ
ββββββββββββββββββββ
βββ βββββββ ββββββββ
Say you run a document rendering API. It turns HTML into PDF, and today it sells monthly plans: a signup form, an API key, a card on file, a dashboard with usage graphs. At 03:10 an agent working for somebody you will never meet needs one PDF. It has no account with you and no intention of making one. It has a wallet and a budget. Under your current design it hits your signup page, fails, and goes to a competitor whose endpoint answered with a price instead of a form.
That gap is what Cloudflare's Monetization Gateway, announced in closed beta on 30 September 2026, is built to close. Its blog post describes it as a "paywall for agents": a domain owner writes a pricing rule, and requests that match it get an HTTP 402 Payment Required response carrying the terms. The buyer signs a payment authorization from a wallet, retries the same request, the payment settles in USDC on Base through Coinbase's x402 facilitator, and the origin's response comes back. No redirect to a checkout. No account. API2PDF, one of the launch users the post names, is a document rendering service very much like the one above.
The interesting part is not the stablecoin. It is where the purchase now lives. In the subscription design, identity, pricing, entitlement and billing are application concerns backed by a database. In the 402 design, the request is the purchase: the price is quoted in a response header, the authorization rides in a request header, and settlement happens between your proxy and a facilitator while the request is still open. That moves real architecture out of your application and into the edge, and it creates failure modes subscription billing never had: a payment that settles after your handler already did the work, a retry that must not charge twice, a price that changes between the 402 and the paid retry.
A 402 with a base64 PAYMENT-REQUIRED header listing what the seller accepts: scheme, network, amount in atomic units, asset, recipient, timeout.
The client retries with PAYMENT-SIGNATURE: one chosen option plus a signed, time bounded, single use authorization from its wallet.
A facilitator verifies and settles through /verify and /settle. The protocol defines when that happens relative to your handler, and it matters.
PAYMENT-RESPONSE on the way out carries the result: success, transaction reference, network, payer. That header is your only per call receipt.
Earlier pieces in this catalog looked at payments from the buyer side, and at payment rails like Daraja where the merchant system owns the callback. This one takes the seller side of a protocol where the merchant system might never see the payment at all. With a gateway in front, your origin receives a request that has already been priced and authorized, plus a signed statement saying so. Your origin stops being the paywall and becomes the meter. Design it like one: verify the statement, do the work, report what it cost, and never assume you will be asked twice.
MDN still describes 402 Payment Required as "a nonstandard response status code reserved for future use," created with digital cash and micropayment systems in mind, with "no standard use convention." It also notes that "no browser supports a 402." Payment APIs have used it for years as a generic failed payment error. None of that gave a client enough information to actually pay.
Two conventions now try to fill it, and an agent developer will meet both. They agree on the shape of the exchange: request, 402 challenge, client pays, client retries, server verifies and answers with a receipt. They disagree on the headers.
| Aspect | x402 (v2) | Payment auth scheme (MPP) |
|---|---|---|
| Challenge | PAYMENT-REQUIRED header, base64 JSON |
WWW-Authenticate: Payment with id, realm, method, intent, request |
| Credential | PAYMENT-SIGNATURE header, base64 JSON |
Authorization: Payment, base64url JSON with challenge, source, payload |
| Receipt | PAYMENT-RESPONSE |
Payment-Receipt on 2xx |
| Retry safety | payment-identifier extension, 409 on reuse with a different payload |
Servers SHOULD accept Idempotency-Key |
| Spec status | Protocol v2 in the x402 Foundation repository | Individual Internet Draft, revision 01 dated 17 March 2026, expired 18 September 2026 |
| Who ships it | Coinbase and Cloudflare, founding members of the x402 Foundation | Authors from Tempo Labs and Stripe |
The draft's authors are Brendan Ryan, Jake Moxey and Tom Meagher of Tempo Labs with Jeff Weinstein and Steve Kaliski of Stripe. It is method neutral by design: specific payment methods and intents are registered separately. x402 bundles more into the protocol itself: schemes, networks, a facilitator API and a discovery API. Cloudflare's Agents SDK documentation lists both as supported protocols. If you sell through the Monetization Gateway, you are on x402, and that is the protocol the rest of this piece follows.
A 402 by itself tells a client nothing about how to pay. The headers are the contract. Treat the status code as routing and the headers as the API. A client that handles one convention and receives the other sees an opaque 4xx, which is exactly what browsers have done with 402 all along.
x402 splits itself into three layers. Types are the data structures (PaymentRequirements, PaymentPayload, SettlementResponse). Logic is the scheme and network specific rule for forming and checking a payment. Representation is the transport: HTTP, MCP or A2A. On HTTP, every piece of protocol data travels in three headers. The transport spec says it directly: "Response bodies are a server implementation concern."
Here is a decoded PAYMENT-REQUIRED header, taken from the v2 specification's own example. Note the amount: 10000 atomic units of a six decimal token is one cent.
{
"x402Version": 2,
"error": "PAYMENT-SIGNATURE header is required",
"resource": {
"url": "https://api.example.com/premium-data",
"description": "Access to premium market data",
"mimeType": "application/json"
},
"accepts": [
{
"scheme": "exact",
"network": "eip155:84532",
"amount": "10000",
"asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
"payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
"maxTimeoutSeconds": 60,
"extra": { "name": "USDC", "version": "2" }
}
],
"extensions": {}
}Every field in an accepts entry carries a design decision.
network is a CAIP-2 identifier. eip155:8453 is Base mainnet and eip155:84532 is Base Sepolia. The spec encourages non blockchain networks to follow the same pattern, with ach:us and sepa:eu as its examples, and Cloudflare's credit backed network is cloudflare:402.amount is a string in atomic units. Never a float, never a display price. Your pricing code should produce integers from the start.payTo is a wallet address or a role constant. "merchant" means the network settles on your behalf.maxTimeoutSeconds bounds how long the quote stays good. It is the only thing in the protocol that speaks to price stability between the 402 and the paid retry.accepts is an array. You can quote the same resource on several networks or schemes and let the client choose. Every entry you list is one you must be able to settle.The client's retry carries a PaymentPayload: the one accepts entry it chose (echoed back as accepted), plus a scheme specific payload. For the exact scheme on EVM chains, that payload is an EIP-712 signature over an EIP-3009 authorization with six fields: from, to, value, validAfter, validBefore and nonce. The settlement result comes back in PAYMENT-RESPONSE with success, transaction, network, payer and, when relevant, the amount actually settled.
Cloudflare's network binding in the x402 repository warns that "HTTP intermediaries may reject headers larger than 2KB," and trims its payloads for that reason: it omits extension schemas and drops optional resource fields. If your accepts array lists five networks with long descriptions, some proxy between you and the agent may strip or reject it. Quote the few options you actually want to settle, and keep descriptions in documentation rather than in every 402.
This is the part of x402 that decides your failure modes, and it is easy to miss. The current v2 specification defines three payment flows that differ in when settlement happens relative to your handler running.
| Flow | Ordering | Who carries the risk |
|---|---|---|
authorization (default) |
verify β resource β settle β respond | Seller. The work is done before the funds move. If settlement fails, the compute is spent. |
upfront |
settle β resource β respond | Buyer. Funds move before the work. If the handler fails, the buyer needs a refund path. |
escrow |
settle β resource β settle β respond | Shared. A first settle holds a ceiling, a second records the final charge. |
The spec adds one invariant for all three: at least one check, either a verify or a settle, must run before the resource executes. In its words, "The resource never executes with nothing checked." And it is explicit that /verify is read only. It "MUST NOT commit payment state or write onchain state." A successful verify means the signature, balance, amount, time window and recipient all checked out at that moment, and that a simulated transfer would succeed. It does not mean you have been paid.
The facilitator checks the EIP-712 signature, the payer's balance, an exact amount match, the time window and the recipient, then simulates transferWithAuthorization.
Your origin renders the PDF, runs the query or generates the tokens. This is where the seller spends real money on compute.
The reference middleware for Express, Hono, Fastify and Next.js skips settlement when the handler returns a status of 400 or above. A failed call costs the buyer nothing.
The facilitator calls the token contract with the signed authorization. On failure, the HTTP transport answers 402 with a failed PAYMENT-RESPONSE, after the work is done.
The resource goes back with PAYMENT-RESPONSE carrying the transaction reference. Only now does the buyer have the resource and the seller have the funds.
Step 4 is the seller's exposure. Between verify and settle, the buyer's balance can drop, another settlement with the same wallet can land first, or the facilitator can be unavailable. Each of those means your handler did paid work and the response goes out as a 402. For a one cent render that is noise. For a call that triggers an expensive model run, it is a reason to choose a different flow, cap concurrent unsettled requests per payer, or return the result only after settlement succeeds, which the default ordering already does.
Subscription systems train you to treat "authorized" as "paid," because the card network holds the funds. EIP-3009 authorizations do not reserve anything. The tokens stay in the payer's wallet until /settle moves them. Design your handler so that the expensive part either happens after settlement, or is cheap enough to lose.
A scheme is x402's word for a billing model. The repository now carries four, and the choice between them is a product decision wearing a protocol name.
exact: a fixed price per callThe buyer signs an authorization for exactly the quoted amount. On EVM it uses EIP-3009 transferWithAuthorization, so the transfer is gasless for the buyer and the facilitator submits it. Verification fails with invalid_exact_evm_payload_authorization_value_mismatch if the amounts differ by a single unit.
EIP-3009 uses a random 32 byte nonce rather than a sequential one, and the token contract refuses to accept a nonce twice. The EIP explains why: with sequential nonces, a transaction submitted with a nonce too high "will revert and fail immediately," which breaks concurrent use.validAfter and validBefore limit the window in which the authorization can be submitted.upto: a ceiling, then the real amountThe buyer authorizes a maximum. The seller settles for actual consumption, which "MAY be 0." On EVM this uses Permit2 exclusively, because EIP-3009 "requires exact amounts at signature time." The amount field is phase dependent: at verify time it is the maximum, at settle time it is what to charge, and the facilitator "MUST verify that this amount does not exceed the authorized maximum."
batch-settlement: commit now, settle laterVerification checks a commitment and access is granted immediately. Value moves later through the network's redemption process. The spec names the reason this exists: per request settlement fails when "gas fees exceed the value of individual requests" or when "block confirmation time is incompatible with HTTP response latency." It supports two trust models: capital backed (escrow, payment channels) and credit backed, where a network intermediary vouches for an identity.
cloudflare:402, asset USD, payTo set to "merchant". Clients sign the request with HTTP Message Signatures (RFC 9421) using Signature-Agent, Signature-Input and Signature, with the web-bot-auth tag and Ed25519 keys published at a .well-known directory. Cloudflare acts as merchant of record and bills the identity behind the signature agent.auth-capture: holds, captures and refundsThe newest scheme in the repository (v1.1, 18 August 2026) adds a lifecycle: authorize, charge, capture, void, refund and a buyer side reclaim. Its own comparison table says exact is not reversible and auth-capture is. Captures are only valid up to extra.captureDeadline, refunds up to extra.refundDeadline, and once the capture deadline passes the client can reclaim its own hold, "so a resource server that abandons a payment cannot strand it forever."
| Scheme | Amount known | Funds move | Reversible | Seller needs |
|---|---|---|---|---|
exact |
Before the call | Per request, at settle | No | A stable price per route |
upto |
After the call | Per request, at settle | No | A meter inside the handler |
batch-settlement |
Per commitment | Later, out of band | Network defined | Trust in the network's redemption |
auth-capture |
Up to a held maximum | Hold, then capture | Void, refund, reclaim | Durable state per payment and deadlines |
You can run x402 yourself with the reference middleware: Cloudflare's Agents SDK documents x402-hono for Workers and paidTool for charging per MCP tool call. The Monetization Gateway takes the other route. It speaks the protocol at Cloudflare's edge, and your origin only sees requests that already passed verification.
Pricing lives in monetization rules that, per the blog, "match any part of a request, such as the URL, headers, or query parameters." The rules documentation adds user agents, IP addresses, geolocation and cookies, with request body matching on Enterprise plans. Each rule picks an audience, "Everyone" or "Verified Bots," and a pricing model.
exact scheme: "The gateway settles the signed amount."upto: it "authorizes a maximum price. Your origin discloses and settles the actual amount."Inbound, PAYMENT-CONTEXT: a JWT the gateway adds to paid requests. Validate it against the JWKS at https://payments.cloudflare.com/certs with Ed25519. The docs are blunt: "Do not parse the token without verifying its signature. Reject requests when JWT validation fails," and "If PAYMENT-CONTEXT is absent, treat the request as unpaid and unverified."
Outbound, PAYMENT-SETTLEMENT: for variable pricing only, a JSON value with the actual amount as a string in atomic units, set "before sending response headers." The amount must satisfy 0 <= actual <= authorized maximum. Zero settles nothing. Do not set it when the status is 400 or greater, and do not set it at all for fixed pricing.
Here is the shape of an origin handler for a variable price route, written against the documented contract. The JWT verification helper stands in for whichever library you use. The header names, the JSON shape { "amount": "..." }, the JWKS location, the algorithm and the bounds come from Cloudflare's payment validation page, which also notes that the gateway strips PAYMENT-SETTLEMENT before the response reaches the buyer.
// Origin behind Monetization Gateway, variable (upto) pricing. // Contract: verify PAYMENT-CONTEXT, do the work, report PAYMENT-SETTLEMENT. // verifyEd25519Jwt is your JWT library of choice: pinned JWKS, Ed25519 only, // keys cached per the endpoint's Cache-Control header. const JWKS_URL = "https://payments.cloudflare.com/certs"; export async function handle(req) { const token = req.headers.get("PAYMENT-CONTEXT"); if (!token) return new Response("unpaid", { status: 402 }); // never trust a missing header let ctx; try { ctx = await verifyEd25519Jwt(token, JWKS_URL); } catch { return new Response("bad payment context", { status: 401 }); } const result = await renderPdf(await req.text()); // the paid work if (!result.ok) return new Response("render failed", { status: 500 }); // status >= 400: no PAYMENT-SETTLEMENT header, so nothing is charged const actual = BigInt(result.pages) * 2000n; // $0.002 per page, atomic units return new Response(result.pdf, { status: 200, headers: { "Content-Type": "application/pdf", "PAYMENT-SETTLEMENT": JSON.stringify({ amount: actual.toString() }), }, }); }
The gateway only protects routes that traffic reaches through Cloudflare. Anyone who learns your origin address can call it directly, without a 402 and without paying. That is why the JWT check is not optional decoration. An origin that serves a paid route without validating PAYMENT-CONTEXT is a free API with a paywall painted in front of it. Lock origin ingress to the proxy as well, and treat the JWT as the second lock, not the only one.
Eligibility is narrow during the beta. Sellers must be based in the United States, with Cloudflare accounts older than 60 days and zones older than 30 days, proxied through Cloudflare, with a credit card on file. The blog says buyers must be US based as well, with "support for new geographies on the way." The roadmap items it lists are identity primitives, agent discoverability, transaction logs and payment rails beyond x402, Base and USDC.
Agents retry. Networks drop responses. An agent that sent a signed payment and saw a timeout cannot know whether you settled. Three mechanisms keep that from becoming a double charge or free service.
The same exact authorization cannot settle twice, because the token contract rejects a used nonce. A replayed PAYMENT-SIGNATURE header fails settlement. That protects the buyer's funds. It does not protect your handler, which in the default flow runs before settlement and would do the work again before the duplicate fails.
The payment-identifier extension lets the client attach an id of 16 to 128 characters and reuse it on retries. The server advertises it in the 402 and can make it required. The behavior table is short:
id: process normally.id, same payload: return the cached response.id, different payload: 409 Conflict.required: true and no id: 400 Bad Request.The extension also says to bind each id to a fingerprint covering scheme, network, asset, amount, payTo, path, method and any order identifier, and to scope the key "by tenant, merchant, route, or facilitator account." An id alone is not an authorization key.
Between your 402 and the paid retry, you might change a rule. The client signed the old amount. For exact, verification requires the signed amount to match the requirements the server checks it against, so a stale signature fails with a value mismatch and the client gets a fresh 402. maxTimeoutSeconds tells clients how long a quote holds. Cloudflare's network binding adds that when the timeout is "omitted or set to 0, the network makes no timing guarantees on price validity," and clients "should not cache pricing information across requests."
| Failure | What the protocol does | What you still own |
|---|---|---|
| Handler returns 5xx | Reference middleware skips settlement on status >= 400. Gateway: do not send PAYMENT-SETTLEMENT. |
Making sure a partial result is not returned with a 200 |
| Settle fails after the handler ran | 402 with a failed PAYMENT-RESPONSE |
The compute you spent. Cap per payer exposure. |
| Client retries after a timeout | Nonce blocks a second transfer, not a second execution | Require payment-identifier and cache responses by fingerprint |
| Price changed between quote and retry | exact rejects the mismatch |
Sensible maxTimeoutSeconds, and rule changes that do not surprise clients |
| Variable amount reported above the ceiling | Gateway settles the authorized maximum | A meter you trust, and alerts when you hit the ceiling often |
| Direct hit on the origin | Nothing. The 402 lives at the edge. | JWT validation and origin lockdown |
Micropayments have always died on fixed costs per transaction. x402 changes who pays some of them, not whether they exist.
Facilitator list price: Coinbase's CDP facilitator documentation lists "1,000 transactions free per month, then $0.001 per transaction," and says the facilitator "pays gas fees for settling payments." Buyers do not need gas for exact settlements.
The floor problem: the gateway's minimum price is $0.001. If a settlement at that price paid the CDP list fee, the fee would equal the whole charge. Cloudflare's documentation does not say who bears facilitator fees inside the gateway, or whether the CDP list price applies there. Ask before you price a route at the floor.
Variable routes: a $0.002 per page render that averages five pages settles $0.010 per call, ten times the floor. Pricing per call rather than per unit, or batching work into larger calls, keeps fixed costs a small share.
Credit backed alternative: batch-settlement on cloudflare:402 exists precisely because "gas fees exceed the value of individual requests" for some workloads. It trades onchain finality per call for one bill from the network.
Subscription pricing lets a hundred cheap calls ride on one expensive plan. Per request pricing cannot hide anything. Every priced route has to be worth its own transaction. The product question becomes which single endpoint delivers enough value that an agent will pay for it with no relationship at all. Keep subscriptions for people who want them, and add the metered lane for machines beside them.
PAYMENT-RESPONSE carries the transaction hash, network, payer and, for variable settlements, the settled amount. Log it next to your own request ID and the meter reading that produced the amount. That record is how you answer "why was I charged" without a customer account to look things up in. Transaction logs are on Cloudflare's roadmap, not in the beta.
Without accounts, the payer's wallet address is the closest thing you have to a customer ID. It is good for rate limits and exposure caps per payer. It says nothing about who the human or company behind it is. The x402 spec points at Sign In With Ethereum for "authenticated pricing models," and the credit backed Cloudflare network ties payments to an RFC 9421 signing identity instead.
The CDP facilitator runs Know Your Transaction (KYT) checks and declines payments involving sanctioned or high risk addresses. Some payments will fail at verify for reasons that have nothing to do with your code. Surface the facilitator's error reason in your logs rather than collapsing every failure into "payment failed."
The spec's examples use eip155:84532, Base Sepolia, for a reason. Run the full loop there, including handler failures, retries with the same identifier and a rule change mid quote, before you put a mainnet payTo in a 402. Keep your monetization rules in reviewed configuration. A typo in a match expression is either free service or a 402 on your health check.
The single call an agent would pay for on its own. Fixed if the cost is known, variable if it is metered.
Ingress only through the proxy, plus PAYMENT-CONTEXT validation on every paid route.
Non 2xx on failure, no settlement header on errors, an integer meter for variable routes.
Require a payment identifier, cache responses by fingerprint, return 409 on mismatches.
Transaction hash, payer, amount and your request ID, in one row you can query later.
Four places where the primary sources say different things or leave a gap. Build to the conservative reading in each case.
Cloudflare's Agents payments page says MPP "maintains backward compatibility with x402" and that MPP clients "can consume existing x402 services without modification." The two specs use different headers: x402 puts its challenge in PAYMENT-REQUIRED, and the Payment auth scheme draft uses WWW-Authenticate: Payment. Compatibility therefore depends on a client implementing both conventions, not on the wire formats matching. Test the specific client you care about.
The x402 upto spec says the facilitator "MUST verify" the settle amount does not exceed the authorized maximum, which reads as a rejection. Cloudflare's gateway documentation says that if the origin reports more than the maximum, it "settles the authorized maximum instead." The buyer is never charged above what they signed either way, but your meter and your revenue can silently disagree. Alert on it.
The x402 reference middleware does not settle when the handler returns 400 or above, and the gateway docs say not to send PAYMENT-SETTLEMENT on such responses for variable routes. For fixed price routes behind the gateway, the documentation pages fetched for this article do not say whether an origin error skips settlement. Assume the conservative case until Cloudflare documents it, and do not let a failed render return 200.
Cloudflare's docs call MPP an open protocol, but the Payment auth scheme's IETF draft is an individual submission with no working group, and revision 01 expired on 18 September 2026. x402's v2 spec lives in a foundation repository rather than a standards body. Neither convention is an RFC today.
PAYMENT-REQUIRED, authorize in PAYMENT-SIGNATURE, receipt in PAYMENT-RESPONSE. There is no session to hang billing state on, so design every paid route as a complete transaction.authorization flow the work happens before the money moves. Choose upfront or escrow, or cap exposure per payer, when the work is expensive.exact for known prices, upto for metered work, batch-settlement when per call settlement costs more than the call, auth-capture when you need refunds.PAYMENT-CONTEXT on every request and restrict origin ingress. The 402 only exists at the edge.payment-identifier with a request fingerprint stops a second execution.New deep-dives on systems architecture, delivered when they ship.