Open data
What the euro column is built on
The app has to answer a question NMBS does not publish an API for: what does this journey cost. It works it out from two published files, both served from this site, both baked into the app so a first launch with no signal still prices correctly.
These prices are indicative. They are the public grid for a second class single. The ticket you actually buy can differ: a supplement, a product you already hold, or a journey through Brussels Airport all move the number.
The files
-
/fares/latest.json— the version pointer. Names the current edition of each dataset, its path, its size and its SHA-256. Fetch this first; it is under half a kilobyte. -
/fares/nmbs-fares-2025-10-15.json— the price grid, edition 2025-10-15. -
/fares/rail-graph-2026-09-01.json— the rail network as a weighted graph, 2026-09-01.
Versioned files never change under their own name, so they cache
forever. Only latest.json moves.
The price grid
Parsed from the NMBS tariff document, edition 2025-10-15. The charged distance is a tariff kilometre, the minimum is 3 km, and everything from 116 km up is charged as 118 km. It is not a rate per kilometre: the grid starts around €1.45 before the first kilometre is counted, which is why a plain euro-per-kilometre model underprices a commuter journey by about a third.
| Distance | Anytime | With Train+ | Off-peak, Train+ | Weekend |
|---|---|---|---|---|
| 1–3 | 2.50 | 2.50 | 2.50 | 2.50 |
| 4 | 2.50 | 2.50 | 2.50 | 2.50 |
| 5 | 2.50 | 2.50 | 2.50 | 2.50 |
| 6 | 2.50 | 2.50 | 2.50 | 2.50 |
| 7 | 2.60 | 2.60 | 2.50 | 2.50 |
| 8 | 2.70 | 2.70 | 2.50 | 2.50 |
| 9 | 2.90 | 2.90 | 2.50 | 2.50 |
| 10 | 3.10 | 3.10 | 2.50 | 2.50 |
| 11 | 3.20 | 3.20 | 2.50 | 2.50 |
| 12 | 3.40 | 3.40 | 2.50 | 2.50 |
| 13 | 3.60 | 3.60 | 2.50 | 2.50 |
| 14 | 3.70 | 3.70 | 2.50 | 2.60 |
| 15 | 3.90 | 3.90 | 2.50 | 2.70 |
| 16 | 4.10 | 4.10 | 2.50 | 2.80 |
| 17 | 4.20 | 4.20 | 2.50 | 3.00 |
| 18 | 4.40 | 4.40 | 2.60 | 3.10 |
| 19 | 4.60 | 4.60 | 2.70 | 3.20 |
| 20 | 4.70 | 4.70 | 2.80 | 3.30 |
| 21 | 4.90 | 4.90 | 2.90 | 3.40 |
| 22 | 5.10 | 5.10 | 3.00 | 3.50 |
| 23 | 5.20 | 5.20 | 3.10 | 3.70 |
| 24 | 5.40 | 5.40 | 3.20 | 3.80 |
| 25 | 5.50 | 5.50 | 3.30 | 3.90 |
| 26 | 5.70 | 5.70 | 3.40 | 4.00 |
| 27 | 5.90 | 5.90 | 3.50 | 4.10 |
| 28 | 6.00 | 6.00 | 3.60 | 4.20 |
| 29 | 6.20 | 6.20 | 3.70 | 4.30 |
| 30 | 6.40 | 6.40 | 3.80 | 4.50 |
| 31–33 | 6.70 | 6.70 | 4.00 | 4.70 |
| 34–36 | 7.20 | 7.20 | 4.30 | 5.00 |
| 37–39 | 7.70 | 7.70 | 4.60 | 5.40 |
| 40–42 | 8.20 | 8.20 | 4.90 | 5.70 |
| 43–45 | 8.70 | 8.70 | 5.20 | 6.10 |
| 46–48 | 9.20 | 9.20 | 5.50 | 6.40 |
| 49–51 | 9.70 | 9.70 | 5.80 | 6.80 |
| 52–54 | 10.20 | 10.20 | 6.10 | 7.10 |
| 55–57 | 10.70 | 10.70 | 6.40 | 7.50 |
| 58–60 | 11.20 | 11.20 | 6.70 | 7.80 |
| 61–65 | 11.80 | 11.80 | 7.10 | 8.30 |
| 66–70 | 12.60 | 12.60 | 7.60 | 8.90 |
| 71–75 | 13.50 | 13.50 | 8.10 | 9.40 |
| 76–80 | 14.30 | 14.00 | 8.60 | 10.00 |
| 81–85 | 15.10 | 14.00 | 9.10 | 10.60 |
| 86–90 | 15.90 | 14.00 | 9.60 | 11.20 |
| 91–95 | 16.80 | 14.00 | 10.10 | 11.70 |
| 96–100 | 17.60 | 14.00 | 10.60 | 12.30 |
| 101–105 | 18.40 | 14.00 | 11.10 | 12.90 |
| 106–110 | 19.30 | 14.00 | 11.60 | 13.50 |
| 111–115 | 20.10 | 14.00 | 12.00 | 14.10 |
| 116+ | 20.90 | 14.00 | 12.50 | 14.60 |
The rail network
Belgian line sections from Infrabel, with the kilometre posts at each end, turned into a graph: nodes are operational points and the stations spliced into the middle of a section, and every edge is metres along the track. The app runs a shortest path across it to propose the rail kilometres between two stations, which is a proposal on an editable field and never a silent input. NMBS charges an administrative tariff distance that can differ from the track, by a kilometre on an open corridor and by rather more around the Brussels junctions.
Where it comes from
- Prices: NMBS/SNCB Tarieven, editie 2025-10-15.
- Network: Infrabel Open Data, line sections and operational points.
- Stations: iRail.
Neither file contains anything personal and neither needs a key. The app fetches them over plain HTTPS and sends nothing with the request.