Metered keys and pricing: prepaid only, no surprise billing

# Metered keys and pricing: prepaid only, no surprise billing

MapMap has no post-paid overage on any path. You start with a provisional key worth 1,000 calls over 72 hours, issued in one API call with no card. Verifying an email upgrades that same key to 50,000 included calls a month with commercial use allowed. Past that, calls draw prepaid credit at 0.05p for a standard call and 1p for a truck or ADR call, stepping down with monthly volume. When the credit is gone the API returns `402` or `429` and stops. It does not keep serving and send you an invoice, because we decided that a bill you cannot refuse is not a feature.

## Why we bill prepaid credit and never post-paid

Because post-paid metering turns a bug in your code into a debt you did not agree to. A retry loop with no backoff, a matrix built from an unbounded list, or an agent that decides the fix for a `500` is to try 4,000 more times: every one of those is a normal Tuesday, and on a post-paid meter every one of them arrives as a five-figure line item at the end of the month. The provider has no incentive to stop it. They are being paid by the mistake.

Prepaid inverts that. The ceiling is a number you chose in advance, and the worst case is that requests stop. A hard stop is the correct failure mode for a metered API, and we accept the cost of that position, which is real and which we name in the limits section below.

It matters more for the reader we built the platform for. An AI agent holding a key cannot phone the finance team to explain a runaway loop. It needs a spend ceiling it physically cannot exceed, enforced in the gateway rather than promised in a terms page.

The rule that follows: **keys carry hard limits, and no path on the platform produces a charge you did not fund first.**

## Getting a key costs nothing and needs no card

One `POST`, no dashboard, no CAPTCHA, no phone number.

```sh
export BASE=https://api.mapmap.ai

curl -fsS -X POST "$BASE/v1/keys" \
-H "Content-Type: application/json" \
-d '{"email": "you@example.co.uk", "accept_tos": true}'
```

```json
{
"key": "snk_…",
"key_id": "3f1c…-uuid",
"state": "provisional",
"calls": 1000,
"expires_in_h": 72,
"verify": "link sent to email; clicking upgrades this key to the free tier",
"tos": "https://mapmap.ai/terms"
}
```

The key is shown once, so store it on receipt. It works immediately, rate-limited to 60 requests a minute, and it expires after 72 hours if nothing verifies it. A magic link goes to the address separately, and clicking it upgrades that same key to the free tier. A provisional key cannot download offline territory layers, and by default it cannot draw prepaid credit either, though an operator can opt a deployment into letting a credited provisional identity spend its balance. It exists to prove the integration works before you decide anything.

## The free tier is 50,000 included calls a month, and commercial use is allowed

Verify an email and the key carries 50,000 included calls per calendar month, indefinitely, and you may ship a commercial product on it. There is no trial cliff. We are not going to switch it off at day 30 and ask you to talk to sales.

How that quota is counted:

| Rule | Value |
|---|---|
| Included calls, verified free tier | 50,000 per calendar month |
| Premium quota weight | one premium (truck/ADR) call draws 20 included calls |
| All-premium free usage | 2,500 calls per month |
| Quota scope | per identity (your email), shared across all of that identity's keys |
| Active keys per identity | 5 |
| Behaviour at the limit | hard stop, unless prepaid credit is present |

Issuing more keys does not multiply the quota. The meter is attached to the identity, not the credential.

## What does a call cost beyond the free tier?

Prepaid credit, at a two-speed tiered marginal rate. Two classes, three bands each, selected automatically from the request itself. These figures reconcile with [the machine-readable price list](/pricing.json), which is authoritative and wins if this post ever drifts.

| Class | Applies to | 50k to 1M/month | 1M to 10M | Beyond 10M |
|---|---|---|---|---|
| Standard | Car, van, bus, two-wheeler and pedestrian routing, geocoding, matrix, isochrone, map-matching | 0.05p | 0.03p | 0.02p |
| Premium | Truck routing and ADR compliance | 1p | 0.7p | 0.4p |

Two properties of that table are worth stating explicitly, because pricing pages usually leave them ambiguous.

**Marginal, not retroactive.** Each band applies only to the calls that fall within it, selected by month-to-date usage. Your 1,000,001st standard call costs 0.03p. The million before it still cost 0.05p each. Crossing a threshold never reprices what you already spent.

**Automatic, not chosen.** You do not select a class or a plan. The gateway reads each request and prices it: `"costing": "truck"`, a top-level `adr` object, `"hazmat": true`, a call to `/adr/check`, or a truck vendor query parameter on the compatible endpoint puts the request in the premium class. Everything else is standard.

Fractional pence bill exactly. The gateway meters an internal millipence ledger where 1p is 1,000 millipence, so a 0.02p call is a real 20-millipence debit rather than a rounding argument. Every external field, including `credits_pence`, stays in pence, and `GET /v1/keys/self` returns both `credits_pence` (floored) and `credits_millipence` (full precision).

Top-ups are Stripe Checkout at £10, £25 or £50. Above 25M calls a month, we quote.

## Why does a truck or ADR call draw 20 included calls?

Because 1p is 20 times 0.05p, and included volume is denominated in standard calls. A premium request costs 1p against a standard 0.05p, a ratio of 20, so a premium call draws 20 included calls from the free tier or a plan. The weighting is not a penalty invented for the free tier. It is the price ratio, applied to included volume so the two rails agree.

The part that trips people up: the 20:1 weight applies to **included** volume only. Once you are spending credit, a premium call costs 1p, priced by its own schedule, not 20 x 0.05p expressed some other way.

## When is one request more than one call?

When the request's size varies, we meter the size, and the rules are published rather than discovered on a bill.

| Request | Billing unit | Cap |
|---|---|---|
| Everything else | 1 call per request | n/a |
| `POST /matrix` | 1 call per started block of 25 elements (`sources × targets`) | 10,000 elements per request |
| `POST /isochrone` | 1 call per contour | 10 contours per request |
| `POST /optimise` | flat 10 calls per request | 200 unique locations |

"Started block" means a 26-element matrix bills two calls, not 1.04. A 5 x 5 matrix is 25 elements and bills one call. A 100 x 100 matrix is 10,000 elements, sits exactly on the cap, and bills 400 calls: at standard rates that is 20p.

One more rule, and it is the one that matters when you are debugging: **a request answered with a client error (4xx) is never charged.** The debit is refunded. It still counts against the monthly quota, so a broken loop can exhaust your free tier without costing money.

## What happens when the money runs out?

You get one of two responses, and they mean different things. A verified identity that has never bought credit hits its quota and gets a `429`:

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

A provisional key past its 1,000 calls, or a credited identity whose balance has fallen below the request price, gets a `402` in the x402 wire format instead of our usual problem+json, because machine clients parse it directly. This is the credited-identity case, where the balance no longer covers a 1p premium call:

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

The provisional case is the same shape with its own `error`, which tells you the way out rather than asking for money:

```json
{
"error": "provisional key call allowance exhausted (1000 calls); verify your email to unlock the free tier of 50000 calls/month"
}
```

The rule of thumb: `429` means stop or wait, `402` means there is a way to pay. Neither is an invoice. The full decision table lives in [the API conventions](/docs/conventions), and the machine-payment path is covered in [how agents pay for calls](/news/x402-machine-payments).

To avoid meeting either one mid-job, poll your own key state. It is free: `GET /v1/keys/self` consumes no quota, no credit and no rate limit, precisely so that watching a balance never costs you a call.

```sh
curl -fsS "$BASE/v1/keys/self" -H "Authorization: Bearer $API_KEY"
```

```json
{
"key_id": "3f1c…-uuid",
"state": "provisional",
"monthly_quota": 1000,
"used_this_month": 1,
"remaining": 999,
"credits_pence": 0,
"credits_millipence": 0,
"expires_at": "2026-07-18T09:00:00Z",
"identity_keys": 1
}
```

That body is abridged to the billing fields. The real response also carries `download_allowance_mib`, `download_used_mib`, `mau_this_month`, `mau_included` and `mau_overdrawn`, so a single free poll covers your call quota, your offline download allowance and your monthly active users at once.

## What this pricing does not do

The honest list. Every one of these is a real cost of the position we took.

- **You can be hard-stopped in the middle of a job.** This is the direct price of no post-paid overage, and it is not a benefit in disguise. If a fleet's overnight optimisation run exhausts a balance at 03:00, it stops at 03:00. Poll `/v1/keys/self` and top up before the run, because nothing on the platform will float you the difference.
- **Per-call x402 always prices at the entry band.** A machine payment settled per request is quoted at the entry-band list price with no volume discount, while prepaid credit bills true tiered prices. For standard-class volume the credit rail is strictly cheaper, so an agent doing volume should top up rather than pay per call.
- **Whether x402 is accepted at all depends on the deployment.** The gateway implements x402 v1 server-side, but accepting payment is configuration-gated. When unconfigured, the `402` keeps the x402 shape with an empty `accepts[]` and prepaid Stripe credit is the settlement rail.
- **Offline territory downloads are metered separately, in bytes.** The free tier includes roughly 2 GB a month of offline evaluation allowance: enough to install one region on one device for a proof of concept, not enough to equip a fleet. Online API use never touches it.
- **Above 25M calls a month, you have to talk to us.** We publish everything up to that line and quote above it.
- **Prices in this post are illustrative of the time of writing.** `/pricing.json` is always authoritative, and if the two disagree, this post is wrong.

## Try it

Issue a key with the `curl` above and read `/pricing.json` on whichever deployment you are pointed at, because it is served per deployment rather than globally. The human-readable version, including the plans that lower the effective rate on volume, is on [the pricing page](/pricing). The quota, rate-limit and error semantics behind all of it are in [the API conventions](/docs/conventions).

Routing derives from OpenStreetMap, so credit "© OpenStreetMap contributors" when you render or republish it.