Realtime/SL

Network baseline

How punctual the network is right now, as a distribution and a histogram.

GET /api/punctuality/baseline

The cross-section rather than a forecast: the delay at every live trip's next call, optionally sliced to a route or mode. This is the distribution predict falls back to when it has no anchor.

sufficientSamples tells you whether the slice cleared the sample floor of 30. When it did not, basis will show that the answer came from a coarser slice than you asked for — so always read basis and basisKey rather than assuming you got what you requested.

histogramMinutes bins delays into whole minutes across ±30, with anything beyond folded into the end bins so the counts always sum to sampleSize. Empty bins are omitted.

Parameters

Query

ParameterTypeDefaultDescription
routeIdstring

Slice to one route. Unknown ids back off and set a Warning header.

modeenum

Coarse vehicle mode, derived from the GTFS route_type. Selects the slice to forecast from when no route is given, or when the route has too few samples.

trammetrorailbusferrycablefuniculartaxiother

Only four modes carry trips in this capture: bus (791), metro (70), tram (53) and ferry (19). The other five match nothing and fall back to the global slice.

delayBasisenumdeparture

Whether to read each call's delay from its departure or its arrival event. In this capture the two are usually close but not identical — a vehicle can arrive on time and leave late.

departurearrival

toleranceSecondsnumber60

The half-width of the on-time band, 0–3600. A delay within ±this counts as on_time; outside it is early or late. Widen it to match your own definition of punctual.

Response

A single data object plus model. counts and share split the sample into early/onTime/late at your tolerance; delaySeconds gives the quantiles. Both share and delaySeconds are omitted entirely when the slice is empty.

GET /api/punctuality/baseline?mode=bus
curl "$API_BASE/api/punctuality/baseline?mode=bus"
200 · application/json
{
  "data": {
    "basis": "mode",
    "basisKey": "bus",
    "delayBasis": "departure",
    "toleranceSeconds": 60,
    "sampleSize": 791,
    "sufficientSamples": true,
    "counts": {
      "early": 23,
      "onTime": 374,
      "late": 394
    },
    "share": {
      "early": 0.029,
      "onTime": 0.473,
      "late": 0.498
    },
    "delaySeconds": {
      "p10": 0,
      "p25": 10,
      "p50": 60,
      "p75": 148,
      "p90": 281,
      "min": -471,
      "max": 1262
    },
    "histogramMinutes": [
      {
        "minute": -8,
        "trips": 1
      },
      {
        "minute": -4,
        "trips": 2
      },
      {
        "minute": -3,
        "trips": 2
      },
      {
        "minute": -2,
        "trips": 12
      },
      {
        "minute": -1,
        "trips": 22
      },
      {
        "minute": 0,
        "trips": 267
      },
      {
        "minute": 1,
        "trips": 180
      },
      {
        "minute": 2,
        "trips": 109
      }
    ]
  },
  "model": {
    "feedTimestamp": "2026-04-27T11:22:38.000Z",
    "builtAt": "2026-08-07T12:36:57.044Z",
    "delayBasis": "departure",
    "tripObservations": 933,
    "driftObservations": 15451,
    "minSamples": 30
  }
}
Captured from a local instance — this endpoint is not on the public API. Arrays trimmed for readability — $.data.histogramMinutes: showing 8 of 21.

Errors

400
{ "error": "request_failed", … }

`toleranceSeconds` outside 0–3600, or an unknown `mode`/`delayBasis`.