Nothing is synthesised
A stop time event may carry a delay with no absolute time. Deriving one from the other needs the scheduled timetable, which this API does not load. You get what the feed gave.
A GTFS-realtime stop time event has three optional parts: a delay in seconds, an
absolute time, and an uncertainty. A feed may send any combination. The
obvious convenience — when only one of delay and time is present, compute the other — is one this
API deliberately does not offer.
What this looks like in practice
In this capture SL is generous: all 16,502 stop time events that exist carry both a
delay and an absolute time, so you will not actually hit the delay-only
case here. It remains a real shape in the format, and a client that assumes time is
always present will break against a feed that is less forthcoming.
{
"stopSequence": 6,
"stopId": "9022050000778004",
"scheduleRelationship": "SCHEDULED",
"arrival": {
"delay": 9,
"time": { "epoch": 1777288329, "iso": "2026-04-27T11:12:09.000Z" },
"uncertainty": 0
},
"departure": {
"delay": 100,
"time": { "epoch": 1777288420, "iso": "2026-04-27T11:13:40.000Z" },
"uncertainty": 0
}
} Stop arrivals makes the distinction explicit rather than making
you infer it. Every call carries hasPredictedTime: false means the feed
gave no clock time, so the call sorts last instead of being placed at a computed
position it has not earned.
The other shape: nothing at all
A stop can also carry no prediction whatsoever. All 17 of those in this capture are
SKIPPED stops — the vehicle is not calling there, so there is nothing to predict, and
the arrival and departure keys are absent entirely rather than present
and empty.
{
"stopSequence": 28,
"stopId": "9022050012081001",
"scheduleRelationship": "SKIPPED",
"stop": {
"stopId": "9022050012081001",
"name": "Åkermyntan",
"latitude": 59.379163,
"longitude": 17.815768,
"locationType": 0,
"parentStation": "12081",
"platformCode": "1"
}
}
This is the one case where an absent prediction carries real information: paired with
scheduleRelationship: "SKIPPED" it means “this service is not stopping
here”, which is worth showing a passenger. See
get trip update for the full example.
What else is not invented
- Route and stop names. They come from the static join. A trip with no match in the archive keeps exactly the fields the feed sent — no partial or guessed enrichment. More →
- Positions. A vehicle with no
positionis omitted from GeoJSON output and counted inmeta.omittedWithoutPosition, rather than being placed at0,0or at its last known stop. - The route list. List routes reports routes appearing in the feed, not SL's catalogue — 369 here, against 7,880 in the archive.
- Trip-level delay. Not one trip in this capture reports one, and the API does not aggregate one from the stop time events. The events are right there if you want to do that yourself; the point is that the API will not pass off a derived figure as a reported one.
The one derived field in the API is delayStatus on a trip, and it is derived purely
from the trip's own delay — early below −60 seconds, late
above +60, on_time between. When delay is absent,
delayStatus is absent too, rather than defaulting to on_time.