x402 machine payments: what is live, what is not

# x402 machine payments: what is live, what is not

The MapMap gateway implements the server side of the x402 open payment standard (HTTP transport, protocol version 1). A `402 Payment Required` from any deployment carries the x402 wire body `{x402Version, error, accepts[], instructions}`, and where an operator has configured payment, an agent retries with an `X-PAYMENT` header and gets served. When this post was first published (2 July) the hosted gateway at `https://api.mapmap.ai` had x402 switched off. That changed on 20 July 2026: the hosted gateway now accepts x402 on mainnet, with the first settlements on-chain. The go-live and what it proved are covered in [x402 is live on mainnet](/news/x402-mainnet-live); everything below about the wire format, the 402-versus-429 rules and the quote arithmetic is unchanged and current. Prepaid credit remains the settlement rail that works on every deployment. x402 is the rail that works where it is configured, which now includes ours.

## What does a MapMap 402 actually contain?

The x402 wire format, in plain `application/json`, so an x402 client can parse it without knowing anything about us:

```json
{
"x402Version": 1,
"error": "free tier of 50000 calls/month exhausted and prepaid balance is below the request price of 1p",
"accepts": [],
"instructions": "x402 payment is not enabled on this deployment yet; top up prepaid credits at https://api.mapmap.ai/account to continue"
}
```

That is the body you get from a deployment that has not configured x402, which described the hosted gateway until 20 July. Four fields, no more. When the operator has configured x402, `accepts[]` fills with `PaymentRequirements` objects (`scheme`, `network`, `maxAmountRequired`, `asset`, `payTo`, `resource`, `maxTimeoutSeconds`, `extra`) and `instructions` changes to tell you to retry with `X-PAYMENT`. The full shape lives in the [x402 payment docs](/docs/x402), which are authoritative on the wire format.

Two rules an agent should hard-code:

- **Dispatch on the HTTP status and the `x402Version`/`accepts` fields.** The `error` string is human-readable and may change.
- **If `accepts` is empty, an `X-PAYMENT` header is ignored entirely.** Do not retry with payment. Top up prepaid credit instead.

## Why is the 402 the one endpoint that breaks our error model?

Because x402 clients parse the body, and a spec-shaped body beats a house-shaped one. Every other error the gateway returns is RFC 9457 problem+json with a stable `urn:sn-gateway:problem:<slug>` type URI, precisely so an agent can branch on the type rather than on prose. The 402 is the single deliberate exception. It has no `type`, no `title`, no `instance`, because an off-the-shelf x402 client library expects `x402Version` and `accepts` at the top level and would choke on our envelope.

We would rather have one documented exception than an error model that is internally tidy and unusable by the ecosystem it is meant to serve. (The compatible URL routing endpoint has its own envelope too, for the same reason: matching the client that already exists beats matching ourselves.)

## When do you get a 402, and when a 429?

Not every out-of-quota response is a 402. What you get depends on your key's state and payment history:

| Situation | Response |
|---|---|
| Provisional key (email unverified) past its 1,000-call allowance | `402`, `error` says verify your email; provisional keys cannot draw prepaid credit |
| Verified key past the free tier, identity has bought credit before, balance below the per-call price | `402` with payment options in `accepts` |
| Verified key past the free tier, identity has never bought credit | `429` quota-exceeded, problem+json, no payment offer |
| Operator-issued key past its quota | `429` quota-exceeded, no self-serve payment path |
| Per-minute rate limit hit, any key | `429` rate-limited, with `Retry-After` |

The two 429s are distinguishable by problem `type`: `urn:sn-gateway:problem:quota-exceeded` versus `urn:sn-gateway:problem:rate-limited`. The practical consequence is that an agent which has never paid should not sit waiting for a 402 to discover its payment options. On a `429` quota-exceeded, top up. After the first top-up, insufficient balance produces 402s.

No credit means a 402 or a 429. It never means a surprise bill. There is no post-paid overage on any MapMap plan, because paid usage is prepaid credit or a monthly plan and nothing else.

## What does dynamic pricing quote?

Your exact request, itemised, with the arithmetic shown. With dynamic pricing enabled (`SN_X402_MICROUSD_PER_PENCE`), the 402 stops quoting a flat rate and runs the same classifier and size meter that bill the ledger: `entry-band list price × billable units`, converted at the deployment's pinned FX rate, floored at a minimum charge. The `extra` object shows the working:

```json
{
"scheme": "exact", "network": "base",
"maxAmountRequired": "5000",
"description": "MapMap /matrix: 4 billable units, standard class, list 0.2p",
"extra": {
"class": "standard", "units": 4, "pencePerUnit": 0.05,
"listPence": 0.2, "listAtomic": "3000", "minChargeApplied": true,
"fxMicroUsdPerPence": 15000, "totalUsd": 0.005,
"topup": { "resource": "https://api.mapmap.ai/v1/x402/topup", "bundlesUsd": ["0.10", "5", "20", "50"] }
}
}
```

Four guarantees you can build against:

- **Quotes are a pure function of the request.** The same method, path and body always quote the same amount.
- **Sign exactly `maxAmountRequired`.** A mismatched value is refused before any facilitator round-trip.
- **One authorization pays for exactly one request.** The gateway claims the authorization's nonce before verifying, so a byte-identical retry of a lost response is served again without settling twice, while a different request on a used nonce is refused with "payment already used".
- **4xx responses are never charged.** A client error releases the payment unused, mirroring the prepaid ledger's refund rule where the debit is taken before the handler runs and returned on any 4xx. Usage counters still meter the request. Only real money moves back.

Read `minChargeApplied: true` carefully. It means the settlement floor (default `5000`, or $0.005) lifted the quote above list price, because facilitator fees exceed the cost of a sub-cent call. `listAtomic` shows what list would have been. The floor exists on the per-call rail only, so for standard-class volume at 0.05p a call, prepaid credit is strictly cheaper. We would rather tell you that than sell you the shiny rail.

## How does an agent buy volume in one settlement?

One x402 settlement at the top-up bridge, which credits the prepaid ledger at true list prices with no per-call floor:

```sh
curl -sS -X POST "$BASE/v1/x402/topup?usd=5" \
-H "Authorization: Bearer $API_KEY"
```

That answers a `402` quoting the bundle's exact amount. Retry it with the `X-PAYMENT` header, and on settlement the credit lands on your email identity's ledger. At a pinned rate of 15000 µUSD per penny, starting from a zero balance, a $5 bundle lands as:

```json
{"status": "credited", "creditedMillipence": 333333, "balanceMillipence": 333333, "tx": "0x…"}
```

The endpoint is key-authed and consumes no quota. Bundles are listed in the 402's `extra`, and the $0.10 micro-bundle is there so a client running its default spend cap can pay without being reconfigured first. Credits are **idempotent by settlement transaction hash**, so a lost response never costs you a second payment. Poll `GET /v1/keys/self` before you ever re-pay. That endpoint consumes no quota, no credit and no rate limit, so poll it freely. The efficient loop is to watch `credits_millipence`, top up on a low-water mark, and never hit a 402 mid-workflow at all.

## What is not switched on yet

*Updated 20 July 2026.* The first two items on the original list are done: the hosted gateway accepts x402 on mainnet with dynamic quoting and the top-up bridge live, and the first settlements are on-chain. The full account, including the mainnet interop bug the go-live check caught, is in [x402 is live on mainnet](/news/x402-mainnet-live). What genuinely remains:

- **There is no settlement-status endpoint.** If settlement does not land inside the roughly 750 ms wait window, you get no `X-PAYMENT-RESPONSE` header. A 2xx still means the payment verified and the call is final. Reconcile on-chain via your facilitator.
- **Provisional keys cannot draw prepaid credit.** They can pay per-call with `X-PAYMENT`; spending banked credit needs a verified email.
- **Large quotes can exceed your client's spend cap.** Legacy `x402-fetch` defaults to 0.1 USDC. Raise `maxValue` or use credit.

Self-hosters are not waiting on us for any of this. Set `SN_X402_PAY_TO`, `SN_X402_FACILITATOR_URL`, `SN_X402_NETWORK`, `SN_X402_ASSET` and `SN_X402_PRICE_ATOMIC`, point the facilitator URL at any service exposing `/verify` and `/settle`, and your deployment accepts machine payments today. The gateway fails closed: a request is served only after the facilitator confirms a valid, sufficient payment. A facilitator error is another 402, never free routing.

## Try it

Get a key with one call and read the 402 contract before you need it rather than during an outage. The [x402 payment docs](/docs/x402) carry the full wire shapes and the self-host configuration. The [agents page](/agents) covers the rest of the machine-legible surface: `/llms.txt`, `/pricing.json`, `/openapi.json` and the hosted MCP server. For how an agent gets from cold start to a route with no human involved, read [maps for AI agents](/news/maps-for-ai). For what a call costs and how the meter counts it, read [metered keys and pricing](/news/metered-keys-and-pricing).

Routing derives from OpenStreetMap. Credit "© OpenStreetMap contributors" when you render or republish it.