Documentation menu
Migrating from NextBillion.ai
A port from NextBillion is a rewrite of the call layer, not a URL swap. Their Directions, Distance Matrix, Navigation and Isochrone APIs are a proprietary family with their own request and response shapes, so every endpoint below needs client changes. What you gain in exchange is an ADR dangerous-goods model, EV journey planning, a self-host licence with a published price, and an agent surface you can call without a key.
Be straight about the shape. MapMap's routing is
OSRM-compatible on the URL endpoint and
Valhalla-shaped on POST /route. NextBillion's is neither. Their Fast and
Flexible variants share one envelope (status, routes[], legs[],
steps[], with latitude/longitude objects and distance/duration as
{value} wrappers) and take named origin/destination query parameters.
A handful of their parameter names are borrowed from OSRM spelling
(overview, approaches, bearings, alternatives, geometry=polyline6),
but the envelope is not OSRM's and there is no costing or costing_options
anywhere in it. Anyone who tells you the Flexible API is Valhalla-shaped has
not read the specification. Checked against their own OpenAPI document on
3 September 2026.
Key swap
NextBillion keys are issued after a business account is set up with them. MapMap keys are issued by one unauthenticated call, card-free:
curl -fsS -X POST "https://api.mapmap.ai/v1/keys" \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "accept_tos": true}'
Their key travels as a key= query parameter on every request. Ours goes in
Authorization: Bearer snk_… (preferred), or ?api_key=snk_… for URL-only
contexts such as style and tile URLs. Verify the email and the free tier is
50,000 calls a month, commercial use allowed.
Note the host difference while you are porting: their documentation is on
docs.nextbillion.ai and their API is on api.nextbillion.io.
Endpoint mapping
| NextBillion | MapMap | Notes |
|---|---|---|
GET /directions/json (Fast) | GET /route/v1/{profile}/{coords} or POST /route | Coordinates move from origin=/destination= query parameters to a path of lon,lat;lon,lat (OSRM endpoint) or a locations[] array of {lat, lon} (native). Watch the order: theirs is lat,lng. |
GET /directions/json?option=flexible | POST /route | The native endpoint is where truck, ADR and route options live. See the parameter table below. |
GET /distancematrix/json | POST /matrix | Their origins/destinations become sources/targets arrays of {lat, lon}. Response is durations (seconds) and distances (metres), row-major, with null for unreachable pairs. Up to 10,000 elements per request. |
POST /mdm/create and GET /mdm/status (async matrix) | POST /matrix, or POST /v1/jobs/matrix + GET /v1/jobs/{id} | Two ways across. Up to 10,000 elements the matrix answers synchronously and the polling pair disappears; above that the asynchronous lane is the same submit-and-poll shape you already have, at 40,000 elements, with an optional signed webhook so you can stop polling altogether. |
POST /optimization/v2 and GET /optimization/v2/result | POST /optimise, or POST /v1/jobs/optimise + GET /v1/jobs/{id} | Same choice. Up to 200 unique locations it is one synchronous call and the result-polling disappears; up to 2,000 the asynchronous lane keeps the job-id shape and adds a signed webhook. Truck and ADR constraints shape the plan either way, polling costs no quota, and a failed job refunds what its submission was charged. Limits are published: 200 or 2,000 unique locations, 1,500 km matrix span. See optimisation. |
GET /snapToRoads/json | POST /trace_route, POST /trace_attributes | Their path becomes shape (an array of {lat, lon}) or encoded_polyline. timestamps and radiuses have no direct equivalent; shape_match (edge_walk, map_snap, walk_or_snap) selects the snapping behaviour instead. |
POST /route-reconstruction, POST /postTripRoute | POST /route/report | Distance and duration broken down by road class, admin area, toll, bridge, tunnel and surface, over an existing route or trace. |
GET /isochrone/json | POST /isochrone | contours_minutes and contours_meters become one contours array whose entries carry a time in minutes or a distance in kilometres. polygons, denoise and generalize port by name. Ten contours per request against their four. |
GET /geocode | GET /geocode | Their q becomes query, and at becomes focus. The response shape differs: ours returns candidates with name, label, lat/lon, type and address parts, not their HERE-style items[] with position{lat,lng}. This one always needs client changes. |
GET /revgeocode | GET /geocode/reverse | Their at=lat,lng becomes lat and lon parameters. |
GET /navigation/json | GET /route/v1/{profile}/{coords}?steps=true | Add voice_instructions=true and banner_instructions=true for Mapbox-shaped spoken prompts and banners, including lane diagrams where OSM carries turn:lanes. |
GET /incidents | POST /v1/incidents/along | Incidents and closures along a route shape, with per-source coverage metadata. Coverage differs by deployment; 501 where none is configured. |
POST /hos/trip-plan | POST /optimise | Driver hours are expressed as vehicle time windows, breaks and shift limits inside the optimisation problem rather than as a separate endpoint. See driver hours. |
/places/autosuggest, /places/autocomplete | GET /geocode/suggest, GET /geocode/retrieve | Search-as-you-type: a compact suggestion list per keystroke, then the full feature for the row the user picked. |
/optimization/driver-assignment/v1, /clustering | No direct equivalent | Model the assignment as a VRP over POST /optimise, or run your own clustering over POST /matrix output. |
Parameter compatibility
Every mapped parameter below was checked as existing on both sides. Anything that exists on only one side is in the section after it.
| Concept | NextBillion | MapMap | Watch out |
|---|---|---|---|
| Vehicle profile | mode = car, truck, motorcycle, bike, walk | costing = auto, truck, motorcycle, bicycle, pedestrian (plus bus, motor_scooter) | bike becomes bicycle, walk becomes pedestrian. Fast-variant callers only ever had car and truck. |
| Truck height, width, length | truck_size = height,width,length in centimetres | height, width, length in metres | Divide by 100. Theirs is one packed string, ours is three fields. |
| Truck weight | truck_weight in kilograms | weight in tonnes | Divide by 1,000. Their own docs are inconsistent here: weight is kg while truck_axle_load is tonnes. |
| Axle load | truck_axle_load in tonnes | costing_options.truck.axle_load in tonnes | Same unit, so this one ports directly. |
| Avoidances | avoid = toll, ferry, highway, … | avoid_tolls, avoid_ferries, avoid_motorways booleans | Their pipe-separated list becomes separate booleans. avoid_tolls and avoid_motorways are motorised profiles only. |
| Shortest versus fastest | route_type = fastest, shortest | shortest boolean | Default on both is fastest. |
| Alternatives | alternatives, altcount | alternatives = true/false or a number, max 3 | One field instead of two. |
| Geometry encoding | geometry = polyline, polyline6, geojson | geometries = polyline, polyline6, geojson on the OSRM endpoint | Same three values under a pluralised name. Their Flexible variant drops geojson, so a Flexible caller gets it back here. |
| Time-dependent routing | departure_time, a UNIX timestamp in seconds | date_time, an object of {type, value} such as {"type": 0, "value": "2026-08-13T09:20"} | Both cost against typical conditions at the given time, but the encoding differs: a local ISO-8601 string with a type discriminator, not an epoch. |
| Step-by-step legs | steps (Fast only) | steps=true | Their Flexible variant has no steps at all, so a Flexible caller gains this in the move. |
Two of their parameters have no documented MapMap equivalent and are not
in the table above because the table is a parity list: approaches
(unrestricted or curb) and bearings. Both are OSRM-named on their side,
but neither appears in the MapMap API reference, so treat curbside approach
and start-bearing constraints as capability you are giving up rather than
remapping.
What ports with client changes
Everything. There is no drop-in path here, and it would be dishonest to suggest one. Budget for:
- Coordinate order and encoding. Theirs is
lat,lngin a query string; ours is{lat, lon}objects in JSON, or barelon,latpairs on the OSRM-compatible URL endpoint. That last one has caught everybody at least once. - Unit conversions. Centimetres to metres, kilograms to tonnes, and their
isochrone
contours_metersto ourdistancein kilometres. - Response parsing. Their
routes[].legs[].distance{value}becomes a plaindistance_m; theirstatus/msgenvelope becomes HTTP status plus a problem+json body. - Deciding what to do with the polling pairs. Below the synchronous caps
(10,000 matrix elements, 200 optimisation locations) both collapse to one
call and the job-id plumbing comes out. Above them, keep it:
/v1/jobs/…is the same submit-and-poll shape, and the polling half is quota-free.
What MapMap adds
- ADR dangerous goods, modelled properly. Their
hazmat_typeis a flat nine-value filter (explosives,gas,flammable_liquid,flammable_gas,organic,toxic,radioactive,corrosive,other) that avoids unsuitable roads, and their specification contains no ADR tunnel category, no tunnel-restriction code and no placard concept. Tunnels are all or nothing throughavoid=tunnel. MapMap takes atunnel_codeof B to E withhazmaton the truck profile and enforces ADR 8.6.4 in costing, returnsapplied_adrsaying what was enforced, and answers the pure tunnel-entry question throughPOST /adr/checkwith no routing at all. Read the limits on that page honestly before you rely on it: it reflects what the map and the ADR matrix record, and it certifies nothing. - EV journey planning.
POST /v1/ev/planworks out the charge stops: physics consumption over the route's own legs, charge times integrated over the vehicle's charging curve rather than energy divided by peak power, and a reserve floor the state of charge never breaches. When no plan exists it saysfeasible: falsewith the cause and the furthest reachable point.POST /v1/charging/alongranks charge points along a route by power with their real engine-computed detour. NextBillion's published API carries no EV endpoint or parameter. - Self-hosting with a published price. The whole stack, gateway, routing
engine, geocoder and MCP server, from one Docker Compose file, with licence
anchors on the pricing page and in
/pricing.json. Their on-premises deployment is offered "exclusively under our Enterprise pricing plan" and quoted on request. - Offline territories. ed25519-signed territory packages that verify with no network, do not expire, and update differentially. On-device routing, search and turn-by-turn against the local package.
- An agent surface. A hosted MCP server with 39 tools at
https://mcp.mapmap.ai/mcp, connectable with no key at all under fair use, plus/llms.txt,/llms-full.txt,/openapi.json,/pricing.json, one-call keys and x402 machine payments. - Measured clearance.
POST /v1/clearance/alongjudges a vehicle against surveyed point-cloud geometry rather than map tags, where a survey exists.
What has no replacement
Say this out loud before you plan the migration, because it is the part that decides whether you can move at all.
- Asset tracking, live tracking and geofencing. NextBillion ships a tracking platform (their Skynet asset APIs, device battery and location telemetry, geofence entry and exit events). MapMap has no equivalent and is not trying to build one. If that platform is load-bearing for you, keep it or replace it with a telematics vendor: Samsara, Motive, Webfleet, Verizon Connect, Geotab or Teltonika-based integrators all sell this as their core product, and most take routing from an API like ours. MapMap routes and complies; it does not track your fleet.
- Their per-customer map editing. Private-road and custom-restriction overlays are not a hosted self-service product here today. Custom territory builds are a self-host and Sovereign tier conversation.
- Static map images from the routing platform. There is a
static map endpoint on the website,
not on the gateway, and it is not a like-for-like replacement for their
static_map_imagetooling. - Hosted worldwide coverage on day one. Hosted coverage is
territory-based; check
GET /territories. Self-host covers anywhere you build. - Hours-of-service as a standalone endpoint. The capability exists inside
POST /optimiseas shifts, breaks and time windows, but a client callingPOST /hos/trip-plandirectly is rewriting, not remapping.
Billing differences to encode
Their pricing is quoted per order, per asset or per API call under an annual
commitment. Ours is published and prepaid: two price classes detected per
request, Standard (car, bicycle and pedestrian routing, matrix, isochrone,
matching, geocoding) and Premium (anything truck or ADR, drawing 20 included
calls from the free tier). No credit means a 402 or 429, never surprise
billing, and a request answered 4xx is never charged. Machine-readable at
https://mapmap.ai/pricing.json.
Attribution
MapMap requires "© OpenStreetMap contributors"; compiled styles carry it structurally. See licensing.
Full API reference: /docs/api-reference (append .md
for raw markdown). Units, errors and quotas:
conventions. A side-by-side on commercial terms:
NextBillion.ai alternative.