Realtime/SL

GTFS-realtime, as JSON you can actually use

Stockholm transit,
one HTTP request away.

Vehicle positions, arrival predictions and service alerts from Storstockholms Lokaltrafik — decoded from protobuf, joined against the national GTFS archive so every id has a name, and served as JSON that never invents a value it wasn't given.

1,116 vehicle positions
934 trip updates
177 service alerts
369 routes in feed

Thirty seconds to a response

No key, no sign-up, no token. Point at a host and start asking questions — which is also why the Try it consoles here run for real in your browser.

terminal
export API_BASE=https://gtfs-realtime-api.broad-darkness-36e7.workers.dev

# What was running, and where, at feed time
curl "$API_BASE/api/vehicles?limit=3"

# Everything calling at Tyresö centrum — a station id, platforms expanded for you
curl "$API_BASE/api/stops/778/arrivals?limit=3"

Prefer to click? Every endpoint page has a Try it console that runs the request from your browser and shows the real response. Try one now →

What backs it

Realtime feeds

Three GTFS-realtime protobuf files from SL — vehicle positions, trip updates and service alerts — decoded with proto2 semantics intact. A field the agency never set stays absent rather than defaulting to zero.

Absent is not zero →

Static GTFS Sweden

7,880 routes and 181,369 stops from the national archive, joined on trip_id. This is what turns 9011001087500000 into “bus 875” — and what supplies the route id the realtime feed almost never sends.

The static join →

And one thing the feed doesn't give you

Every trip update carries a predicted delay for each of its remaining calls, so a single snapshot yields 15,451 observations of how delay drifts with distance. That is enough for an empirical forecast: give it a trip and it will tell you the odds it is still late in five stops' time — with the sample size and the slice it actually used, so you can tell a real answer from a fallback.

Not on the public API. These four endpoints read every trip and stop time event on each call, which the deployed Worker's database backend can't do economically — so they run only against a local instance and return 404 on the public URL. Documented in full anyway, because they're the most interesting thing here. How the forecasts work, and what they can't do →

Things worth knowing first

7 short pages covering the parts of this API that will otherwise surprise you.

The whole surface

19 endpoints. Every one has a runnable console.

GET /health Liveness, uptime and a one-line feed summary. GET /api Machine-readable list of every endpoint and its filters. GET /api/feed Feed header, per-file load report, and static-join statistics. POST /api/feed/reload Re-read the data directory and rebuild every index. GET /api/vehicles Vehicle positions, freshest first, with route and stop names joined on. GET /api/vehicles/:id One vehicle by id. GET /api/trips Predicted arrivals and departures per trip, freshest first. GET /api/trips/:tripId One trip with every stop time update, untruncated. GET /api/alerts Service alerts, soonest-starting first, with an isActive flag. GET /api/alerts/:id One alert by feed entity id. GET /api/routes Routes present in the feed, named, with per-route entity counts. GET /api/routes/:routeId Everything the feed says about one route, in a single response. GET /api/stops Every stop id mentioned anywhere in the feed, named, with counts. GET /api/stops/:stopId/arrivals Predicted calls at a stop, earliest first, across all trips. GET /api/stops/:stopId/alerts Alerts affecting a stop, with the same station/platform expansion. GET /api/punctuality What the forecasts are built from, and — importantly — what they cannot do. GET /api/punctuality/trips/:tripId A delay forecast for every remaining call of a trip that is in the feed. GET /api/punctuality/predict A forecast for a trip this snapshot does not carry — one being planned, say. GET /api/punctuality/baseline How punctual the network is right now, as a distribution and a histogram.