BYTETOOLS

Digitraffic Rail (Finland) API

Free official Finnish railway API with no key: live train locations, full timetables with actual times, cancellations and cause codes for every service. Tested example included.

No API key requiredCORS enabledHTTPSFree tier

Endpoint tested and returned HTTP 200 on 2026-08-21

What is the Digitraffic Rail (Finland) API?

Digitraffic Rail is the Finnish Transport Infrastructure Agency's free, key-free railway API. It publishes every train's timetable with scheduled and actual times at each station, live GPS positions, cancellations, composition data and structured cause codes explaining every delay.

Most national rail APIs tell you a train is late. This one tells you why, in structured form: every timetable row carries a `causes` array with official cause and third-level cause codes, so delays can be aggregated by reason across an entire network rather than counted as an undifferentiated total. For punctuality analysis that difference is the whole exercise.

The data model is row-based rather than stop-based, and getting that right avoids a lot of confusion. Each `timeTableRow` is one event — an ARRIVAL or a DEPARTURE — so a train calling at a station generates two rows, and only origins and terminals have a single one. `differenceInMinutes` is signed, `commercialStop` distinguishes passenger stops from operational ones, and `trainReady` appears only where a departure clearance was recorded. Like the marine API, this host requires `Accept-Encoding: gzip`.

Quick facts

Base URL
https://rata.digitraffic.fi/api/v1
Authentication
No API key or account. Finnish open government data; the agency asks callers to send a `Digitraffic-User` header.
Rate limit
No published numeric quota. Live data changes every few seconds; the agency prefers MQTT subscriptions to heavy polling.
Pricing
Free. Published under a CC BY licence.
CORS
Enabled — callable directly from browser JavaScript
Official docs
Read the docs

How to use the Digitraffic Rail (Finland) API

Every request below was executed against the live API on 2026-08-21, and the response shown is the real body it returned — not an illustration.

1. Fetch the latest run of a specific train number

GET https://rata.digitraffic.fi/api/v1/trains/latest/1

curl
curl 'https://rata.digitraffic.fi/api/v1/trains/latest/1' \
  -H 'Accept-Encoding: gzip' \
  -H 'Digitraffic-User: Bytevancer/ByteTools'
JavaScript (fetch)
const res = await fetch("https://rata.digitraffic.fi/api/v1/trains/latest/1", {
  headers: {
    "Accept-Encoding": "gzip",
    "Digitraffic-User": "Bytevancer/ByteTools",
  },
});
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
const data = await res.json();
console.log(data);
Python (requests)
import requests

headers = {
    "Accept-Encoding": "gzip",
    "Digitraffic-User": "Bytevancer/ByteTools",
}

res = requests.get("https://rata.digitraffic.fi/api/v1/trains/latest/1", headers=headers, timeout=20)
res.raise_for_status()
print(res.json())
Response — HTTP 200 (truncated)
[
  {
    "commuterLineID": "",
    "runningCurrently": true,
    "cancelled": false,
    "version": 293815121063,
    "timetableType": "REGULAR",
    "timetableAcceptanceDate": "2026-07-02T05:55:40.000Z",
    "departureDate": "2026-08-21",
    "trainNumber": 1,
    "operatorUICCode": 10,
    "operatorShortCode": "vr",
    "timeTableRows": [
      {
        "type": "DEPARTURE",
        "commercialTrack": "7",
        "cancelled": false,
        "scheduledTime": "2026-08-21T03:54:00.000Z",
        "actualTime": "2026-08-21T03:54:36.000Z",
        "differenceInMinutes": 1,
        "commercialStop": true,
        "causes": [],
        "stationShortCode": "HKI",
        "stationUICCode": 1,
        "countryCode": "FI",
        "stopSector": "B3",
        "trainReady": {
          "accepted": true,
          "source": "KUPLA",
          "timestamp": "2026-08-21T03:52:36.000Z"
        },
        "trainStopping": true
      },
      {
        "type": "ARRIVAL",
        "commercialTrack": "4",
        "cancelled": false,
        "scheduledTime": "2026-08-21T03:59:00.000Z",
        "actualTime": "2026-08-21T03:59:12.000Z",
        "differenceInMinutes": 0,
        "commercialStop": true,
        "causes": [],
        "stationShortCode": "PSL",
        "stationUICCode": 10,
        "countryCode": "FI",
        "stopSector": "C3",
        "trainStopping": true
      },
      {
        "type": "DEPARTURE",
        "commercialTrack": "4",
        "cancelled": false,
        "scheduledTime": "2026-08-21T04:00:00.000Z",
        "actualTime": "2026-08-21T04:00:49.000Z",
        "difference

Parameters

ParameterTypeRequiredDescription
(latest train)pathOptional`/trains/latest/{number}` returns the most recent run of a train number. 1
(by date)pathOptional`/trains/{date}/{number}` returns a specific departure date's run. 2026-08-21/1
(live positions)pathOptional`/train-locations/latest/{number}` returns GPS positions for a running train. 1
(station schedule)pathOptional`/live-trains/station/{code}` returns arrivals and departures at a station. HKI
arrived_trains / departed_trainsqueryOptionalHow many past events to include on a station query. 5
Accept-EncodingheaderRequiredMust be `gzip`; the service returns 406 otherwise. gzip

Response fields

trainNumber / departureDateinteger / string
Together these identify a run uniquely. The number alone does not.
operatorShortCode / operatorUICCodestring / integer
Operating company — `vr` for the national operator.
trainCategory / trainTypestring
Long-distance, commuter or cargo, and the specific service type.
commuterLineIDstring
Letter code for Helsinki-area commuter services, empty for other trains.
runningCurrently / cancelledboolean
Whether the train is moving now and whether the run was cancelled.
timeTableRowsarray
One row per event — ARRIVAL or DEPARTURE — so a calling point produces two.
timeTableRows[].typestring
`ARRIVAL` or `DEPARTURE`.
timeTableRows[].scheduledTime / actualTimestring
Planned and actual times in UTC. `actualTime` is absent until the event happens.
timeTableRows[].differenceInMinutesinteger
Signed delay. Negative means early.
timeTableRows[].stationShortCodestring
Station code — HKI is Helsinki. Join to `/metadata/stations` for names.
timeTableRows[].commercialStop / commercialTrackboolean / string
Whether passengers may board, and the platform.
timeTableRows[].causesarray
Structured delay reasons with official category codes, when a delay has been attributed.

What you can build with the Digitraffic Rail (Finland) API

  • Build a departure board for a Finnish station
  • Track a specific train's live position and delay
  • Analyse punctuality by cause code across the network
  • Alert commuters to cancellations on their line
  • Study historical timetable performance from the archive endpoints

Common errors and how to fix them

406 Not Acceptable

The request did not send `Accept-Encoding: gzip`.

Fix: Advertise gzip and decompress. Digitraffic enforces this on every endpoint across both the rail and marine services.

Two rows for the same station

Correct — arrival and departure are separate events.

Fix: Filter on `type` for what you need. Origins have only a DEPARTURE row and terminals only an ARRIVAL.

actualTime is missing

The event has not happened yet.

Fix: Fall back to `scheduledTime` for future stops, and use the presence of `actualTime` to decide whether a stop is in the past.

A train number returns the wrong service

Numbers are reused across departure dates.

Fix: Always pair `trainNumber` with `departureDate`. The `/latest/` path does this for you; explicit date queries do not.

Digitraffic Rail (Finland) API — frequently asked questions

Is the Finnish rail API free?

Yes, free with no key or account. It is open government data from the Finnish Transport Infrastructure Agency under a CC BY licence, and the agency simply asks that you identify your application in a header.

Can I see why a train is delayed?

Yes, and this is the API's standout feature. Every timetable row can carry a `causes` array with official category codes, so delays can be aggregated by reason rather than merely counted.

Why does each station appear twice?

Because the model is event-based: an arrival and a departure are separate rows. A through station generates both; an origin generates only a departure and a terminal only an arrival.

Are live train positions available?

Yes. The `/train-locations/` endpoints return GPS positions for running services, and there is an MQTT feed for subscribing to updates instead of polling.

Tools that pair with this API

Digitraffic Rail (Finland) is an independent third-party service and is not affiliated with ByteTools or ByteVancer. Details on this page were verified on 2026-08-21; always check the official documentation before relying on this API in production, as terms and limits can change.