Time, clocks and timezones
There are three independent time axes in this API, and mixing them is the most common source of wrong timelines. None of them converts into another.
| Axis | Fields | Unit | What it answers |
|---|---|---|---|
| Wall time | start_date, ut, ct, occurred_at | timestamp | when did this happen in the real world |
| Match clock | clock_time, clock_status, played_time | seconds | how far into the match are we |
| Incident time | event_time, or minute + second | see below | when in the match did this incident occur |
Wall time and the tz parameter
Section titled “Wall time and the tz parameter”All dates are UTC by default and follow ISO 8601. Pass tz with an IANA timezone name to get
them converted:
curl "https://api.statscore.com/v2/events/12345?token=YOUR_TOKEN&tz=UTC"# "start_date": "2026-04-22 20:00"
curl "https://api.statscore.com/v2/events/12345?token=YOUR_TOKEN&tz=America/New_York"# "start_date": "2026-04-22 16:00"tz also converts internal timestamps such as verification times, so a response is internally
consistent - you never get a mix of zones in one payload.
The match clock
Section titled “The match clock”Available on /v2/events and /v2/events/{id}:
| Field | Meaning |
|---|---|
clock_time | time in the current period, in seconds. Resets at each period. |
clock_status | running, stopped or null |
played_time | cumulative time in seconds. Only some sports have it. |
The relationship, verified on live matches:
played_time = clock_time + the sum of completed periodsMeasured on production: a second-half match showed clock_time: 2051 (34:11) and
played_time: 4751 (79:11). The difference is 2700 seconds - exactly the 45-minute first half.
An ice-hockey match in the same sample had played_time: null entirely.
Breaks and waiting states are the other trap: Halftime, Waiting for extra time,
Waiting for penalty and every Break after … status all have status_type: live while the clock
is stopped. The status tables mark this per status.
Incident time: two schemas, two endpoints
Section titled “Incident time: two schemas, two endpoints”This is where the source documentation and production disagree, so read carefully.
| Endpoint | Time fields | Extras |
|---|---|---|
GET /v2/events/{id} → events_incidents | event_time, a "MM:SS" string | important incidents only |
GET /v2/events/{id}/important-incidents | minute + second as numbers | running home_score / away_score, occurred_at with milliseconds, ct / ut |
Verified on a finished Ekstraklasa match: events.show returned event_time: "32:21" and no
minute field; important-incidents on the same match returned minute: 94, second: 53 and the
score at that moment, with no event_time.
So the choice is not stylistic:
- building a full timeline with phases →
events.show - needing minutes, exact ordering, or the score at each incident →
important-incidents
Added time is an incident, not arithmetic
Section titled “Added time is an incident, not arithmetic”Do not compute 90+4 by comparing clock_time against a period length. Added time arrives as
incident 449 (Added time) at the end of each period.
Confirmed on Ekstraklasa:
event_time | Phase | Incident |
|---|---|---|
45:03 | 1st half | Added time |
49:01 | 1st half | Halftime |
90:01 | 2nd half | Added time |
95:04 | 2nd half | Finished regular time |
There is also no wall_clock field anywhere in the specification or in any captured payload. The
nearest equivalent is ut / ct on an incident, which is when the system recorded it - not when it
happened in the match.
One more ordering trap
Section titled “One more ordering trap”Incident 2895 (Key incident added with delay) marks an incident entered late. Its match time is
earlier than its arrival, so a timeline sorted strictly by arrival puts it in the wrong place. Sort
by id or by match time, and treat 2895 as a signal to re-sort.
- Show a match timeline - the working code
- Sync incrementally -
api.timestampas a change cursor - Coverage levels - how much data you get in the first place