Overview
Products
Reference
Bus
Bus (and tram/rail-station) stop data covers Great Britain and is sourced from NaPTAN; timetables come from BODS, and live vehicle positions from BODS' SIRI-VM feed.
Find stops
GET /v1/bus/stops.json?lat={lat}&lon={lon}&radius={metres}
Or by bounding box: min_lat/min_lon/max_lat/max_lon. Filter by type (bus_stop, train_station, tram_stop).
Departures
GET /v1/bus/stop_timetables/{atcocode}.json?live=true
Times are in the stop's local time (UK time in Britain and Northern Ireland, Irish in the Republic, Amsterdam and Brussels time in the Netherlands and Belgium), and the response's timezone names the zone. A datetime without an offset is read as local time at the stop.
Returns scheduled departures from GTFS timetable data. With live=true, TransCAPI also queries BODS' SIRI-VM feed for vehicles near the stop and matches them to scheduled departures by line and timing, attaching a live_vehicle position where a match is found. This is a best-effort match, since BODS' SIRI-VM feed does not include per-stop call sequence data.
Where TransCAPI tracks a bus against its timetable, which since 30 September 2026 is wherever the operator reports positions to the Bus Open Data Service, departures and arrivals also carry its delay_seconds, an expected time, and a status of on_time, late or early, with source: "avl". A bus already past the stop is departed. This is matched by exact trip, not guessed, and applies with or without live=true.
In the Republic of Ireland, expected times come from the National Transport Authority's live feed, with source: "nta_gtfsr", for Dublin Bus, Bus Éireann, Go-Ahead Ireland and the other bus operators it covers. Luas trams get expected times from Transport Infrastructure Ireland's own forecasts (source: "luas_forecasts"), matched to the timetabled tram to the same destination, and a Luas board's messages carries the line's status when it isn't running normally ("No service between Belgard and Saggart"). A journey the NTA reports cancelled, or a stop it will skip, is status: "cancelled". /v1/bus/vehicles.json includes the Republic's buses too. Irish Rail trains use Irish Rail's own live times (source: "irish_rail"). Northern Ireland has no live data yet.
The Netherlands and Belgium. Every departure has live expected times and cancellations where the operator publishes them: all Dutch operators (source: "ovapi_gtfsr"), and SNCB, De Lijn and TEC in Belgium ("bmc_gtfsr"). Brussels' STIB trams, metro and buses get expected times from STIB's own waiting times ("stib_waiting_times"), for the next two of each line at each stop.
Whole stations. Dutch and Belgian stations list each platform as its own stop (Antwerpen-Centraal has sixteen). Every such stop has a station_atcocode, in /v1/bus/stops.json and on its board. Pass that id to /v1/bus/stop_timetables/{atcocode}.json to get every platform on one board, each departure with its platform (null while the operator hasn't given one) and the platform's own stop_atcocode. The board's stop has type: "station" and lists its platforms.
GET /v1/bus/stop_timetables/BE-gs:nmbssncb:S8821006.json
{ "stop": { "atcocode": "BE-gs:nmbssncb:S8821006", "type": "station",
"name": "Antwerpen-Centraal", "platforms": [ { "atcocode": "BE-gs:nmbssncb:8821006_1", "platform": "1" }, ... ] },
"timezone": "Europe/Brussels",
"departures": [ { "line": "IC", "destination": "Nivelles", "platform": "3",
"aimed_departure_time": "2026-10-25T18:40:00+01:00", ... } ] }
Predicted before the bus sets off. A journey only gets a tracked delay once a bus is matched to it, so the start of a route, and journeys more than a few minutes away, used to show only the timetable. Where the timetable says which journeys one bus works in turn (its block), and the bus is being tracked on the journey before, the departure now carries a prediction with source: "block": the previous journey's expected finish, plus a minute to turn round, against this journey's start. A bus with time to spare is predicted on time, because its layover absorbs the lateness. predicted_from names that journey and gives the bus's position and how late it's running:
{ "line": "51", "aimed_departure_time": "2026-10-01T09:38:00+00:00",
"expected_departure_time": "2026-10-01T09:48:53+00:00",
"delay_seconds": 653, "status": "late", "source": "block",
"predicted_from": { "trip_id": "VJ...", "vehicle_ref": "FSYO:FSYO-35935",
"latitude": 53.39, "longitude": -1.43,
"previous_trip_delay_seconds": 1013 } }
It's a prediction, not a tracked bus: show it as "expected" rather than "live". It's available where operators publish blocks, which is about 43% of journeys nationally: First and Stagecoach on every trip, Arriva, Go North East and the Bee Network not at all. Departures only, within the next two hours.
Live vehicles
GET /v1/bus/vehicles.json?lat={lat}&lon={lon}&radius={metres}
Every bus reporting its position in the area, nearest first. Use a radius up to 10 km, or a bounding box (min_lat/min_lon/max_lat/max_lon, up to 0.25 square degrees). Filter with line or operator (operator code or name). Each bus is linked to its timetabled trip where the timetable holds it, so its trip_id can be passed to /v1/bus/services/{trip_id}.json for its calling points. delay_seconds is given where the bus is tracked against its timetable and is null elsewhere. Positions more than five minutes old are left out, and stale marks any over two minutes.
Coverage follows the operators reporting to the Bus Open Data Service, which is England's scheme: English operators nationally, some Welsh ones, and few in Scotland. Coaches and private hire that report only a registration come back without a line.
{
"results_count": 1,
"member": [
{ "vehicle_id": "SYRK-19472", "line": "52", "operator": "Stagecoach Yorkshire",
"operator_code": "SYRK",
"destination": "Hillsborough Interchange/H1", "direction": 0,
"trip_id": "VJ2ac58a3f39fe0f5624dcfa4b47ae406a40c9c54b", "route_id": "8294",
"trip_start_time": "18:25:00",
"latitude": 53.38271, "longitude": -1.468699, "bearing": 0.0,
"recorded_at": "2026-09-28T18:58:04+00:00", "age_seconds": 14, "stale": false,
"delay_seconds": -189, "current_stop_sequence": 45, "distance": 201.7 }
]
}