List vehicles
Vehicle positions, freshest first, with route and stop names joined on.
/api/vehicles Sorted by timestamp descending; vehicles without one sort last, then by id, so paging is stable.
Pass format=geojson to get a FeatureCollection instead of the usual envelope — see the second example below. That form drops vehicles with no position and reports how many in meta.omittedWithoutPosition rather than shrinking the result set silently.
Try it
Runs from your browser against the API in .
Query
Run this in your terminal
curl equivalent
Parameters
Query
| Parameter | Type | Default | Description |
|---|---|---|---|
routeId | string | — | GTFS route id. Served from an index, so it is the cheapest filter here. Nearly every value you can pass was backfilled by the static join — check |
tripId | string | — | Exact match on |
stopId | string | — | Exact match on the vehicle's current Matches nothing in this capture. Not one of the 1,116 vehicles carries a |
status | enum | — | Where the vehicle is relative to
Only |
occupancy | enum | — | How full the vehicle is.
Matches nothing in this capture. Zero of 1,116 vehicles report occupancy. Absent is not |
congestion | enum | — | Traffic congestion around the vehicle.
Matches nothing in this capture. Zero of 1,116 vehicles report congestion. |
bbox | bbox | — | Bounding box as |
format | enum | json |
|
limit | integer | 50 | Page size, 1–1000. Values outside that range are a 400 rather than a silent clamp. |
offset | integer | 0 | Rows to skip. Compare against |
Response
The standard list envelope: data plus meta with count, total, limit, offset, feedTimestamp and loadedAt.
curl "$API_BASE/api/vehicles?limit=2" {
"data": [
{
"id": "9031001001501695",
"vehicle": {
"id": "9031001001501695"
},
"trip": {
"tripId": "14010000703221662",
"routeId": "9011001087300000",
"directionId": 0,
"scheduleRelationship": "SCHEDULED",
"routeIdSource": "static",
"route": {
"routeId": "9011001087300000",
"agencyId": "505000000000000001",
"shortName": "873",
"type": 700
}
},
"position": {
"latitude": 59.242779,
"longitude": 18.223082,
"bearing": 270,
"speed": 10.6
},
"currentStatus": "IN_TRANSIT_TO",
"timestamp": {
"epoch": 1777288959,
"iso": "2026-04-27T11:22:39.000Z"
}
},
{
"id": "9031001007000472",
"vehicle": {
"id": "9031001007000472"
},
"position": {
"latitude": 59.332401,
"longitude": 18.06319,
"bearing": 249,
"speed": 0
},
"currentStatus": "IN_TRANSIT_TO",
"timestamp": {
"epoch": 1777288959,
"iso": "2026-04-27T11:22:39.000Z"
}
}
],
"meta": {
"count": 2,
"total": 1116,
"limit": 2,
"offset": 0,
"feedTimestamp": "2026-04-27T11:22:38.000Z",
"loadedAt": "2026-08-07T12:01:42.748Z"
}
} As GeoJSON
format=geojson with a bounding box over central Stockholm. Note the different envelope and the omittedWithoutPosition count.
curl "$API_BASE/api/vehicles?bbox=17.9,59.30,18.15,59.36&format=geojson&limit=2" {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
18.06319,
59.332401
]
},
"properties": {
"id": "9031001007000472",
"vehicle": {
"id": "9031001007000472"
},
"currentStatus": "IN_TRANSIT_TO",
"timestamp": {
"epoch": 1777288959,
"iso": "2026-04-27T11:22:39.000Z"
},
"bearing": 249,
"speed": 0
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
18.031305,
59.347157
]
},
"properties": {
"id": "9031001001004006",
"vehicle": {
"id": "9031001001004006"
},
"trip": {
"tripId": "14010000635931335",
"routeId": "9011001000600000",
"directionId": 1,
"scheduleRelationship": "SCHEDULED",
"routeIdSource": "static",
"route": {
"routeId": "9011001000600000",
"agencyId": "505000000000000001",
"shortName": "6",
"type": 700
}
},
"currentStatus": "IN_TRANSIT_TO",
"timestamp": {
"epoch": 1777288958,
"iso": "2026-04-27T11:22:38.000Z"
},
"bearing": 140,
"speed": 0
}
}
],
"meta": {
"count": 2,
"total": 308,
"limit": 2,
"offset": 0,
"omittedWithoutPosition": 0,
"feedTimestamp": "2026-04-27T11:22:38.000Z",
"loadedAt": "2026-08-07T12:01:42.748Z"
}
} Errors
{ "error": "request_failed", … } An enum filter got a value outside its list, or `bbox` was malformed, or `limit`/`offset` were out of range.