Forecast from your own inputs
A forecast for a trip this snapshot does not carry — one being planned, say.
/api/punctuality/predict Two modes, chosen by whether you supply currentDelaySeconds:
Anchored. With a current delay and a horizonStops, you get that delay shifted by the empirical drift distribution over that many stops. method reads anchored.
Prior. Without a current delay you get the marginal distribution for the route or mode — the network's punctuality for that service, with no knowledge of the specific trip. method reads prior, and horizonStops is not accepted, because a prior has no horizon to speak of.
Passing a routeId the static archive does not know is not an error: the forecast quietly backs off to mode or global, and the response carries a Warning header saying so. Read it, or you will take a global answer for a route-specific one.
Parameters
Query
| Parameter | Type | Default | Description |
|---|---|---|---|
routeId | string | — | Forecast from this route's own history. Also settles the mode when the archive knows the route. Unknown ids back off and set a |
mode | enum | — | Coarse vehicle mode, derived from the GTFS
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. |
currentDelaySeconds | number | — | The trip's delay right now, in seconds; negative is early. Supplying it switches the method from |
horizonStops | integer | 1 | How many stops ahead to forecast, 1 or more. Required with |
delayBasis | enum | departure | 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.
|
toleranceSeconds | number | 60 | The half-width of the on-time band, 0–3600. A delay within ±this counts as |
thresholdSeconds | string | — | Comma-separated delays, at most 10, to report an exceedance probability for. |
Response
data.query echoes what the model actually used — check it, since a routeId that failed to resolve will be missing its route. data.forecast is the answer, and model carries provenance.
curl "$API_BASE/api/punctuality/predict?routeId=9011001087500000¤tDelaySeconds=180&horizonStops=5&thresholdSeconds=300,600" {
"data": {
"query": {
"routeId": "9011001087500000",
"route": {
"routeId": "9011001087500000",
"agencyId": "505000000000000001",
"shortName": "875",
"type": 700
},
"mode": "bus",
"currentDelaySeconds": 180,
"horizonStops": 5,
"delayBasis": "departure",
"toleranceSeconds": 60
},
"forecast": {
"horizonStops": 5,
"horizonBand": "4-6",
"method": "anchored",
"delayBasis": "departure",
"currentDelaySeconds": 180,
"basis": "mode",
"basisKey": "bus",
"sampleSize": 2227,
"sufficientSamples": true,
"toleranceSeconds": 60,
"probability": {
"early": 0.015,
"onTime": 0.067,
"late": 0.917
},
"delaySeconds": {
"p10": 74,
"p25": 137,
"p50": 181,
"p75": 229,
"p90": 274,
"mean": 180
},
"exceedance": [
{
"thresholdSeconds": 300,
"probability": 0.057
},
{
"thresholdSeconds": 600,
"probability": 0.003
}
],
"expected": "late"
}
},
"model": {
"feedTimestamp": "2026-04-27T11:22:38.000Z",
"builtAt": "2026-08-07T12:36:57.044Z",
"delayBasis": "departure",
"tripObservations": 933,
"driftObservations": 15451,
"minSamples": 30
}
} Prior mode
No currentDelaySeconds, so no anchor and no horizon — this is the metro's punctuality in general. Note method: "prior" and how much wider the quantiles are than the anchored case above.
curl "$API_BASE/api/punctuality/predict?mode=metro" {
"data": {
"query": {
"mode": "metro",
"delayBasis": "departure",
"toleranceSeconds": 60
},
"forecast": {
"horizonStops": 1,
"horizonBand": "1",
"method": "prior",
"delayBasis": "departure",
"basis": "mode",
"basisKey": "metro",
"sampleSize": 70,
"sufficientSamples": true,
"toleranceSeconds": 60,
"probability": {
"early": 0,
"onTime": 0.943,
"late": 0.057
},
"delaySeconds": {
"p10": -10,
"p25": 0,
"p50": 4,
"p75": 22,
"p90": 47,
"mean": 14
},
"expected": "on_time"
}
},
"model": {
"feedTimestamp": "2026-04-27T11:22:38.000Z",
"builtAt": "2026-08-07T12:36:57.044Z",
"delayBasis": "departure",
"tripObservations": 933,
"driftObservations": 15451,
"minSamples": 30
}
} Errors
{ "error": "request_failed", … } `horizonStops` given without `currentDelaySeconds`, `horizonStops` below 1 or fractional, `toleranceSeconds` outside 0–3600, or an unknown `mode`/`delayBasis`.