Isochrone endpoint
Compute a travel-time area from a coordinate. Answers “everywhere you can reach within N minutes” by driving, walking, cycling, or transit.
Computed live from the routing engine's reachable-node set. Measured 422 ms for the 5, 10 and 20 minute driving areas of Brussels in a single call on 24 September 2026, and 1.3 s for a 20 minute transit area in Vienna.
Request
| Name | In | Type | Description |
|---|---|---|---|
| travelMode required | query | string or int |
Either the name or the number, they are interchangeable: Driving or 1, Walking or 2, Bicycling or 3, Transit or 4. Both spellings return byte-identical responses.
|
| latitude required | query | double | Origin latitude. |
| longitude required | query | double | Origin longitude. |
| numberOfSeconds required | query | int |
Travel-time limit in seconds. Standard values: 300 (5 min), 600 (10 min), 1200 (20 min). Longer horizons are supported: 1800, 2700 and 3600 all answer, and cost grows with the area covered rather than with a cliff.
|
Response
The body is a bare GeoJSON geometry, not a Feature and not a
FeatureCollection. There is no features array to index into.
Driving,WalkingandBicyclingreturn aPolygon.Transitreturns aMultiPolygonwhenever the area reachable by public transport falls into disconnected pieces around the stops you can get to. A 15 minute transit area from the Grand-Place in Brussels returned 2 pieces on 24 September 2026.
Handle both types. Code that assumes a Polygon will break on the first transit
call. Pieces and holes too small to draw are removed before the response is sent, so every
piece you receive has a real area and you can hand the geometry straight to a containment test.
The shape of the response, not an executable response:
{
"type": "Polygon",
"coordinates": [
[ [lon, lat], [lon, lat], [lon, lat], [lon, lat] ]
]
}
Each ring is a list of [longitude, latitude] positions, in that order, whose first
and last positions are identical: at least four positions per ring, as
RFC 7946
requires. Complete, valid responses for the Grand-Place example:
walking, Polygon
and public transport, MultiPolygon.
Examples
curl -H 'LicenseKey: YOUR_KEY' \
'https://be.yatmo.com/isochrone?travelMode=Walking&latitude=50.846714&longitude=4.352514&numberOfSeconds=900'
const url = 'https://be.yatmo.com/isochrone'
+ '?travelMode=Walking&latitude=50.846714&longitude=4.352514&numberOfSeconds=900';
const res = await fetch(url, { headers: { LicenseKey: 'YOUR_KEY' } });
const geometry = await res.json();
// Polygon and MultiPolygon nest their rings differently, so normalise once
// and the rest of your code stops caring which mode was requested.
const polygons = geometry.type === 'MultiPolygon'
? geometry.coordinates
: [geometry.coordinates];
const ringCount = polygons.length;
const outerRing = polygons[0][0]; // [[lon, lat], [lon, lat], ...]
// Ready to hand to MapLibre, Leaflet or turf as a GeoJSON geometry:
map.getSource('reachable').setData(geometry);
$qs = http_build_query([
'travelMode' => 'Walking',
'latitude' => 50.846714,
'longitude' => 4.352514,
'numberOfSeconds' => 900,
]);
$ch = curl_init("https://be.yatmo.com/isochrone?$qs");
curl_setopt($ch, CURLOPT_HTTPHEADER, ['LicenseKey: YOUR_KEY']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$geometry = json_decode(curl_exec($ch), true);
curl_close($ch);
$polygons = $geometry['type'] === 'MultiPolygon'
? $geometry['coordinates']
: [$geometry['coordinates']];
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("LicenseKey", "YOUR_KEY");
var qs = "travelMode=Walking&latitude=50.846714&longitude=4.352514&numberOfSeconds=900";
var json = await http.GetStringAsync($"https://be.yatmo.com/isochrone?{qs}");
using var doc = JsonDocument.Parse(json);
var type = doc.RootElement.GetProperty("type").GetString(); // Polygon or MultiPolygon
Variants
GET /isochrone: the standard endpoint above. Returns one geometry.GET /isochrone/TravelTime: same parameters, same response shape. It used to be a separate, faster computation path; since 24 September 2026 both routes run the same computation and return identical responses. Kept because existing integrations call it.GET /isochrone/GetMultipleTimes: returns the 5, 10 and 20 minute areas in one call. It takeslanguageinstead ofnumberOfSeconds, and its response is a JSON array, not a geometry.
GET /isochrone/GetMultipleTimes?travelMode=Walking&latitude=50.846714&longitude=4.352514&language=EN
[
{ "label": "5 min", "iso": { "type": "Polygon", "coordinates": [ ... ] } },
{ "label": "10 min", "iso": { "type": "Polygon", "coordinates": [ ... ] } },
{ "label": "20 min", "iso": { "type": "Polygon", "coordinates": [ ... ] } }
]
The label is already localised for the language you asked for, so it
can be shown as is. Each iso follows the same rules as the single geometry above.
Notes
- The area is computed outwards from the origin. It answers “where can I get to from here”. It does not answer “who can get to here”, which is a different computation: travel times are not symmetric, because one-way streets, timetables and turn restrictions are not.
- Long horizons are fine. A 60 minute driving area for London answered in 2.8 seconds and 19 KB on 24 September 2026. Ask for the horizon your users need.
- Shorter areas nest inside longer ones. Within one
GetMultipleTimescall, the 5 minute area is contained in the 10 minute area, which is contained in the 20 minute area, so rings drawn on top of each other never cross. - The outline is smoothed on purpose. It is built to be drawn and to be tested against, not to be exact to the metre: expect a few hundred vertices rather than several thousand, rounded corners rather than a staircase, and a tolerance of one to two street widths at the edge. In sparsely built areas the outline is tighter than it used to be, because it now follows the reachable network instead of spanning the gaps between distant roads.
- Transit availability varies by country.
Transitneeds GTFS data; some countries have full coverage, others only their major cities.