River route
Barge route over inland waterways with mode=RIVER, plus road to and from the river port when the points are off the water. The example is Rotterdam to Basel up the Rhine on 2026-10-17: 825.8 km, 17 locks, almost all upstream, with the Rhine low water note for October. A road chain comes back as the alternative.
Query parameters
Any form from the Locations table. UN/LOCODEs of river ports resolve to the river port.
Any form from the Locations table.
RIVER (or INLAND, INLAND_WATERWAY, IWW, BARGE). Road is added for the access legs.
Other feasible chains in alternatives[]. Default true for ROAD, RAIL, AIR and /multimodal.
Add terminal handling at each transfer: port 24 h, rail terminal 12 h, airport 12 h, river port 18 h. Default true.
Geometry per section as [lat, lng] pairs. Road sections also give ferry_paths as lines.
Departure date YYYY-MM-DD for the seasonal river rules. Default today (UTC). Only river legs depend on it.
false switches the seasonal river rules off: no closures, no slow-downs, no seasonal_notes. Default true.
Response schema
19 fields
Nested exactly as the JSON is. Open a branch to read its fields; hover a name for the full dot-path.
data
from / data
The resolved points: kind (port, airport, country, address, coordinates), name, locode or iata, country_code, lat, lng.
The modes you allowed.
route
Chain type: Sea, Rail, Air, Road, River (road, barge, road) or Sea + River (sea to a river-mouth gateway, then barge).
The modes the chain actually uses, in order.
summary
Total km and nm for the chain.
Total hours and days. duration.hours = moving_hours + handling_hours.
Relative cost in thousands of km-equivalents at SEA 1, RIVER 1.8, RAIL 3, ROAD 6, AIR 40 per km. For ranking, not a price.
sections[]
Legs in order: transport_mode, from, to, distance, duration, path. SEA legs add speed_knots, via, eca and passages. ROAD legs add driving_hours and ferry_paths. RIVER legs add the fields below.
RIVER: average speed over ground for this leg, current and locks included.
RIVER: km sailed with the current (downstream_km), against it (upstream_km) and on still water such as canals, lakes and tidal reaches (slack_water_km).
RIVER: lock sites passed. lock_hours is the time they add, already inside duration.
RIVER: named waterways on the leg, longest first, as name, km and class (CEMT class in Europe).
RIVER: seasonal rules that touch this leg on the requested date, with the km affected.
RIVER: credit line for the waterway data this leg was built from. Show it wherever you display the leg.
Each change of mode: at (port, rail terminal or airport), from_mode, to_mode, hours.
true when a road leg was estimated from straight-line distance because road routing was briefly unavailable.
Other feasible chains, same shape, in the order set by optimize.
Present when RIVER is allowed: the date the seasonal rules were applied for.
Seasonal river rules that changed the answer: id, kind (closure, ice_risk, low_water), note, typical_window, source, then time_factor for a slow-down or reopens_about for a closure, and effect: no_route (the river chain is gone), detour (it goes round the closed stretch) or slower.
Errors
A failure answers with an HTTP error status and { "error": { "code", "message" } }. Branch on the code, and log the message.
A parameter is missing or malformed: an unknown mode, speed_knots outside 3 to 40, an unknown passage in avoid, a pol/pod that is not a sea port, or a date that is not YYYY-MM-DD.
The location is well formed but we cannot place it: an unknown code, or an address the geocoder does not find.
No route joins the two points with the modes and passages you allowed, for example SEA only between two inland cities. When a seasonal river closure is the cause, the message names each closure, its typical window and the date it usually reopens.
Free-text address lookup is briefly down. Codes and coordinates keep working.
How river time is counted
| Part | Rule |
|---|---|
| Speed through water | 12.5 km/h on rivers, 10 km/h on canals. |
| Current | Signed per stretch: EURIS up and down speeds in Europe, elsewhere HydroRIVERS flow direction with a strength of 1 to 5 km/h by discharge, 35 % of that on dammed cascades, zero on canals, lakes and tidal reaches. |
| Operating factor | Moving time ×1.1. Speed over ground never below 3 km/h. |
| Locks | 2,746 lock sites on the graph. 0.75 h each, 1.25 h in North America (USACE LPMS). |
| Direction | The path is chosen on direction-neutral time; the hours reported are for your direction. Rotterdam to Basel is about 112 h upstream, Basel to Rotterdam about 76 h. |
| Handling | 18 h at each river port where the cargo changes mode (handling=false removes it). |
Sources and licences
The waterway graph is built from these datasets and refreshed at night from OpenStreetMap, with a check and rollback. Each RIVER section carries its own attribution line, and /health lists them under river.sources. Show the attribution when you display river legs.
| Dataset | Licence and attribution line |
|---|---|
| Europe: EURIS Inland Fairway Graph v0.2.1 (Zenodo 10.5281/zenodo.18313951) | CC BY 4.0. Fairway data: EURIS / European RIS authorities, graph by the EURIS fairway graph authors (CC BY 4.0) |
| USA: USACE / BTS NTAD National Waterway Network | US public domain. U.S. Army Corps of Engineers, Bureau of Transportation Statistics NTAD |
| Rest of world and locks: OpenStreetMap via Overpass | ODbL 1.0. (c) OpenStreetMap contributors, https://www.openstreetmap.org/copyright |
| Rest of world: HydroRIVERS v1.0, WWF HydroSHEDS | Free incl. commercial use, with attribution. HydroRIVERS, WWF HydroSHEDS, www.hydrosheds.org |
| Rest of world: Natural Earth 10m rivers | Public domain. Made with Natural Earth |
curl 'https://api.navo24.com/v1/distance/route?from=NLRTM&to=CHBSL&mode=RIVER&date=2026-10-17' \
-H "Authorization: Bearer tmcp_YOUR_API_KEY"const res = await fetch("https://api.navo24.com/v1/distance/route?from=NLRTM&to=CHBSL&mode=RIVER&date=2026-10-17", {
headers: {
"Authorization": "Bearer tmcp_YOUR_API_KEY"
}
});
const data = await res.json();import requests
res = requests.get(
"https://api.navo24.com/v1/distance/route?from=NLRTM&to=CHBSL&mode=RIVER&date=2026-10-17",
headers={"Authorization": "Bearer tmcp_YOUR_API_KEY"},
)
data = res.json() {
"data": {
"from": {
"kind": "port",
"locode": "NLRTM",
"name": "Rotterdam",
"country": "Netherlands",
"country_code": "NL",
"lat": 51.90438,
"lng": 4.44245
},
"to": {
"kind": "river_port",
"locode": "CHBSL",
"name": "Basel (Rheinhafen)",
"country_code": "CH",
"lat": 47.59,
"lng": 7.59
},
"transport_modes": [
"RIVER",
"ROAD"
],
"optimize": "cost",
"routing_mode": "short",
"avoided": [],
"route": {
"label": "River",
"transport_modes": [
"RIVER"
],
"summary": {
"distance": {
"km": 825.8,
"nm": 445.9,
"meters": 825800
},
"duration": {
"hours": 111.6,
"days": 4.65,
"seconds": 401760
},
"moving_hours": 111.6,
"handling_hours": 0,
"speed_kmh": 7.4,
"cost_index": 1.49
},
"sections": [
{
"transport_mode": "RIVER",
"distance": {
"km": 825.8,
"nm": 445.9,
"meters": 825764
},
"duration": {
"hours": 111.6,
"days": 4.65,
"seconds": 401721
},
"speed_kmh": 7.4,
"current": {
"downstream_km": 1.3,
"upstream_km": 783.5,
"slack_water_km": 41.0
},
"locks": 17,
"lock_hours": 12.8,
"waterways": [
{
"name": "Rhein",
"km": 503.0,
"class": "CEMT VIc"
},
{
"name": "Rhin",
"km": 181.1,
"class": "CEMT VIa"
},
{
"name": "Boven-Rijn, Waal, Boven-Merwede, Beneden-Merwede en Noord",
"km": 125.3,
"class": "CEMT VIc"
},
{
"name": "Nieuwe Maas, Nieuwe Waterweg en Maasmond",
"km": 13.5,
"class": "CEMT VIc"
},
{
"name": "Koningshaven",
"km": 1.9,
"class": "CEMT VIc"
},
{
"name": "IJsselhaven",
"km": 0.7,
"class": "CEMT Va"
}
],
"data_sources": [
"euris",
"link",
"osm_locks"
],
"attribution": "Fairway data: EURIS / European RIS authorities, graph by the EURIS fairway graph authors (CC BY 4.0); Locks (c) OpenStreetMap contributors, https://www.openstreetmap.org/copyright",
"estimated": false,
"seasonal": [
{
"id": "rhine_low",
"kind": "low_water",
"note": "Rhine low water season (Kaub gauge): part loads and low water surcharges",
"typical_window": "01 Aug - 31 Oct",
"source": "estimate: ELWIS / Kaub gauge, low water most years Aug - Oct (2018, 2022 severe)",
"time_factor": 1.15,
"km": 809.4
}
],
"from": {
"kind": "port",
"name": "Rotterdam",
"country_code": "NL",
"lat": 51.904383,
"lng": 4.442447,
"locode": "NLRTM"
},
"to": {
"kind": "river_port",
"name": "Basel (Rheinhafen)",
"country_code": "CH",
"lat": 47.59,
"lng": 7.59,
"locode": "CHBSL"
}
}
],
"transfers": [],
"estimated": false
},
"alternatives": [
{
"label": "Road",
"transport_modes": [
"ROAD"
],
"summary": {
"distance": {
"km": 752.2,
"nm": 406.2,
"meters": 752200
},
"duration": {
"hours": 7.8,
"days": 0.33,
"seconds": 28080
},
"moving_hours": 7.8,
"handling_hours": 0,
"speed_kmh": 96.44,
"cost_index": 4.51
},
"sections": [
{
"transport_mode": "ROAD",
"distance": {
"km": 752.2,
"nm": 406.1,
"meters": 752181
},
"duration": {
"hours": 7.8,
"days": 0.32,
"seconds": 28032
},
"driving_hours": 7.8,
"estimated": false,
"from": {
"name": "Rotterdam",
"locode": "NLRTM",
"country_code": "NL",
"lat": 51.90438,
"lng": 4.44245,
"kind": "port"
},
"to": {
"name": "Basel (Rheinhafen)",
"locode": "CHBSL",
"country_code": "CH",
"lat": 47.59,
"lng": 7.59,
"kind": "river_port"
}
}
],
"transfers": [],
"estimated": false
}
],
"date": "2026-10-17",
"seasonal_notes": [
{
"id": "rhine_low",
"kind": "low_water",
"note": "Rhine low water season (Kaub gauge): part loads and low water surcharges",
"typical_window": "01 Aug - 31 Oct",
"source": "estimate: ELWIS / Kaub gauge, low water most years Aug - Oct (2018, 2022 severe)",
"time_factor": 1.15,
"effect": "slower"
}
]
},
"meta": {
"took_ms": 9
}
}