> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mrdoge.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Live Timeline Feed

> Schema and event types for the in-match timeline returned with live events

## 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:

```json theme={null}
{
  "type": "GoalWithScorer",
  "context": "H",
  "captions": ["47", "Mirassol SP", "Lucas Oliveira"],
  "phaseCode": "2H",
  "timeOffset": 47
}
```

<Info>
  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.
</Info>

## Field reference

### `type`

A string identifying what happened. See [Event types](#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`](#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        |

<Info>
  Only `1H` and `2H` are common; the extra-time and penalty codes only appear in
  knockout fixtures that go beyond regulation.
</Info>

### `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]`         |

<Info>
  Every shot on target is also reported as a regular shot in the same minute.
  Don't double-count when computing total shots.
</Info>

### 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:

```json theme={null}
[
  {
    "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.
