Skip to content

50,000 free calls a month, card-free. Get an API key →

Documentation menu
docs / x402 · raw .md
x402: your agent pays per call · 2:50 · all videos

Machine payments (x402)

MapMap is designed so that a software agent can pay for routing the same way it calls it: per request, no dashboard, no human. This page documents the 402 Payment Required shape the gateway returns and the two payment paths an agent can take: prepaid credit (always on) and x402 (on when the operator configures it).

One thing first: every request still needs an API key. x402 pays for a call; it does not replace authentication. A request without Authorization: Bearer snk_… gets a 401 regardless of any payment header. Get a key with one call to POST /v1/keys; see the Quickstart.

Status, honestly: the gateway implements the x402 open payment standard (HTTP transport, protocol version 1) on the server side. The hosted gateway at https://api.mapmap.ai accepts x402 payments on mainnet as of 20 July 2026: its 402s advertise USDC payment requirements on Base and Solana and settle through a facilitator; sign up for a key, or run the self-host distro. Whether a self-hosted deployment accepts x402 payments depends on its configuration: with SN_X402_* set it advertises payment requirements and verifies payments through a facilitator; without them it is "x402-ready", so the 402 keeps the same wire shape with an empty accepts array and points agents at prepaid credit. Prepaid Stripe credit is the settlement rail that works on every deployment.

When you get a 402, and when a 429

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

SituationResponse
Provisional key (email not yet verified) past its 1,000-call allowance402; the error field tells you to verify your email; an X-PAYMENT retry is accepted where x402 is configured, and where SN_TOPUP_PROVISIONAL_SPEND is enabled (as it is on the hosted service) a provisional key can also top up and spend prepaid credit
Verified key past the free tier, identity has bought credit before but the balance is below the per-call price402 with payment options in accepts
Verified key past the free tier, identity has never bought credit, x402 configured402 with payment options in accepts, and an error naming the prepaid-credit route as well. Corrected 10 August 2026: this row previously said 429 with no payment offer, which stopped being true on 17 July
Verified key past the free tier, identity has never bought credit, x402 not configured429 quota-exceeded (RFC 9457 problem+json); the classic hard quota signal, no payment offer
Operator-issued key past its quota429 quota-exceeded; no self-serve payment path
Per-minute rate limit hit (any key)429 rate-limited, with a Retry-After header

The two 429s are distinguishable by their problem type: urn:sn-gateway:problem:quota-exceeded versus urn:sn-gateway:problem:rate-limited. On a deployment with no x402 configured, the never-credited 429 looks like this:

json
{
  "type": "urn:sn-gateway:problem:quota-exceeded",
  "title": "Monthly quota exceeded",
  "status": 429,
  "detail": "monthly quota exceeded (50000/50000)",
  "quota": 50000,
  "used": 50000
}

So an agent that has never paid should not wait for a 402 to discover payment options: on a 429 quota-exceeded, top up prepaid credit (below); after the first top-up, insufficient balance produces 402s. See Conventions for the full error envelope and the 402-vs-429 rules.

The 402 body

The 402 is not RFC 9457 problem+json like the gateway's other errors. It is the x402 wire format (plain application/json), so x402 clients parse it directly. On a deployment without x402 configured, a previously-credited key whose balance has run below the per-call price gets:

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

A provisional key past its allowance gets the same shape with "error": "provisional key call allowance exhausted (1000 calls); verify your email to unlock the free tier of 50000 calls/month". Dispatch on the HTTP status, never on error strings; they are human-readable and may change.

When the operator has configured x402, accepts carries one or more PaymentRequirements objects and instructions changes accordingly:

json
{
  "x402Version": 1,
  "error": "free tier of 50000 calls/month exhausted and prepaid balance is below the request price of 1p",
  "accepts": [
    {
      "scheme": "exact",
      "network": "base",
      "maxAmountRequired": "10000",
      "asset": "0x…",
      "payTo": "0x…",
      "resource": "https://api.mapmap.ai/route/v1/truck/1.3134,51.1279;-1.8904,52.4862",
      "description": "One sn-gateway metered API call (truck/ADR routing, compliance or territory download)",
      "mimeType": "application/json",
      "outputSchema": null,
      "maxTimeoutSeconds": 60,
      "extra": null
    }
  ],
  "instructions": "Pay per call by retrying with an X-PAYMENT header satisfying one of `accepts`, or top up prepaid credits at https://api.mapmap.ai/account"
}

The resource and account URLs in the wire body are both built from the deployment's single configured public base URL (SN_PUBLIC_URL), so they always share a host and vary together per deployment.

Contract rules:

  • The 402 body has no type/title/instance; dispatch on the HTTP status and the x402Version/accepts fields.
  • accepts[] may be empty ("x402-ready") or carry several requirements; ignore schemes you don't implement.
  • If accepts is empty, an X-PAYMENT header is ignored entirely; do not retry with payment; top up prepaid credit instead.
  • Prepaid credit is always an option for verified keys: poll GET $BASE/v1/keys/self until credits_pence > 0, then retry the original request. No new key is needed.

How an agent pays

Both walkthroughs assume:

sh
export BASE=https://api.mapmap.ai   # or your own deployment; see /docs/conventions
export API_KEY=snk_...

Prepaid credit (works everywhere)

Trigger: a truck-profile call past the free tier. Truck and ADR calls are the premium class; ADR is the European agreement on carriage of dangerous goods by road; tunnel codes B–E restrict which tunnels a hazmat load may use (full tunnel-code table in Conventions).

sh
curl -sS -G "$BASE/route/v1/truck/1.3134,51.1279;-1.8904,52.4862" \
  -H "Authorization: Bearer $API_KEY" \
  --data-urlencode "height=4.0" \
  --data-urlencode "weight=44.0"

Past the free tier with no usable balance, that returns one of the 402 bodies above (or the never-credited 429). Then:

  1. Top up at mapmap.ai/account (Stripe card top-up), or ask the operator to credit your identity ledger. Credit is a balance on your email, shared by all its keys, so one top-up covers future 402s until spent.

  2. Poll your balance; this endpoint consumes no quota, credit or rate limit, so agents can poll it freely:

    sh
    curl -sS "$BASE/v1/keys/self" -H "Authorization: Bearer $API_KEY"
    
    json
    {
      "key_id": "3f1c…-uuid",
      "state": "verified",
      "monthly_quota": 50000,
      "used_this_month": 50012,
      "remaining": 0,
      "credits_pence": 500,
      "credits_millipence": 500000,
      "identity_keys": 1
    }
    

    credits_millipence is the full-precision balance (1p = 1,000 millipence), useful because per-call prices are fractional.

  3. Retry the original request unchanged. Each metered call beyond the free tier draws the price for its class: standard routing and data from 0.05p/call, truck/ADR premium from 1p/call, detected per request (see /pricing.json and Pricing).

The 4xx refund rule: the ledger is never charged for a request answered with a client error. The debit is taken before the handler runs, and refunded if the response is a 4xx (a bad request, no route found, and so on). Usage counters still meter the request; only real money moves back. Budget per-call spend against successful responses.

x402 inline payment (when accepts is non-empty)

A facilitator is the service that verifies and settles x402 payments on-chain on the gateway's behalf; the gateway POSTs to its /verify and /settle endpoints and never touches a chain itself.

  1. Pick a PaymentRequirements entry from accepts.

  2. Build an x402 PaymentPayload for it (scheme "exact"). Truncated:

    json
    {
      "x402Version": 1,
      "scheme": "exact",
      "network": "base",
      "payload": {
        "signature": "0x…",
        "authorization": { "value": "10000", "…": "…" }
      }
    }
    

    The payload contents are defined by the scheme; see the x402 core spec v1 (§5.2, PaymentPayload) and the HTTP transport spec. Client libraries in the x402 repository build this for you. The gateway itself checks the envelope (x402Version must be 1; scheme and network must be strings) and leaves payload validation to the facilitator, with one exception: when the operator sets a maximum, payload.authorization.value is capped locally and an over-limit payment is refused with a 402.

  3. Base64-encode the JSON and retry the request, key and payment together:

    sh
    export PAYMENT=$(printf '%s' "$PAYLOAD_JSON" | base64)
    curl -sS -G "$BASE/route/v1/truck/1.3134,51.1279;-1.8904,52.4862" \
      -H "Authorization: Bearer $API_KEY" \
      -H "X-PAYMENT: $PAYMENT" \
      --data-urlencode "height=4.0" \
      --data-urlencode "weight=44.0"
    
  4. The gateway verifies the payment with the configured facilitator's /verify and, on success, serves the request. It fails closed: a request is served only after the facilitator confirms a valid, sufficient payment. A facilitator error is another 402 with the reason in error, never free routing. Your prepaid ledger is left untouched when you pay inline.

  5. Settlement runs asynchronously via the facilitator's /settle. If it completes within the wait window (about 750 ms), the response carries the base64 SettlementResponse in the X-PAYMENT-RESPONSE header. A 2xx response means your payment was verified and the call is final; the absence of X-PAYMENT-RESPONSE only means settlement had not landed in time. There is no settlement-status endpoint; reconcile on-chain via your facilitator.

Dynamic per-request pricing (when the deployment enables it)

With dynamic pricing on, the 402 quotes the exact price of your request instead of one flat rate: the same classifier and size meter that bill the ledger compute entry-band list price × billable units (a matrix bills per started block of 25 elements, an isochrone per contour, an optimisation a flat 10 units), converted to asset units at the deployment's pinned FX rate and floored at a minimum charge. The extra object itemises it:

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"] }
  }
}

Rules an agent can rely on:

  • Quotes are a pure function of your 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.
  • minChargeApplied: true means the settlement floor lifted the quote above list price (facilitator fees exceed sub-cent calls). The floor exists on the per-call rail only; prepaid credit bills true tiered list prices, so for standard-class volume the credit rail is strictly cheaper. listAtomic shows what the list price would have been.
  • One authorization pays for exactly one request. The gateway claims the authorization's nonce before verifying: a byte-identical retry of a lost response is served again without settling twice; a different request on a used nonce is refused with "payment already used".
  • Only successful calls are charged. A 4xx response releases the payment unused, the x402 analogue of the ledger's 4xx refund rule.
  • Large quotes can exceed your client's spend cap (legacy x402-fetch defaults to 0.1 USDC). Raise your client's maxValue or use prepaid credit; quotes above the deployment's per-call cap are steered to credit in instructions.

Paying on Base or Solana (multi-chain)

Where the deployment enables it, one 402 offers more than one chain in accepts[], an EVM entry (Base) and a Solana entry, and you pay on whichever you hold USDC on. USDC is 6-decimals on both, so maxAmountRequired is the same; only the rail differs:

  • EVM (base, base-sepolia): extra carries the EIP-712 domain (name, version) you sign the TransferWithAuthorization against. The payment exposes a transparent value and nonce.
  • Solana (solana, solana-devnet): extra carries feePayer; the facilitator sponsors gas and account rent, so you need only USDC (no SOL). The payment is a single pre-signed transaction; its amount is verified by the facilitator and it settles once via Solana's own blockhash + signature replay protection.

Stock clients handle both: an x402-fetch wired with an EVM signer picks the EVM entry, one wired with a Solana signer picks the Solana entry. Everything else (exact-quote binding, one-authorization-per-request, 4xx-never-charged, and the top-up bridge below) works identically on either rail.

Buying prepaid credit via x402 (POST /v1/x402/topup)

One settlement can fund thousands of calls: POST $BASE/v1/x402/topup?usd=5 (key-authed, consumes no quota) answers a 402 quoting the bundle's exact amount; retry with X-PAYMENT, and on settlement the credit lands on your email identity's ledger: {"status": "credited", "creditedMillipence": …, "balanceMillipence": …, "tx": "0x…"}. Bundles are listed in the 402's extra (the $0.10 micro-bundle clears stock client spend caps unconfigured). Credits are idempotent by settlement transaction hash; a lost response never costs a second payment; poll GET /v1/keys/self before ever re-paying. The efficient loop: watch credits_millipence, top up on a low-water mark, and never hit a 402 mid-workflow.

Enabling x402 on a self-hosted deployment requires all of SN_X402_PAY_TO, SN_X402_FACILITATOR_URL, SN_X402_NETWORK, SN_X402_ASSET and SN_X402_PRICE_ATOMIC (all-or-nothing), plus optional SN_X402_MAX_AMOUNT (per-call rail only). Dynamic quotes and the top-up bridge switch on with SN_X402_MICROUSD_PER_PENCE (µUSD per penny, e.g. 15000 = $1.50/£), with optional SN_X402_MIN_CHARGE_ATOMIC (default 5000 = $0.005), SN_X402_TOPUP_BUNDLES_USD (default 0.10,5,20,50; none disables) and SN_TOPUP_PROVISIONAL_SPEND (lets unverified identities spend credited balance; payment as the verification signal). SN_X402_FACILITATOR_URL points at any x402 facilitator exposing /verify and /settle; the x402 project lists public facilitators, including Coinbase's for the Base networks.

Agents that implement x402 pay inline; agents that don't keep using prepaid credit. The response shape is the same either way.

Next steps

  • Quickstart: issue a key and make your first call
  • Conventions: base URL, auth, error envelope, 402-vs-429
  • Self-host: run your own gateway, with or without x402
  • Pricing: per-call prices, plans and top-ups