Documentation menu
Quickstart
From nothing to a dimensioned truck route in two calls. No install needed to try it: the playground runs the same requests from your browser.
Status, honestly: the hosted gateway at https://api.mapmap.ai is live:
sign up for a key, or run the self-host distro;
every call below works identically against your own deployment.
Base URL, auth and conventions are defined in full on the
conventions page.
Set up your shell once so every snippet on this page is copy-pasteable:
export BASE=https://api.mapmap.ai # or your self-hosted gateway origin
1. Issue a key, one call, card-free
curl -fsS -X POST "$BASE/v1/keys" \
-H "Content-Type: application/json" \
-d '{"email": "you@example.co.uk", "accept_tos": true}'
Response (201 Created):
{
"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:
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.
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:
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):
{
"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. Coverage is territory-based; see
territories for what is loaded where.
3. Check your key
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:
{
"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).
A truck/ADR call draws 20 included calls from the free tier, matching the
price ratio. Top up from /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:
{ "code": "InvalidValue", "message": "unsupported profile \"hovercraft\": expected one of driving/car, truck, bus, bicycle/bike, walking/foot/pedestrian, scooter, motorcycle" }
And a bad key:
{
"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.
Attribution
Routing derives from OpenStreetMap data. Anything you render or republish must credit "© OpenStreetMap contributors" with a link to openstreetmap.org/copyright.
Next steps
- API reference: every endpoint, parameter and response shape
- Conventions: base URL, auth, units, error envelope, ADR tunnel codes
- SDKs: web, Android and iOS wrappers around these calls
- Self-host: run the whole stack on your own hardware