Skip to content

Isochrones and reachability

POST /v1/isochrone answers “where can this train get from here within 2 hours (or 150 km)?”. It follows the routing rules of POST /v1/route for the vehicle (electrification, axle load, gauging, gauge, train protection, maximum speed, reversals, avoided lines and areas), so a place counts as reached at the distance and time of the route POST /v1/route would take there. It needs a key with the route scope.

Terminal window
curl -X POST -H "Authorization: Bearer $RAIL_API_KEY" -H "Content-Type: application/json" \
https://api.routing.gleisklar.de/v1/isochrone -d '{
"origin": { "station": "AH" },
"profile": "freight-electric-de",
"max_minutes": 180,
"buckets": [60, 120, 180]
}'
FieldWhat
originStart: a place as in POST /v1/route ({"station": code}, {"lat", "lon"} or {"osm_node"})
max_kmDistance limit, at most 1,000
max_minutesTime limit, at most 720
bucketsUpper band edges in bucket_unit, ascending, at most 10; the last one is the outer limit. Without: one band up to the limit
bucket_unitminutes or km (default: minutes if max_minutes is set, else km)
polygonsAlso return areas around the reached network (default false)
max_stationsCap on the station list (default 500, at most 5,000)
profile, vehicle, avoid, reversal_min, no_reversalAs in POST /v1/route

At least one of max_km, max_minutes or buckets is needed. With both limits, a place must be within both.

Times are the routing time, as in the distance matrix: running at the line speed capped at the vehicle’s maximum speed, plus reversal_min per reversal, with service track counted three times. Unlike the route’s running time estimate, they leave out acceleration and braking (the search needs times that add up edge by edge), so they are somewhat optimistic, most of all for heavy trains and short distances.

{
"origin": { "name": "Hamburg Hbf", "kind": "station", "ds100": "AH", "snapped": { … }, … },
"bucket_unit": "minutes", "buckets": [60, 120, 180], "max_minutes": 180,
"algorithm": "dijkstra",
"network": {
"type": "FeatureCollection",
"features": [
{ "type": "Feature",
"properties": { "bucket": 60, "from": 0, "unit": "minutes", "track_km": 412.7 },
"geometry": { "type": "MultiLineString", "coordinates": [ … ] } },
…
]
},
"stations": [
{ "name": "Lüneburg", "kind": "station", "ds100": "ALBG", "lat": 53.2497, "lon": 10.4199,
"distance_m": 49870, "duration_s": 1920, "bucket": 60 },
…
],
"stations_truncated": false,
"profile": "freight-electric-de", "vehicle": { … },
"data_version": "20261104-0200", "warnings": []
}

(Illustrative values.)

  • network is the meaningful output for rail: one MultiLineString per bucket, the track reached in that band (from the previous bucket’s edge, from, up to bucket). The last stretch of each line is cut where the limit is reached. Lines are simplified to about 10 m (more, with a warning, beyond 100,000 coordinates).
  • stations lists the stations and RINF operational points within 300 m of the track reached, nearest first in the bucket unit, one per name, with the route’s distance_m and duration_s and the bucket they fall in.
  • polygons (with "polygons": true): per bucket a polygon around everything reached up to that bucket (cumulative, about 2 km on each side of the track, outlined on a grid). It is a rough approximation for maps: trains don’t reach the space between lines, so prefer the network.
  • algorithm says which search answered: dijkstra for time limits up to 3 hours, phast (one-to-all over the whole network) beyond and for distance limits alone. Both are exact.

An isochrone counts as one request per bucket.

The dashboard’s playground has an isochrone mode: click a start on the map, pick a vehicle and a limit, and see the banded network and the stations reached.