Skip to main content
FR

Report a problem

This page is not about one stop, route, station or vehicle. Open one to have the report name it, or use the full report.

What happened
Full report No account needed
Evidence and data
  1. Reading
  2. Evidence and data
  3. Developer API

Every figure on this site is one free JSON call away.Developer API

Every figure here is versioned JSON. Free to use, with or without a key.Every figure here is versioned JSON. Free to use, with or without a key.

Base address https://otranspo.ca/api/public/v1

Free, key optional · 1,000 a day, 60 a minute · code MIT · version 1.0.0

Access

Free

key optional

Rate limit

1,000 a day

60 a minute; more on Developer

Code licence

MIT

data keeps its source’s terms

Version

1.0.0

stable · 180 days’ notice

Plans

Free

1,000 calls a day, 60 a minute. No key needed; a free key counts your calls separately from everyone else on your network.

Credit ‘Data: OTranspo (otranspo.ca)’ wherever you show the data.

Developer

$10 a monthor $100 a year (CAD)

  • 100,000 calls a day, 600 a minute
  • Bulk downloads and full history
  • Support by email

Journalists, students and council staff: the free tier is yours. Write to us if you need more for a story or a study.

How to send a key

curl -H "Authorization: Bearer otr_…" https://otranspo.ca/api/public/v1/route-states

Limits

Each answer carries X-RateLimit-Remaining (this minute) and X-RateLimit-Daily-Remaining (today, UTC). Over the limit you get 429 with the time it resets.

One call, start to finish

Request

curl https://otranspo.ca/api/public/v1/route-states

The response is the real one from this site, fetched when you ask.

Response, shortened Schema

Running…

Every resource, 39

Paths start at /api/public/v1 unless written in full. Open any row for its HTTP statuses, error codes, access, uncertainty and schema.

Index and contractstart here2
API indexGET/api/public/v1—JSON

HTTP status

200

Error reason codes

—

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

endpoints.id · endpoints.path

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1

JSON Schema

OpenAPI 3.1 contractGET/openapi.json—JSON

HTTP status

200

Error reason codes

—

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

operationId · path

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/openapi.json

JSON Schema

Service nowwhat is happening this minute5
Cancellations posted nowGET/current-cancellations—JSON

HTTP status

200 · 400 · 503

Error reason codes

unsupported_query 400 · current_cancellations_unavailable 503

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

trips.tripId · trips.routeId

Source and uncertainty

Only explicit CANCELED/DELETED notices for timetable trips in the current snapshot are listed. Empty or unavailable feeds do not prove that no trips were cancelled; outside-timetable notices may be withheld.

Example call

GET /api/public/v1/current-cancellations

JSON Schema

Route states: scheduled vs seenGET/route-states—JSON

HTTP status

200 · 503

Error reason codes

—

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

operatorId · routeId

Source and uncertainty

This is not an operator alert. Routes without published positions use positions_not_published; stale or missing feeds return unavailable.

Example call

GET /api/public/v1/route-states

JSON Schema

Incidents, in English and FrenchGET/incidents—JSON

HTTP status

200 · 503

Error reason codes

—

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

publicId · slug · updates.id

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/incidents

JSON Schema

One official alertGET/alerts/{alertId}format=json|csv · alertIdJSON · CSV

HTTP status

200 · 400 · 503

Error reason codes

invalid_alert_id 400 · unsupported_format 400 · alert_not_found 400 · alert_unavailable 503

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

alert.id · alert.operatorId

Source and uncertainty

The notice is the operator’s own wording. Kept wordings start when we first saw the notice, not when the operator posted it, and an empty list does not prove the notice never changed.

Example call

GET /api/public/v1/alerts/{alertId}

JSON Schema

Station boardGET/stations/{stationId}format=json|csv · stationIdJSON

HTTP status

200 · 400 · 404 · 503

Error reason codes

invalid_station_id 400 · unsupported_format 400 · station_not_found 404 · station_board_unavailable 503

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

station.id · lines.routeRecordId · departures.tripId

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/stations/{stationId}

JSON Schema

Evidence and reportsthe figures behind every page11
Reliability evidenceGET/reliability-evidenceformat=json|csvJSON · CSV

HTTP status

200 · 400 · 503

Error reason codes

unsupported_format 400

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

routeId · window

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/reliability-evidence

JSON Schema

Route evidenceGET/routes/{routeId}/evidenceformat=json|csv · routeIdJSON

HTTP status

200 · 400 · 404 · 503

Error reason codes

invalid_route_id 400 · unsupported_format 400 · route_not_found 404 · route_evidence_unavailable 503

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

route.routeId

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/routes/{routeId}/evidence

JSON Schema

Route 7 evidence on the site

Route service by dayGET/routes/{routeId}/service-evidencewindow=day|week|month|28d · date · format=json|csv · routeIdJSON

HTTP status

200 · 400 · 404 · 503

Error reason codes

invalid_route_id 400 · unsupported_window 400 · invalid_service_date 400 · unsupported_format 400 · route_not_found 404 · route_service_evidence_unavailable 503

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

routeId · window

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/routes/{routeId}/service-evidence

JSON Schema

Station or ward serviceGET/places/{kind}/{placeId}/service-evidencedate · kind=station|ward · placeIdJSON

HTTP status

200 · 400 · 503

Error reason codes

unsupported_place_kind 400 · invalid_place_id 400 · unsupported_query 400 · invalid_service_date 400 · place_service_evidence_unavailable 503

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

kind · placeId · operatorId

Source and uncertainty

Observation and cancellation completeness are explicitly unverified; no-position candidate counts remain null and comparison eligibility is false.

Example call

GET /api/public/v1/places/{kind}/{placeId}/service-evidence

JSON Schema

Evidence record downloadGET/evidence/{evidenceId}format=json|csv · evidenceIdJSON · CSV

HTTP status

200 · 400 · 404

Error reason codes

unsupported_format 400 · not_found 404

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

evidenceId

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/evidence/{evidenceId}

JSON Schema

Ward scorecardsGET/ward-scorecardsformat=json|csvJSON · CSV

HTTP status

200 · 503

Error reason codes

—

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

snapshotId · wardId

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/ward-scorecards

JSON Schema

Past scorecard editionsGET/historical-scorecardssnapshotId=historical-scorecards:<sha256> · routeIdJSON

HTTP status

200 · 400 · 404 · 422

Error reason codes

snapshot_id_required 400 · invalid_route_id 400 · invalid_parameters 400 · snapshot_not_found 404 · route_detail_not_published 422 · route_not_in_snapshot 404

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

snapshotId · routeId

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/historical-scorecards

JSON Schema

Service report archiveGET/service-report-archivekindJSON

HTTP status

200 · 400 · 503

Error reason codes

invalid_archive_query 400 · archive_unavailable 503

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

kind · period

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/service-report-archive

JSON Schema

Prediction accuracyGET/prediction-calibration—JSON

HTTP status

200 · 503

Error reason codes

—

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

operatorId · routeId · routeContext · horizonBucket

Source and uncertainty

Later observed arrival is a comparison, not ground truth or a validated prediction interval; independent validation is false.

Example call

GET /api/public/v1/prediction-calibration

JSON Schema

Selected service reportGET/api/insights/reports/selected?period={period}&date={YYYY-MM-DD}period=day|week|month · date=YYYY-MM-DD · operator=all|oc_transpo|sto · routeJSON

HTTP status

200 · 400 · 503

Error reason codes

invalid_selection 400 · selected_report_unavailable 503 · invalid_route_hour_selection 400 · route_hours_unavailable 503

Access and rate limit

Anonymous; no public-api limit is configured for this path.

Stable identifiers

period · date · operator · method

Source and uncertainty

Without route, the selected-report contract is unchanged. With route, the selected-route-hours contract returns at most48 method-separated local-hour prediction groups, preserving requested report operator separately from routeOperator. These mutable retained predictions do not prove physical arrivals, complete archive coverage, zero service or an immutable publication.

Example call

GET /api/insights/reports/selected?period={period}&date={YYYY-MM-DD}

JSON Schema

Prediction comparison inputsGET/api/insights/reports/selected/comparison-evidence?period={period}&date={YYYY-MM-DD}period=day|week|month · date=YYYY-MM-DD · operator=all|oc_transpo|stoJSON

HTTP status

200 · 400 · 503

Error reason codes

invalid_comparison_evidence_selection 400

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

payload.edition · payload.selection · checksum.value

Source and uncertainty

This opt-in export preserves the exact captured route/day read results, declared calendar, comparison refusals and measured source-code manifest. It is bounded to 20,000 input rows and 8 MiB and does not claim an atomic database snapshot, statistical independence, confidence intervals, physical service delivery, causation, equivalence or model eligibility. Schema validation alone does not verify checksum or replay; consumers must perform those checks separately.

Example call

GET /api/insights/reports/selected/comparison-evidence?period={period}&date={YYYY-MM-DD}

JSON Schema

History and replaywhat already happened6
Past cancellations and gapsGET/historical-cancellationswindow=day|week|28d|month · date · assessment=noneJSON

HTTP status

200 · 400 · 503

Error reason codes

unsupported_query 400 · unsupported_window 400 · invalid_service_date 400 · unsupported_assessment 400 · historical_cancellations_unavailable 503 · historical_cancellation_limit_exceeded 400

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

period · records.tripId

Source and uncertainty

Historical polling completeness is unverified and schedule matching may be unassessed; unknown coverage is not zero cancellations.

Example call

GET /api/public/v1/historical-cancellations

JSON Schema

City replayGET/replaydate · routeFamily · operator · fromMinute · minutes · summaryJSON

HTTP status

200 · 400 · 503

Error reason codes

date_required 400 · invalid_route_family 400 · invalid_operator 400 · replay_positions_unavailable 503 · published_replay_unavailable 503

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

date · routeFamily · operator

Source and uncertainty

Replay is historical and never live; only captured/published archive evidence is returned.

Example call

GET /api/public/v1/replay

JSON Schema

Vehicles seen, by dayGET/fleet-historydate · operator=all|oc_transpo|sto · route · feedIdJSON

HTTP status

200 · 400 · 503

Error reason codes

invalid_fleet_history_lookup 400 · invalid_fleet_history_date 400 · invalid_fleet_history_operator 400 · fleet_history_unavailable 503

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

serviceDate · operator · route

Source and uncertainty

Retained feed observations are not a physical fleet inventory; missing retention is not zero service.

Example call

GET /api/public/v1/fleet-history

JSON Schema

Feed vehicle IDs, by dayGET/fleet-history/feed-idsdate · operator=all|oc_transpo|sto · cursorJSON

HTTP status

200 · 400 · 503

Error reason codes

invalid_fleet_feed_id_selection 400 · invalid_fleet_history_date 400 · invalid_fleet_history_operator 400 · invalid_fleet_feed_id_cursor 400 · fleet_feed_id_census_unavailable 503

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

date · operator · digest · collisionOrdinal

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/fleet-history/feed-ids

JSON Schema

One vehicle ID over timeGET/vehicles/{vehicleId}/visibility-historyformat=json|csv · vehicleIdJSON

HTTP status

200 · 400 · 404 · 503

Error reason codes

invalid_vehicle_id 400 · unsupported_format 400 · vehicle_history_unavailable 503 · vehicle_history_not_found 404

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

vehicleId

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/vehicles/{vehicleId}/visibility-history

JSON Schema

Vehicles seen, in bulkGET/bulk/fleet-historyfrom · to · operator=all|oc_transpo|sto · route · feedIdJSON

HTTP status

200 · 400 · 401 · 403 · 429 · 503

Error reason codes

unsupported_query 400 · invalid_bulk_range 400 · invalid_fleet_history_lookup 400 · invalid_fleet_history_operator 400 · fleet_history_unavailable 503 · api_key_required 401 · invalid_api_key 401 · plan_required 403 · rate_limited 429

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

serviceDate · operator · route

Source and uncertainty

Each line is the fleet-history evidence for one seven-day window; retained feed observations are not a physical fleet inventory and missing retention is not zero service.

Example call

GET /api/public/v1/bulk/fleet-history

JSON Schema

Timetables and offlinethe published timetable6
Timetable for one routeGET/transit-planning/{routeId}date · routeIdJSON

HTTP status

200 · 400 · 503

Error reason codes

invalid_route_or_date 400 · use_history_for_past_dates 400 · planning_baseline_unavailable 503

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

routeId · serviceDate

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/transit-planning/{routeId}

JSON Schema

Timetable for the networkGET/transit-planning/networkdateJSON

HTTP status

200 · 400 · 503

Error reason codes

invalid_parameters 400 · invalid_service_date 400 · network_baseline_unavailable 503

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

serviceDate

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/transit-planning/network

JSON Schema

Street path between two pointsPOST/transit-planning/street-pathbodyJSON

HTTP status

200 · 400 · 503

Error reason codes

invalid_body 400 · invalid_segment 400

Access and rate limit

Anonymous, trusted origin required; 60 a minute when distributed rate limiting is on.

Stable identifiers

from · to

Source and uncertainty

Path may be unavailable when routing source data is absent; no path is not evidence of no accessible route.

Example call

POST /api/public/v1/transit-planning/street-path

JSON Schema

Offline timetable packsGET/offline-pack—JSON

HTTP status

200 · 503

Error reason codes

offline_pack_not_published 503 · offline_pack_unavailable 503

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

packId · digest

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/offline-pack

JSON Schema

Offline pack manifestGET/offline-pack/manifestpackJSON

HTTP status

200 · 404 · 503

Error reason codes

—

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

packId · shards.id

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/offline-pack/manifest

JSON Schema

Offline pack pieceGET/offline-pack/shards/{id}idbytes

HTTP status

200 · 404 · 503

Error reason codes

—

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

id · digest

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/offline-pack/shards/{id}

JSON Schema

Registers and policywhat we changed and why6
Corrections registerGET/correctionsformat=json|csvJSON · CSV

HTTP status

200 · 400

Error reason codes

unsupported_format 400

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

records.id · records.revision

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/corrections

JSON Schema

Policy registerGET/policy-register—JSON

HTTP status

200

Error reason codes

—

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

records.id · records.revision

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/policy-register

JSON Schema

Accessibility assuranceGET/accessibility-assurance—JSON

HTTP status

200

Error reason codes

—

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

evidence.id · remediationLog.id

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/accessibility-assurance

JSON Schema

Regional coverage and freshnessGET/regional-coverage—JSON

HTTP status

200 · 503

Error reason codes

—

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

operators.operatorId

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/regional-coverage

JSON Schema

Notification and help channelsGET/journey-service-policy—JSON

HTTP status

200

Error reason codes

—

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

contractVersion · channels.channel

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/journey-service-policy

JSON Schema

Vehicle presentation checkGET/fleet-presentation—JSON

HTTP status

200 · 503

Error reason codes

—

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

evidence.operatorSamples.operatorId

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/fleet-presentation

JSON Schema

Sharinglinks and social cards3
Make a share linkPOST/share-snapshotsbodyJSON

HTTP status

200 · 400 · 404 · 409 · 503

Error reason codes

Invalid request body. 400 · A canonical public path is required. 400 · This page cannot be shared as a public snapshot. 400 · The public page was not found. 404

Access and rate limit

Anonymous, trusted origin required; 60 a minute when distributed rate limiting is on.

Stable identifiers

snapshotId · revision

Source and uncertainty

If immutable evidence is not published, issuance returns a canonical_only state; retryable storage faults return a human-readable error and 503.

Example call

POST /api/public/v1/share-snapshots

JSON Schema

Share link statusGET/share-snapshots/{snapshotId}snapshotIdJSON

HTTP status

200 · 400 · 404 · 410 · 503

Error reason codes

—

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

snapshotId · revision

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/share-snapshots/{snapshotId}

JSON Schema

Share link social cardGET/share-snapshots/{snapshotId}/opengraphsnapshotIdPNG

HTTP status

200 · 400 · 404 · 503

Error reason codes

invalid_identifier 400 · not_found 404 · temporarily_unavailable 503

Access and rate limit

Anonymous access; 60 a minute when distributed rate limiting is on.

Stable identifiers

snapshotId · revision

Source and uncertainty

Read the response status, evidenceState, source timestamps, limitations and gaps; absence is not proof of zero.

Example call

GET /api/public/v1/share-snapshots/{snapshotId}/opengraph

JSON Schema

Access and use

Access and useLimits, caching, versions, privacy and licence
Access
Every GET resource is public and free to use, with or without a key. Bulk and history resources need a Developer key. The two POST resources (making a share link, drawing a street path) only accept requests from otranspo.ca itself.
Rate limit
1,000 calls a day and 60 a minute, with or without a free key; 100,000 a day and 600 a minute on the Developer plan. Read the X-RateLimit-* headers on every answer; X-RateLimit-Status says when limits are degraded.
Keys
Send a key as Authorization: Bearer otr_… or X-API-Key. Never in the address. A wrong, revoked or expired key gets 401, never a keyless answer.
Caching
The index is kept 30 seconds by your browser and 5 minutes at the edge. Live resources such as cancellations are sent no-store. Offline timetable pieces never change once published.
Versions
Each response names its schema and schemaVersion. A breaking change gets a new /v2 path, with 180 days’ notice in Deprecation, Sunset and Link headers.
Privacy
Do not send personal data. Coordinates sent to the street path are used for that request only, never logged or stored. Responses never hold account IDs, trip searches, email or network addresses, or internal evidence links.
Unknown is not zero
A response can be unavailable even when the resource exists. Read status, evidenceState, source times, coverage and limitations. Route states compare the timetable with buses seen; they are not operator alerts.
Licence
Code: MIT. OC Transpo and STO data stay under their own open-data terms and need credit. Our figures: CC BY 4.0, credit otranspo.ca.
Not done yet
No SDK is published, no second city is supported, and partner tenant-key access is not open. This page does not claim them.
Data and downloadsThe same figures as CSV and JSON files, with how to cite them.