Realtime/SL

Stations and platforms

SL's two feeds reference stops at different levels: trip updates use platform ids, alerts use station ids. Stop endpoints accept either and tell you what they searched.

GTFS models a stop at more than one level. A station (location_type: 1) is the place a passenger names — “Tyresö centrum”. A platform (location_type: 0) is a specific stopping point within it, pointing back at its station through parent_station.

SL's two realtime feeds pick different levels, and neither is wrong:

FeedReferencesExample
Trip updates Platforms — a prediction is for a specific stopping point 9022050000778004
Service alerts Stations — disruption affects the whole place 778

What the API does

Stop arrivals and stop alerts both accept either level. Given a station id they automatically expand to cover its child platforms, and report every id searched in includedStopIds:

GET /api/stops/778/arrivals
curl "$API_BASE/api/stops/778/arrivals?limit=2"
200 · trimmed — data array and meta abbreviated
{
  "data": [ /* 23 calls across all platforms */ ],
  "meta": { "count": 2, "total": 23, "limit": 2, "offset": 0, "…": "…" },
  "stopId": "778",
  "stop": {
    "stopId": "778",
    "name": "Tyresö centrum",
    "latitude": 59.244143,
    "longitude": 18.229239,
    "locationType": 1
  },
  "includedStopIds": [
    "778",
    "9022050000778001", "9022050000778002", "9022050000778003",
    "9022050000778004", "9022050000778005", "9022050000778006",
    "9022050000778007", "9022050000778008", "9022050000778009",
    "9022050000778010", "9022050000778011"
  ]
}
The data array and some meta keys are elided here; includedStopIds is complete.

Three things to read off that response:

  • stopId is what you asked for, echoed back unchanged.
  • stop is the static detail for that id. locationType: 1 confirms you passed a station.
  • includedStopIds is the actual search set — the station plus eleven platforms. It appears only when the id expanded to more than itself, so its presence is the signal that expansion happened.

Reading an empty result correctly

Expansion working and there being nothing to find are different outcomes, and the response distinguishes them. Station 10316 (Duvbo torg) expands to two platforms, and no trip update in this capture calls at either:

200 · GET /api/stops/10316/arrivals — trimmed meta
{
  "data": [],
  "meta": { "count": 0, "total": 0, "limit": 2, "offset": 0, "…": "…" },
  "stopId": "10316",
  "stop": {
    "stopId": "10316",
    "name": "Duvbo torg",
    "latitude": 59.370423,
    "longitude": 17.952471,
    "locationType": 1
  },
  "includedStopIds": ["10316", "9022050010316001", "9022050010316002"]
}

A populated includedStopIds with an empty data means the lookup did its job and the answer is genuinely nothing. Had includedStopIds been missing, that would mean the id had no children in the archive — either it is already a platform, or the archive has no record of it.

Which id do I have?

SL station ids are short (778, 10316); platform ids are sixteen digits. That is a useful heuristic, not a rule — read the data instead:

  • parentStation present → it is a platform, and that is its station.
  • locationType: 1 → it is a station.
  • platformCode present → the platform's public letter or number, e.g. "G".

List stops returns both levels together, since it is the union of every stop id mentioned anywhere in the feed. Counts sit on whichever id was mentioned, so a station's row typically shows alerts and no trip updates, while its platforms' rows show the reverse — which is the same split, seen from the other side.