Historical data
Headcode retains normalised service data for 13 months, so you can look back at what ran on a past day — not just what’s running now. Two capabilities expose this history:
- Service-by-date discovery — list past services for a date, then drill into any one.
- Historical station boards — an arrivals/departures board for a past day, with aimed, actual, and last-known expected times.
Both are the read-side counterparts to the live service and board endpoints, and reuse the same response shapes so you can share parsing code.
Discover past services by date
Section titled “Discover past services by date”Pass a date to the service list endpoint without a uid to list the services that ran on that day, optionally filtered:
GET /v1/services?date=2026-05-14&toc=GR&origin=KGX&limit=20| Parameter | Description |
|---|---|
date | Scheduled start date (YYYY-MM-DD), required |
toc | Two-character ATOC operator code |
origin | Service origin — a TIPLOC or any station identifier (CRS, etc.) |
destination | Service destination — a TIPLOC or any station identifier |
headcode | Four-character headcode |
limit / offset | Pagination, default 20, max 100 |
The response is a paginated envelope. Each row carries the service’s identity plus its origin and destination calling points with scheduled times — enough to display a result and follow up for detail:
{ "services": [ { "rid": "202605141A45", "uid": "C12345", "ssd": "2026-05-14", "toc_code": "GR", "calling_points": [ { "location_type": "OR", "tiploc": "KNGX", "public_departure": "08:00" }, { "location_type": "DT", "tiploc": "EDINBUR", "public_arrival": "12:20" } ] } ], "total": 142, "limit": 20, "offset": 0}Use the rid to fetch full detail — calling points, formation, associations, actual times — from the unchanged detail endpoint:
GET /v1/services/202605141A45See Service lookup for more on the detail endpoint.
Historical station boards
Section titled “Historical station boards”Past-day boards have their own dedicated endpoints under a /history path segment. date is required:
GET /v1/stations/KGX/history/departures?date=2026-05-14GET /v1/stations/KGX/history/arrivals?date=2026-05-14GET /v1/stations/KGX/history/board?date=2026-05-14The live /departures, /arrivals, and /board endpoints are now purely “now” boards and no longer accept date. The history response shape is identical to the live board, so each row exposes:
- Aimed times — the scheduled public (
scheduled_public) and working (scheduled_working) times. - Actual times — the recorded
actualtime where the service ran. - Last-known expected times — the final
estimated/working_estimatedforecast. - Platform, operator, and delay flags.
The same toc, platform, calling_at, and destination filters as the live board apply (the combined /history/board, like the live board, has no calling_at filter).
Intra-day time window
Section titled “Intra-day time window”A history board defaults to the whole day. To narrow it, pass from and to as 24-hour wall-clock times (HH:MM):
| Parameter | Meaning |
|---|---|
from | Inclusive window start (HH:MM), defaults to 00:00 |
to | Inclusive window end (HH:MM), defaults to end of day |
GET /v1/stations/KGX/history/departures?date=2026-05-14&from=08:00&to=10:00returns departures between 08:00 and 10:00 on that day. A malformed time, or a to earlier than from, returns a 400.
Caching
Section titled “Caching”Past-day boards are effectively immutable, so history responses are fully cacheable. Each response carries a Last-Modified, a strong ETag, and Cache-Control: public, max-age=…. Replay the Last-Modified as If-Modified-Since, or the ETag as If-None-Match, and a still-current board returns a bare 304 Not Modified. The data stays revalidatable rather than immutable, so a recent day that later receives corrections is picked up once the max-age expires. (Live boards are unchanged and set no Cache-Control.)
Retention
Section titled “Retention”Data is retained for 13 months. A date older than the retention window returns a 400 stating the earliest retained date, rather than an empty success:
{ "status": 400, "code": "HEADCODE.GENERAL.BAD_REQUEST", "detail": "Date is outside the retention window; the earliest retained date is 2025-05-12."}What’s retained, and what isn’t
Section titled “What’s retained, and what isn’t”Headcode keeps each service’s final state: aimed times, actual times, and the last-known expected times. It does not retain how a forecast evolved through the day — the sequence of changing ETAs as Darwin updated them. “Did it run, and was it on time?” is fully answered by the final state; forecast-accuracy or ETA-replay products are out of scope.
This is comparable to TransportAPI’s train/actual_journeys and train/station_actual_journeys endpoints.