Overview
The timeline is an ordered list of events that happen during a live match —
goals, cards, shots, fouls, throw-ins, etc. Each entry follows the same shape
regardless of event type:
{
"type": "GoalWithScorer",
"context": "H",
"captions": ["47", "Mirassol SP", "Lucas Oliveira"],
"phaseCode": "2H",
"timeOffset": 47
}
The timeline is appended to as the match progresses. Pull the live event again
to receive the latest entries — it is always returned in full, ordered from
kick-off to the most recent event.
Field reference
type
A string identifying what happened. See Event types below for
the full observed list.
Many events come in two variants:
XxxWithPlayer — the data source attributes the action to a specific player
XxxWithoutPlayer — the same action, but no player is identified
The without-player variant is common early in the season for newer teams, or
during fast sequences where the source can’t reliably name the actor. Treat
both as the same event for analytic purposes; the only difference is whether
captions carries a player name.
context
Who the event belongs to:
| Value | Meaning |
|---|
H | Home team |
A | Away team |
G | Global / match-level (kick-off, half-time, full-time, etc.) |
captions
A positional array whose length and meaning depend on type:
| Shape | When it applies |
|---|
[datetime] | Match boundary events (StartOfMatch, StartOfSecondHalf) — ISO-like local timestamp |
[homeScore, awayScore] | Period boundary events (EndOfFirstHalf, EndOfMatch) |
[displayMinute, teamName] | Generic team events without an attributed player |
[displayMinute, teamName, playerName] | Player-attributed events (...WithPlayer, GoalWithScorer) |
displayMinute is a string and may include stoppage time (e.g. "45+2",
"90+5"). For sorting and computation, use timeOffset instead
— it is always a clean integer.
phaseCode
Which phase of the match the event belongs to:
| Code | Phase |
|---|
1H | First half |
2H | Second half |
ET1 | Extra time, first half |
ET2 | Extra time, second half |
PEN | Penalty shootout |
Only 1H and 2H are common; the extra-time and penalty codes only appear in
knockout fixtures that go beyond regulation.
timeOffset
Minutes elapsed since the start of the current phaseCode. This is the
canonical numeric clock — it does not reset across stoppage time, so a
displayMinute of "45+3" corresponds to a timeOffset of 48.
Period boundary events (EndOfFirstHalf) carry timeOffset: 0 and should be
treated as markers rather than positioned moments.
Event types
The list below covers every type observed across our live feed. The data source
may emit additional types we haven’t catalogued yet — clients should tolerate
unknown values rather than reject them.
Match boundaries (context: G)
| Type | captions shape | Notes |
|---|
StartOfMatch | [datetime] | Kick-off timestamp |
EndOfFirstHalf | [homeScore, awayScore] | Half-time |
StartOfSecondHalf | [datetime] | Restart timestamp |
EndOfSecondHalf | [homeScore, awayScore] | Full-time at 90’ |
EndOfMatch | [homeScore, awayScore] | Final whistle (after ET / pens if applicable) |
Restarts (context: H / A)
| Type | captions shape |
|---|
GoalKick | [minute, team] |
ThrowIn | [minute, team] |
Corner | [minute, team] |
PenaltyKick | [minute, team] |
Goals (context: H / A)
| Type | captions shape |
|---|
GoalWithScorer | [minute, team, scorer] |
GoalWithoutScorer | [minute, team] |
Shots (context: H / A)
| Type | captions shape |
|---|
ShotWithPlayer | [minute, team, player] |
ShotWithoutPlayer | [minute, team] |
ShotOnTargetWithPlayer | [minute, team, player] |
ShotOnTargetWithoutPlayer | [minute, team] |
Every shot on target is also reported as a regular shot in the same minute.
Don’t double-count when computing total shots.
Defensive actions (context: H / A)
| Type | captions shape |
|---|
TackleWithPlayer | [minute, team, player] |
TackleWithoutPlayer | [minute, team] |
FoulWithPlayer | [minute, team, player] |
FoulWithoutPlayer | [minute, team] |
OffsideWithPlayer | [minute, team, player] |
OffsideWithoutPlayer | [minute, team] |
Cards (context: H / A)
| Type | captions shape |
|---|
YellowCardWithPlayer | [minute, team, player] |
YellowCardWithoutPlayer | [minute, team] |
RedCardWithPlayer | [minute, team, player] |
RedCardWithoutPlayer | [minute, team] |
Worked example
A handful of entries from a Mirassol vs LDU Quito match:
[
{
"type": "StartOfMatch",
"context": "G",
"captions": ["07/05/2026 19:00:32"],
"phaseCode": "1H",
"timeOffset": 0
},
{
"type": "Corner",
"context": "H",
"captions": ["3", "Mirassol SP"],
"phaseCode": "1H",
"timeOffset": 3
},
{
"type": "ShotOnTargetWithPlayer",
"context": "A",
"captions": ["28", "LDU Quito", "Jose Quintero"],
"phaseCode": "1H",
"timeOffset": 28
},
{
"type": "YellowCardWithPlayer",
"context": "A",
"captions": ["45", "LDU Quito", "Gian Franco Allala"],
"phaseCode": "1H",
"timeOffset": 45
},
{
"type": "EndOfFirstHalf",
"context": "G",
"captions": ["0", "0"],
"phaseCode": "1H",
"timeOffset": 0
},
{
"type": "GoalWithScorer",
"context": "H",
"captions": ["47", "Mirassol SP", "Lucas Oliveira"],
"phaseCode": "2H",
"timeOffset": 47
}
]
Notes for implementers
- Treat
type as open. New event types may appear; render unknown ones as
generic entries rather than dropping them.
- Use
timeOffset for ordering. displayMinute (in captions[0]) is for
display only — string sorting on "45+2" vs "46" will not give correct
results.
- Player names can be empty or padded. Some sources emit names with a
leading space (e.g.
" Reinaldo"); trim before matching against rosters.
captions is positional, not keyed. Don’t rely on length alone to infer
the type — always branch on type first, then read the expected positions.