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/agencies

Returns 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=10
  • near is required as lng,lat in WGS84.
  • radius is metres from 50 to 10,000. The default is 1,000.
  • limit is 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=50
  • at is an ISO 8601 instant with Z or an explicit offset. It defaults to now. A local time without an offset is rejected because daylight-saving transitions can make it ambiguous.
  • window is 1 to 240 minutes. The default is 60.
  • limit is 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.