# The Request Is the Purchase: Architecture of HTTP 402 Metered Access for Agents

> How x402 turns HTTP 402 into a checkout for agents: the quote, the signed retry, when settlement happens, schemes, and the origin contract.

- Canonical: https://thearchitecturedeepdive.blog/articles/http-402-metered-access.html
- Series: The Architecture DeepDive, No. 028
- Author: Barnabas Waweru
- Published: 2026-10-06
- Tags: Payments, AI Agents, Networking
- Cite as: Barnabas Waweru, "The Request Is the Purchase: Architecture of HTTP 402 Metered Access for Agents", The Architecture DeepDive, https://thearchitecturedeepdive.blog/articles/http-402-metered-access.html

---

x402 · Cloudflare Monetization Gateway

Per Request Settlement at the Edge

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.

## Overview

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.

#### The Quote

A `402` with a base64 `PAYMENT-REQUIRED` header listing what the seller accepts: scheme, network, amount in atomic units, asset, recipient, timeout.

#### The Authorization

The client retries with `PAYMENT-SIGNATURE`: one chosen option plus a signed, time bounded, single use authorization from its wallet.

#### The Settlement

A facilitator verifies and settles through `/verify` and `/settle`. The protocol defines when that happens relative to your handler, and it matters.

#### The Receipt

`PAYMENT-RESPONSE` on the way out carries the result: success, transaction reference, network, payer. That header is your only per call receipt.

The Paywall Moved to the Proxy

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.

## A Status Code With Two Conventions

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.

Same Status, Different Contract

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.

## The Wire Format

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."

```
CLIENT (agent) RESOURCE SERVER (your edge) FACILITATOR │ │ │ 1 │── GET /render ──────────────▶│ │ │◀─ 402 PAYMENT-REQUIRED ─────│ accepts[]: scheme, network, │ │ (base64 JSON) │ amount, asset, payTo, │ │ │ maxTimeoutSeconds, extra │ 2 │ pick one accepts[] entry │ │ │ sign authorization │ │ │ (wallet, time bound, │ │ │ random 32 byte nonce) │ │ 3 │── GET /render ──────────────▶│ │ │ PAYMENT-SIGNATURE (base64) │── POST /verify ──────────────▶│ │ │◀─ { isValid, payer } ─────────│ 4 │ │ run the handler │ 5 │ │── POST /settle ──────────────▶│ │ │◀─ { success, transaction } ───│ 6 │◀─ 200 PAYMENT-RESPONSE ─────│ │ │ + the resource │ │ Default "authorization" flow: verify, resource, settle, respond. The client never talks to the facilitator. The seller never holds keys that can move the buyer's funds beyond what the buyer signed.
```

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.

### The fields that matter to a seller

-   **`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.

Headers Have a Size Budget

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.**

## When the Money Moves

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.

01

#### Verify

The facilitator checks the `EIP-712` signature, the payer's balance, an exact amount match, the time window and the recipient, then simulates `transferWithAuthorization`.

02

#### Run the handler

Your origin renders the PDF, runs the query or generates the tokens. This is where the seller spends real money on compute.

03

#### Check the outcome

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.

04

#### Settle

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.

05

#### Respond

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.

Verify Is a Promise, Settle Is a Payment

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.**

## Four Schemes, Four Billing Models

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 call

The 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.

-   **Replay protection:** `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.
-   **Time bounds:** `validAfter` and `validBefore` limit the window in which the authorization can be submitted.
-   **Fits:** search queries, document renders, single data lookups. Anything where cost is known before the work starts.

### `upto`: a ceiling, then the real amount

The 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."

-   **Single use:** each authorization settles at most once. No streaming, no per chunk settlement, no recurring charges.
-   **One time setup:** Permit2 needs the buyer to approve the Permit2 contract once, either directly with their own gas or through a sponsored extension.
-   **Fits:** LLM token generation, bandwidth, compute priced after the fact.

### `batch-settlement`: commit now, settle later

Verification 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's binding:** network `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.
-   **Clients with a preauthorized agreement** can send the payment headers on the first request and skip the 402 entirely.

### `auth-capture`: holds, captures and refunds

The 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."

-   **Fits:** delayed delivery, buyer protection, metered work where you want card style semantics on a stablecoin rail.

| 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 |

## The Gateway as Seller

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.

```
┌──────────── CLOUDFLARE EDGE ─────────────┐ agent ──────────▶│ monetization rule matches? │ │ no ──▶ normal proxy path ─────────────┼──▶ origin │ yes, no PAYMENT-SIGNATURE │ agent ◀── 402 ───│ ──▶ PAYMENT-REQUIRED quote │ │ yes, PAYMENT-SIGNATURE present │ │ ──▶ verify with x402 facilitator │ │ ──▶ add PAYMENT-CONTEXT (signed JWT)┼──▶ origin │ │ │ │ │ validate JWT │ │ do the work │ ◀── response (+ PAYMENT-SETTLEMENT │◀────┘ │ for variable pricing) │ │ ──▶ settle (USDC on Base) │ agent ◀── 200 ───│ origin response returned after settle │ └───────────────────────────────────────────┘ The origin never touches a wallet. It reads one header, writes one header.
```

### Rules are the price list

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.

-   **Fixed** maps to the `exact` scheme: "The gateway settles the signed amount."
-   **Variable** maps to `upto`: it "authorizes a maximum price. Your origin discloses and settles the actual amount."
-   **Units:** one atomic unit is $0.000001. The minimum settlement is $0.001 (1,000 units) and the maximum price is $100 (100,000,000 units).

### The origin contract: two headers

**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() }),
    },
  });
}
```

Assume the Proxy Can Be Bypassed

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.

## Retries, Replays and Moving Prices

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 nonce stops a replayed payment

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 stops a repeated purchase

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:

-   New `id`: process normally.
-   Same `id`, same payload: return the cached response.
-   Same `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.

### The timeout bounds a moving price

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 |

## The Unit Economics of a Tenth of a Cent

Micropayments have always died on fixed costs per transaction. x402 changes who pays some of them, not whether they exist.

Cost Reality Check

**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.

Find the Call Worth Selling Alone

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.

## Operating a Metered Endpoint

### Reconcile against the receipt

`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.

### Treat the payer address as an identity, carefully

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.

### Expect compliance checks you do not control

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."

### Test on Base Sepolia, write rules as code

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.

01

#### Pick one route

The single call an agent would pay for on its own. Fixed if the cost is known, variable if it is metered.

02

#### Lock the origin

Ingress only through the proxy, plus `PAYMENT-CONTEXT` validation on every paid route.

03

#### Make the handler honest

Non 2xx on failure, no settlement header on errors, an integer meter for variable routes.

04

#### Make retries safe

Require a payment identifier, cache responses by fingerprint, return 409 on mismatches.

05

#### Log the receipt

Transaction hash, payer, amount and your request ID, in one row you can query later.

## Where the Sources Disagree

Four places where the primary sources say different things or leave a gap. Build to the conservative reading in each case.

### Is MPP compatible with x402?

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.

### A variable amount above the ceiling

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.

### Fixed price routes that fail at the origin

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.

### The state of the alternative standard

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.

## Key Takeaways

### Principles

1.  **The request is the purchase.** Quote in `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.
2.  **Know your flow before you write the handler.** In the default `authorization` flow the work happens before the money moves. Choose `upfront` or `escrow`, or cap exposure per payer, when the work is expensive.
3.  **Verify is not payment.** A successful verify is read only and reserves nothing. Only settle moves funds.
4.  **Pick the scheme from the cost model.** `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.
5.  **The origin is the meter, and the meter must lock its own door.** Validate `PAYMENT-CONTEXT` on every request and restrict origin ingress. The 402 only exists at the edge.
6.  **Retries need identity, not just nonces.** Nonces stop a second transfer. A required `payment-identifier` with a request fingerprint stops a second execution.
7.  **Errors must look like errors.** Return 4xx or 5xx on failure and never attach a settlement amount to them. A 200 with a broken body is a charge for nothing.
8.  **Price above the fixed costs.** A $0.001 route can cost as much to settle as it earns. Find out who pays facilitator fees before you price at the floor.
9.  **Log the receipt as your customer record.** Transaction hash, payer, amount and request ID are all you will have when someone asks what they paid for.

### Official Sources

[Cloudflare Blog: Monetization Gateway beta, charge AI agents for consumption with HTTP 402 (30 September 2026)](https://blog.cloudflare.com/monetization-gateway-beta/) [Cloudflare Docs: Monetization Gateway, x402 protocol request flow](https://developers.cloudflare.com/monetization-gateway/x402/index.md) [Cloudflare Docs: Monetization Gateway, monetization rules](https://developers.cloudflare.com/monetization-gateway/configuration/rules/) [Cloudflare Docs: Monetization Gateway, payment validation (PAYMENT-CONTEXT and PAYMENT-SETTLEMENT)](https://developers.cloudflare.com/monetization-gateway/configuration/payment-validation/index.md) [Cloudflare Docs: Monetization Gateway, eligibility](https://developers.cloudflare.com/monetization-gateway/eligibility/index.md) [Cloudflare Docs: Monetization Gateway, get started](https://developers.cloudflare.com/monetization-gateway/get-started/index.md) [Cloudflare Agents Docs: Agentic Payments (x402 and MPP)](https://developers.cloudflare.com/agents/tools/payments/) [Cloudflare Agents Docs: x402](https://developers.cloudflare.com/agents/x402) [x402 Foundation: x402 Protocol Specification v2](https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v2.md) [x402 Foundation: HTTP transport v2](https://github.com/x402-foundation/x402/blob/main/specs/transports-v2/http.md) [x402 Foundation: the upto scheme](https://github.com/x402-foundation/x402/blob/main/specs/schemes/upto/scheme_upto.md) [x402 Foundation: the upto scheme on EVM (Permit2)](https://github.com/x402-foundation/x402/blob/main/specs/schemes/upto/scheme_upto_evm.md) [x402 Foundation: the batch settlement scheme](https://github.com/x402-foundation/x402/blob/main/specs/schemes/batch-settlement/scheme_batch_settlement.md) [x402 Foundation: batch settlement on cloudflare:402](https://github.com/x402-foundation/x402/blob/main/specs/schemes/batch-settlement/scheme_batch_settlement_cloudflare.md) [x402 Foundation: the auth capture scheme](https://github.com/x402-foundation/x402/blob/main/specs/schemes/auth-capture/scheme_auth_capture.md) [x402 Foundation: payment identifier extension](https://github.com/x402-foundation/x402/blob/main/specs/extensions/payment_identifier.md) [x402 Foundation: Express middleware (no settlement on status 400 and above)](https://github.com/x402-foundation/x402/blob/main/typescript/packages/http/express/src/index.ts) [Coinbase Developer Platform: x402 facilitator](https://docs.cdp.coinbase.com/x402/core-concepts/facilitator) [ERC-3009: Transfer With Authorization](https://eips.ethereum.org/EIPS/eip-3009) [IETF draft-ryan-httpauth-payment-01: The Payment HTTP Authentication Scheme](https://datatracker.ietf.org/doc/html/draft-ryan-httpauth-payment-01) [RFC 9421: HTTP Message Signatures](https://rfc-editor.org/rfc/rfc9421.html) [MDN: 402 Payment Required](https://developer.mozilla.org/docs/Web/HTTP/Reference/Status/402)
