# Quickstart

From nothing to a dimensioned truck route in two calls. No install needed to try it:
the [playground](/playground) runs the same requests from your browser.

**Status, honestly:** the hosted gateway at `https://api.mapmap.ai` is live:
[sign up](/signup) for a key, or run the [self-host distro](/docs/self-host);
every call below works identically against your own deployment.
Base URL, auth and conventions are defined in full on the
[conventions page](/docs/conventions).

![Truck routing with multiple stops, from key to rendered route](/docs-videos/directions-multistop.mp4)

Set up your shell once so every snippet on this page is copy-pasteable:

```sh
export BASE=https://api.mapmap.ai   # or your self-hosted gateway origin
```

## 1. Issue a key, one call, card-free

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

Response (`201 Created`):

```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 `snk_` key is shown once.** Store it now:

```sh
export API_KEY=snk_…   # the "key" field from the response
```

It is live immediately as a *provisional* key: 1,000 calls, valid for 72 hours,
rate-limited to 60 requests a minute. A magic verification link is emailed
separately (it is not in the response; `verify` is just a note). Click it and
the same key is upgraded to the free tier of 50,000 calls a month.

No email? `POST /v1/keys` again with the same address; the verification link
upgrades every provisional key issued to that email, so re-issuing is safe.
Unverified keys stop working after 72 hours; just issue a new one.

## 2. Route a truck

Our routing API takes coordinates as `lon,lat;lon,lat`, with truck dimensions
and the tunnel code as query parameters. Several profiles are exposed on this
endpoint: `truck`, `driving` (aliases `car`/`auto`), `bus`, `bicycle`
(`bike`/`cycling`), `walking` (`foot`/`pedestrian`), `scooter` and
`motorcycle` (`motorbike`), so swap `truck` for `driving` for a standard car
route, or any of the others. The truck parameters below require the `truck`
profile (they `400` on any other profile).

The tunnel code is from ADR (the European agreement on carriage of dangerous
goods by road; tunnel codes B–E restrict which tunnels a hazmat load may use);
the full tunnel-code table is on the [conventions page](/docs/conventions).
Setting `tunnel_code` implies `hazmat=true`. Slashed codes like `B/D` must be
URL-encoded, which `--data-urlencode` handles below.

| Parameter | Required | Default | Meaning |
| --- | --- | --- | --- |
| `{profile}` (path) | yes | n/a | `truck`, `driving`/`car`, `bus`, `bicycle`, `walking`, `scooter` or `motorcycle` |
| `{coordinates}` (path) | yes | n/a | `lon,lat` pairs separated by `;` |
| `height` | no | EU 96/53/EC artic | Vehicle height in metres (truck only) |
| `width` | no | EU 96/53/EC artic | Vehicle width in metres (truck only) |
| `length` | no | EU 96/53/EC artic | Vehicle length in metres (truck only) |
| `weight` | no | EU 96/53/EC artic | Gross weight in tonnes (truck only) |
| `hazmat` | no | `false` (`true` if `tunnel_code` set) | Carrying dangerous goods (truck only) |
| `tunnel_code` | no | none | ADR 8.6.4 tunnel restriction code, e.g. `D` or `B/D` (truck only) |
| `steps` | no | `false` | Include turn-by-turn steps |
| `geometries` | no | `polyline` | `polyline`, `polyline6` or `geojson` |
| `overview` | no | `simplified` | `full`, `simplified` or `false` |
| `alternatives` | no | `false` | `true`, `false` or a number of alternates |
| `avoid_tolls` | no | `false` | Avoid toll roads (motorised profiles only) |
| `avoid_motorways` | no | `false` | Avoid motorways/highways (motorised profiles only) |
| `avoid_ferries` | no | `false` | Avoid ferries (all profiles) |
| `shortest` | no | `false` | Optimise for distance over time (all profiles) |

The four route options are honoured by the hosted gateway only; the keyless
demo router ignores them. `avoid_tolls`/`avoid_motorways` on a non-motorised
profile (`bicycle`/`walking`) return `InvalidValue`.

Dover to Birmingham, 44 t artic, 4.0 m high, ADR tunnel restriction code D:

```sh
curl -fsS -G "$BASE/route/v1/truck/1.3134,51.1279;-1.8904,52.4862" \
  -H "Authorization: Bearer $API_KEY" \
  --data-urlencode "overview=full" \
  --data-urlencode "height=4.0" \
  --data-urlencode "width=2.55" \
  --data-urlencode "weight=44.0" \
  --data-urlencode "hazmat=true" \
  --data-urlencode "tunnel_code=D"
```

Response (`200 OK`, truncated):

```json
{
  "code": "Ok",
  "routes": [
    {
      "distance": 362514.3,
      "duration": 16043.9,
      "geometry": "u{~vHmgg@…",
      "weight": 16043.9,
      "weight_name": "duration",
      "legs": [
        {
          "distance": 362514.3,
          "duration": 16043.9,
          "summary": "M25, M40"
        }
      ]
    }
  ],
  "waypoints": [
    { "name": "A20", "location": [1.3134, 51.1279] },
    { "name": "", "location": [-1.8904, 52.4862] }
  ]
}
```

OSRM-compatible: distances are metres, durations are seconds, geometry is an
encoded polyline (`geometries=geojson` for GeoJSON), so common routing clients
work unchanged. Prefer a richer JSON body? `POST /route` takes a native routing
request plus a top-level `adr` extension. See the
[API reference](/docs/api-reference). Coverage is territory-based; see
[territories](/docs/territories) for what is loaded where.

## 3. Check your key

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

Fresh from steps 1–2, before clicking the verification link, you hold a
provisional 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,
  "download_allowance_mib": 8192,
  "download_used_mib": 0,
  "mau_this_month": 0,
  "mau_included": 1000,
  "mau_overdrawn": false
}
```

After you click the emailed link, `state` flips to `"verified"`,
`monthly_quota` becomes 50,000 and `expires_at` disappears. Polling this
endpoint is quota-free, so agents can watch for the upgrade.

Beyond the free quota, calls draw prepaid credit at the two-speed rate:
standard routing and data from 0.05p/call, truck and ADR compliance from
1p/call; the class is detected per request (see [/pricing.json](/pricing.json)).
A truck/ADR call draws 20 included calls from the free tier, matching the
price ratio. Top up from [/account](/account). No credit means no overage:
requests stop with `429` rather than billing you.

## If something goes wrong

The routing endpoint answers errors in the OSRM envelope
(`{"code": …, "message": …}`) because OSRM clients dispatch on `code`;
everything else uses RFC 9457 `application/problem+json`. The first failures
a new key hits:

| Status | `code` / problem | Cause and fix |
| --- | --- | --- |
| `400` | `InvalidQuery` | Malformed coordinates; check `lon,lat;lon,lat` order and that you sent at least two pairs |
| `400` | `InvalidValue` | Unsupported profile (see the profile list above), bad `tunnel_code`, or truck parameters on a non-`truck` profile |
| `400` | `NoSegment` / `NoRoute` | Coordinates could not snap to a road / no legal path exists for the vehicle |
| `401` | `unauthorized` | Missing, unknown or expired key; check the `Authorization: Bearer` header |
| `429` | `rate-limited` / `quota-exceeded` | Over 60 requests/min, or free quota exhausted with no credit |

For example, a wrong profile:

```json
{ "code": "InvalidValue", "message": "unsupported profile \"hovercraft\": expected one of driving/car, truck, bus, bicycle/bike, walking/foot/pedestrian, scooter, motorcycle" }
```

And a bad key:

```json
{
  "type": "urn:sn-gateway:problem:unauthorized",
  "title": "Unauthorised",
  "status": 401,
  "detail": "unknown API key"
}
```

The full error envelope, including when you see `402` versus `429`, is on the
[conventions page](/docs/conventions).

## Attribution

Routing derives from OpenStreetMap data. Anything you render or republish must
credit **"© OpenStreetMap contributors"** with a link to
[openstreetmap.org/copyright](https://www.openstreetmap.org/copyright).

## Next steps

- [API reference](/docs/api-reference): every endpoint, parameter and response shape
- [Conventions](/docs/conventions): base URL, auth, units, error envelope, ADR tunnel codes
- [SDKs](/docs/sdks): web, Android and iOS wrappers around these calls
- [Self-host](/docs/self-host): run the whole stack on your own hardware
