Transit API
The transit data API exposes the static GTFS release behind Unmap as agencies, nearby stops, routes and scheduled departures. It uses the same key and the same usage meter as routing. There is no separate transit plan or quota.
The contract is present, but no production release is enabled yet. Every endpoint on this page
returns 503 with retryable: true until TRANSIT_DATA_VERSION points at a validated, immutable
release. An empty bucket never appears as an empty country. See Coverage
for the feeds that have cleared licensing and validation.
Client
@unmap/sdk exposes all five endpoints through unmap.transit:
import { Unmap } from "@unmap/sdk";
const unmap = new Unmap({ key: "um_live_..." });
const agencies = await unmap.transit.agencies();
const stops = await unmap.transit.nearbyStops([-79.3832, 43.6532], {
radius: 800,
limit: 10,
});
const stop = stops.data[0];
if (stop) {
const departures = await unmap.transit.departures(stop.id, {
at: new Date(),
window: 60,
limit: 20,
});
}Each method returns { data, meta }. meta identifies the source release, attribution and
freshness. Static transit calls count as one normal routing call.
Agencies
GET /transit/agenciesReturns every agency in the enabled release. An agency with the GTFS id TTC in the ttc feed
has the identifier um:transit:agency:ttc:TTC. A single-agency feed that omits agency_id uses
the feed-level form, such as um:transit:agency:ttc. GTFS identifiers are only unique inside one
feed, so raw ids are never presented as global ids.
Nearby stops
GET /transit/stops?near=-79.3832,43.6532&radius=800&limit=10nearis required aslng,latin WGS84.radiusis metres from 50 to 10,000. The default is 1,000.limitis 1 to 100. The default is 20.
The result is filtered by exact great-circle distance and sorted nearest first. Every returned
stop has distance in metres and a stable id such as um:transit:stop:ttc:1234.
Parent stations aggregate the routes and timed departures of their child platforms.
Stop and route lookup
GET /transit/stops/{id}
GET /transit/routes/{id}Pass the Unmap id returned by another transit call. Encode it as a URL path segment when building
the request yourself. The SDK does this automatically with getStop(id) and getRoute(id).
Departures
GET /transit/stops/{id}/departures?at=2026-09-17T08:00:00-04:00&window=60&limit=50atis an ISO 8601 instant withZor an explicit offset. It defaults to now. A local time without an offset is rejected because daylight-saving transitions can make it ambiguous.windowis 1 to 240 minutes. The default is 60.limitis 1 to 200. The default is 50.
The compiler preserves GTFS times after midnight and service exceptions from calendar_dates.txt.
The API resolves them in the feed's timezone, including daylight-saving boundaries, and returns
absolute ISO instants:
{
"data": [
{
"stop_id": "um:transit:stop:ttc:1234",
"route_id": "um:transit:route:ttc:1",
"trip_id": "um:transit:trip:ttc:night-1",
"headsign": "Finch",
"arrival": "2026-09-18T05:14:00.000Z",
"departure": "2026-09-18T05:15:00.000Z",
"stop_sequence": 7,
"schedule_type": "scheduled"
}
],
"meta": {
"source": "Toronto Transit Commission: TTC Routes and Schedules",
"source_updated_at": null,
"source_version": "mdb-732",
"content_hash": "<sha256>",
"data_version": "20260917-0123456789ab",
"unmap_updated_at": "2026-09-17T12:00:00.000Z",
"status": "current",
"attribution": "Open Government Licence - Toronto",
"schedule_type": "scheduled"
}
}schedule_type is always scheduled in this release, on every row and in meta even when the
result is empty. No response implies live vehicle movement, delay or cancellation data.
GTFS-Realtime is a later, separate phase.
Feeds that use frequencies.txt are refused for now. A headway-based trip cannot be represented as
one exact departure without inventing precision the producer did not publish.
Routing is a separate deployment
Static data and routing have separate release gates. An agency can appear here before its feed is
safe to include in Valhalla. Use mode=transit with depart_at on /route only when the coverage
page says transit routing is deployed. There is no arrive_by, transit matrix or transit
isochrone contract.