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:
| Feed | References | Example |
|---|---|---|
| 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:
curl "$API_BASE/api/stops/778/arrivals?limit=2" {
"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"
]
} Three things to read off that response:
-
stopIdis what you asked for, echoed back unchanged. -
stopis the static detail for that id.locationType: 1confirms you passed a station. -
includedStopIdsis 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:
{
"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:
parentStationpresent → it is a platform, and that is its station.locationType: 1→ it is a station.platformCodepresent → 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.