How a transit agency is described to Transit, which providers are active and what it takes for a provider to appear on the public site.

Reference Value
Subject and boundary Provider manifests, the registry, the public catalog and the path for adding a provider. Variable names are on ‣.
Verified source config/providers, registry.py, snapshots/providers.py, core/models.py, live_policy.py, health/checks.py at main 9733eb26d92533f56cdc8bc46b81b93fbb5987c8, checked November 10, 2026.
Support state STM and OC Transpo active; STO an inactive template. Configuration alone does not establish public availability or permission to use a source.

Providers

Provider Manifest State Feeds Feed authentication
STM (Montréal) stm.yaml Active, public Static GTFS, GIS, trip updates, vehicle positions, i3 alerts Realtime and i3 use STM_API_KEY in the apiKey header
OC Transpo (Ottawa) octranspo.yaml Active, public Static GTFS, trip updates, vehicle positions Realtime uses OCTRANSPO_API_KEY in Ocp-Apim-Subscription-Key
STO (Outaouais) sto.yaml Inactive template Static GTFS, trip updates, vehicle positions, service alerts Key plus a per-minute SHA-256 hash in query parameters

STO stays inactive until its required source statement and actual data update date are filled in. The data proxy answers /data/v1/sto/* with HTTP 410.

Manifest sections

Section Holds
provider ID, display name, timezone, bounds, city, attribution text, is_active, live_source_lag_seconds, max_vehicle_speed_kmh
public enabled, EN/FR labels, map fit and max bounds, geocode context, basemap URL and bounds, poster index, agency alert links
feeds One entry per endpoint: endpoint_key, feed_kind, source_url_env_var, auth type and credential variable, refresh_interval_seconds and optional refresh_phase_seconds
realtime lines_without_live_data: lines the provider publishes no live data for

Live settings per provider

Key STM OC Transpo Effect
feeds.*.refresh_interval_seconds, refresh_phase_seconds Vehicles 20 s at phase 10 s; trip updates 30 s; i3 alerts 300 s Vehicles 20 s, unphased; trip updates 30 s; no alerts feed (#746, merge 9c713e39) Capture cadence (see ‣)
provider.live_source_lag_seconds 0 (default) 60 Published as manifest.files.live.source_lag_s; the web app widens its Not reporting cutoff and estimated-position horizon by it
provider.max_vehicle_speed_kmh 130 (default) 130 (default) Silver nulls a reported speed above the cap, negative or non-finite, keeping the row; the default was raised from 100 in #742 because highway buses report 101–117 km/h
realtime.lines_without_live_data metro_realtime: route type 1 otrain_realtime: route type 0 Declared lines are left out of the live silent and non-responding trip counts (gold.scheduled_running_trips_at). The daily silent_trip_days rollup (gold/rollups.py) still counts them. STO declares none
public.basemap_bounds −75, 44.8 to −72.5, 46.3 −77.2, 44.5 to −74.2, 46.3 Extract area for the provider's basemap archive, wider than the map's max bounds

A lines_without_live_data entry has a gap_id and selects routes by route_ids, route_types or both; the static load syncs it into core.providers. Each realtime Silver load records the last time a declared route appeared in vehicle positions or trip updates in core.route_live_observations. A declared line seen within the last 15 minutes is promoted automatically and counted like any other line. Any recorded observation also makes the health API report a degraded component <provider>_live_policy_<route> saying the configuration is outdated, so the owner can update the manifest.

Secrets never appear in a manifest; each feed names the environment variable that holds its URL or key. list-providers and scheduled jobs use active manifests only. seed-core records every manifest, so inactive state is explicit in core.providers.

How a provider reaches the public catalog

transit-ops publish-providers --default-provider <id> builds /v1/providers.json; the default provider is a required option. A provider is included only if all of these hold:

The web app discovers cities from this catalog. Providers with public.enabled=false are skipped. A readiness failure on an enabled provider raises and aborts the whole catalog build; providers.json is written only after every enabled provider and the selected default pass, so that validation failure leaves the existing catalog unchanged. publish-providers is run by an operator; no workflow runs it.

Provider IDs are always explicit inside the publisher: test_explicit_provider_ids.py walks the snapshots package syntax tree and fails on any provider_id parameter or field default. A provider without a GIS feed, such as OC Transpo, gets gis_status: not-configured from the static pipeline instead of a failure.

The web build reads the same manifests for share cards: build-og.ts renders an EN and FR home card for each provider with is_active and public.enabled, using its public labels.

Adding a provider