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

news / isochrones · raw .md
Routing6 min readMapMap engineering
Concentric reachability rings spreading unevenly from one origin, stretched by the road network into lobes rather than circles.

Truck isochrones, billed one call per contour

POST /isochrone returns reachability contours: the area a vehicle can get to from an origin inside a time or distance budget, as GeoJSON you can drop straight onto a map. Send "costing": "truck" and the same height, width, length and weight limits that shape a truck route shape the contour, so a 4-metre-high box van's 30-minute area stops at the low bridge instead of running through it. The limits are enforced inside the costing model rather than filtered off the result afterwards, so the polygon is an area the vehicle can actually reach. Billing is one call per contour, capped at 10 contours per request: 0.05p per contour on standard costing, 1p per contour when the body carries truck costing.

What does POST /isochrone actually return?

A GeoJSON FeatureCollection with one feature per contour, returned from the routing engine. Each feature's properties carry the contour value in the unit you asked for and a metric of "time" or "distance".

Here is a real request. Where can a 4-metre-high, 40-tonne truck get to from a London depot in 10 and 20 minutes:

sh
export BASE=https://api.mapmap.ai
export API_KEY=snk_...

curl -fsS -X POST "$BASE/isochrone" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "locations": [{ "lat": 51.5074, "lon": -0.1278 }],
  "costing": "truck",
  "contours": [{ "time": 10 }, { "time": 20 }],
  "polygons": true,
  "costing_options": { "truck": { "height": 4.0, "weight": 40.0 } }
}'

And the response shape, truncated to one feature:

json
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": { "contour": 10.0, "metric": "time" },
      "geometry": {
        "type": "Polygon",
        "coordinates": [[[-0.14, 51.50], [-0.11, 51.50], [-0.11, 51.52], [-0.14, 51.50]]]
      }
    }
  ]
}

GeoJSON geometry is [lon, lat]. That is the GeoJSON standard, not our choice. Note that request locations are {lat, lon} objects with named keys, so there is no coordinate-order ambiguity on the way in.

The parameters worth knowing:

FieldRequiredWhat it does
locationsyesOrigins the reachability is computed from.
costingyesauto, truck, bus, motor_scooter, motorcycle, bicycle or pedestrian.
contoursyesEach is a time in minutes or a distance in kilometres. A contour carrying neither is a 400.
polygonsnoReturn polygons instead of the default linestrings.
denoiseno0 to 1. Higher drops smaller contour islands.
generalizenoGeometry simplification tolerance in metres.
show_locationsnoInclude the input locations as GeoJSON points.
costing_optionsnoPassed to the engine verbatim, keyed by costing name.

What do fleets actually use reachability polygons for?

Depot siting, service-area definition and driver-hours planning. None of the three is drawing a pretty blob on a map.

  • Depot siting. You have a candidate site and a list of customers. The question is not "how far is it" but "how many of these can a 40-tonne artic reach inside a 45-minute window". Run the contour from each candidate, count the customers inside, compare. Straight-line radius answers a different question and answers it wrongly, because the truck drives roads, not circles.
  • Service-area definition. "Can we serve this postcode in under 45 minutes" is a contract question, and a sales team asking it 200 times a day wants a polygon they can test a point against rather than 200 route calls. One isochrone, cached, does the work of a lot of routing.
  • Driver-hours planning. A driver has a legal driving window left. The contour is the honest answer to what is still reachable inside it, computed against the roads the vehicle can legally use.

For the many-to-many version of the depot question, where you want the actual travel time from each of 12 depots to each of 40 stops rather than an area, use POST /matrix instead. We wrote that up in the matrix API and how it bills by element. The rule of thumb: an isochrone answers "what is in range", a matrix answers "how far is each of these, exactly".

Why is a truck isochrone a different shape from a car isochrone?

Because costing_options reaches the engine verbatim, so the truck cost model that gates a route gates the contour too. A low bridge, a weight-limited lane and a width restriction are edges the search cannot traverse under truck costing, and an area computed from a search that cannot traverse them is therefore an area the truck can actually reach.

json
{
  "truck": {
    "height": 4.0, "width": 2.55, "length": 16.5,
    "weight": 40.0, "axle_load": 9.0, "axle_count": 5,
    "hazmat": true, "adr_tunnel_code": "C"
  }
}

Dimensions in metres, weights in tonnes. adr_tunnel_code is honoured by our ADR-extended engine, so a hazmat contour can be tightened by the tunnels the load may not enter. A stock engine ignores unknown keys, which is why the request stays portable.

Be careful with what adr_tunnel_code in costing_options.truck does and does not promise. The isochrone is shaped by ADR costing where the engine supports it, but the isochrone is not a compliance product and we would rather say so here than let you find out later. POST /adr/check is the authoritative tunnel-entry decision, and it is the one to log. Do not build a dangerous-goods compliance step on top of a polygon.

What does an isochrone cost?

One call per contour, and the class is decided from the body.

RequestUnitsClassCost
1 contour, "costing": "auto"1Standard0.05p
3 contours, "costing": "auto"3Standard0.15p
3 contours, "costing": "truck"3Premium3p
10 contours, "costing": "truck"10Premium10p
11 contoursrejectedn/a400, nothing billed

Standard is 0.05p per call up to 1M calls a month, 0.03p to 10M, 0.02p beyond. Premium is 1p, 0.7p and 0.4p across the same bands. Bands are marginal, so each price applies only to the calls inside it.

The free tier is denominated in standard calls: 50,000 a month after email verification, and a premium call draws 20 of them. A 3-contour truck isochrone therefore draws 60 included calls, which is worth knowing before you put one behind a page load. Prices reconcile with /pricing.json, which wins if this page ever drifts.

What this does not do

Five real limits, in writing.

  • A top-level adr object is ignored here, and still bills premium. The adr extension is honoured on POST /route, POST /route/along and POST /optimise only. The isochrone request has no such field, so it is dropped silently by the handler, while the billing classifier sees it and charges premium. You pay 1p a contour for something that had no effect. Put truck and ADR settings in costing_options.truck instead, which is the path that actually reaches the engine.
  • 10 contours is a hard cap. An 11th contour is a 400 and the request is not billed. Split it.
  • GraphHopper deployments are more limited. On a self-hosted deployment running SN_ROUTING_ENGINE=graphhopper, isochrones are single-origin, cannot mix time and distance contours in one call, and match your contours exactly only when they are evenly spaced. Valhalla, the default, has none of these limits.
  • The MCP isochrone tool is narrower than the endpoint. reachable_area on our MCP server computes time contours from a single origin, in minutes only, with no costing_options. For distance contours, multiple origins or truck dimensions, an agent has to call the HTTP endpoint directly.
  • A contour is a model, not a promise. It is computed from the road network and the costing model, and it does not know that your yard gate is locked at 18:00 or that the customer needs a 20-minute unload. Reachability is not serviceability.

Try it

The full parameter table, the error envelope and the sibling endpoints are in the analysis APIs documentation, which is authoritative on request and response shapes. A key comes from one card-free call to POST /v1/keys and works immediately, and the playground runs the request in a browser with no install.

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