Section 04 of 12
Concepts
This page defines the words used everywhere else: identifiers, stops versus areas, freshness, units, the response envelope, and time handling.
Identifiers#
Every object id is an opaque string of the form {network}:{kind}:{ref}, where kind is one of line, stop, area, trip, vehicle, alert and ref is the operator's own identifier, which may itself contain :. Split on the first two colons only. Examples: tbm:line:59, tbm:stop:3824, tbm:area:BEPIS66, idfm:line:C01371, idfm:area:71264, sncf:area:87581009, star:line:0006, tisseo:area:SA_1715.
Ids are stable across refreshes as long as the operator keeps its references. Ids may be passed in the path as is or URL-encoded (tbm%3Astop%3A3824); both forms work.
Stops and areas#
A stop (kind: "stop") is a physical stop point, usually one platform or one side of the street. An area (kind: "area") groups the stop points that share a name and a location, such as both platforms of a tram station. Areas have children; stops have a parent_id. Departure endpoints accept both: an area aggregates the departures of all its children, which is what most "next departures" displays want.
Lines and directions#
A Line has a code (what is printed on the vehicle), a name, a mode, colours as #RRGGBB, and directions. In list responses directions carry only id, name and headsign; GET /lines/{id} and GET /lines/{id}/stops add the ordered stops. Direction ids are 0 and 1 where the operator uses GTFS conventions, or the operator's own reference otherwise. Modes are tram, metro, bus, rail, coach, ferry, funicular, cable, other.
Freshness#
Quavsit never fabricates realtime. Each Departure carries realtime (boolean) and status; meta.freshness summarises the list:
meta.freshness | Meaning |
|---|---|
realtime | at least one item comes from a live feed |
scheduled | every item comes from the timetable |
stale | served from an expired cache because the upstream failed or its daily budget is exhausted; at most 15 minutes old |
mixed | cross-network merges where sources differ |
A scheduled departure has expected_at: null, delay_seconds: null, realtime: false and status: "unknown" unless the operator explicitly marks it on time. A stale answer also sets freshness: "stale" on the affected meta.sources[] entry and adds the header Warning: 110 quavsit "stale".
Departures and status#
status is one of on_time, delayed, early, cancelled, unknown. scheduled_at is the timetable time, expected_at the live prediction when there is one, delay_seconds their difference. Lists are sorted by expected_at falling back to scheduled_at. source names the feed the item came from (for example tbm:xtradata:horai or gtfs-rt:trip_updates).
Vehicles and estimated positions#
Vehicle.position_source is gps when the operator publishes positions, and estimated when Quavsit places the vehicle on the line shape between its previous and next stop, proportionally to the elapsed time of a realtime trip update (Tisséo in this version). Estimated positions are an approximation for display; do not use them for distance or speed calculations. Networks without either answer 404 capability_unsupported on vehicle endpoints.
Alerts#
An Alert has a severity (info, warning, critical), a title, an optional message, the line_ids and stop_ids it applies to, and starts_at/ends_at. Lists are sorted by severity, then most recently updated. Operator marketing notices are not surfaced as alerts.
The envelope#
Success responses are {"data": …, "meta": {…}}. meta always contains generated_at (RFC 3339, UTC) and units (units charged). Paginated lists add count, limit and next_cursor (null on the last page; pass it back as cursor). Data endpoints add:
{
"generated_at": "2026-09-07T12:11:03Z",
"units": 1,
"network": "tbm",
"freshness": "realtime",
"sources": [
{"id": "tbm:xtradata:horai", "fetched_at": "2026-09-07T12:10:58Z", "age_seconds": 5, "freshness": "realtime"}
],
"attribution": ["Bordeaux Métropole / TBM — Licence Ouverte 2.0"]
}Errors are {"error": {"code": "QVST1-3404", "reason": "stop_not_found", "message": "…", "details": {…}}}. reason and code are stable contracts; message is for humans and may change. See Errors.
Units#
Usage is counted in units. Every successful read costs 1 unit, except GET /journeys which costs 5, and each data event pushed on a stream which costs 1. Units are charged after a successful (2xx) response; errors cost nothing. Three headers accompany every response:
| Header | Value |
|---|---|
X-Quavsit-Units | units charged by this call |
X-Quavsit-Units-Remaining | units left in the current month, or unlimited |
X-Quavsit-Period-End | RFC 3339 instant at which the monthly counter resets |
Months are calendar months in UTC. Burst limits per minute and the monthly budget are described in Limits and pricing.
Time and time zones#
Every datetime is RFC 3339 with the offset of the network's time zone, for example 2026-09-07T14:11:03+02:00. meta.generated_at is UTC. The when parameter accepts an RFC 3339 instant (with offset) or the literal now. Timetable times past midnight are attributed to the correct service day, so a 25:10:00 GTFS time appears as 01:10:00 on the following calendar day.
Caching headers#
Responses carry Cache-Control: private, max-age=<n> where n is the TTL of the freshest source (10 to 20 seconds for realtime, 300 for static data). Static resources (networks, lines, stops, shapes) carry an ETag; send If-None-Match to receive 304 Not Modified. A 304 costs no units.