/api endpoints addressed by session id alone, and the server resolves each session’s sport. What a sport determines is how to parse: which event vocabulary and state shape the feed speaks. The catalog row’s sport field names the family:
Every sport speaks the same wire shape — the differences are only in the state fields and the event vocabulary. Read this page once for the shared mechanics, then the per-sport page for the specifics.
The snapshot
Every WebSocket frame carries a full state snapshot. On the live feed you never rebuild state from events — each snapshot is complete and already computed, so a dropped frame leaves you only one event behind, and the next frame brings you back in sync. The history backfill is the one exception: it returns events only. If you need state with no live socket (a closed game, offline analysis), replay the events — each sport page specifies every event’s exact effect on state, and applying them in order rebuilds the same snapshot the live feed would have sent. See the History backfill. All field names are camelCase on the wire.The A/B side model
Teams are alwaysA or B on the wire — never by name. The display names are fixed when the session is created and ride the top-level matchup { a, b } on every frame and on the /api/history and /api/health responses, not the state snapshot. Score and every team-attributed field stay on the abstract A/B sides. See Core Concepts — the A/B side model.
How to read a sport page
Each sport page is self-contained and follows the same shape:- State — the fields in that sport’s snapshot.
- Enum values — the closed sets a field can take.
- Events — the vocabulary, grouped by topic. Each event lists its
type, payload fields, and an example.
frame.event. The type field is the discriminator; payload carries the event’s fields minus type.
Events shared across every sport
These behave the same in every sport, so they are documented once here. The per-sport pages cover only the events specific to that sport.score_set — manual score correction
score_set — manual score correction
Overwrites the derived score. Scoring continues from the new values. Used to correct a drifted score; rare during normal play.
game_end / match_end — the game is over
game_end / match_end — the game is over
Terminal: the snapshot moves to its final state and no further frames arrive. Close the connection after receiving it. Soccer names this
match_end; baseball and basketball name it game_end.No payload fields.undo — retract the last press
undo — retract the last press
Retracts the most recent scout press. Both the original press and the
undo appear in /history as raw events. A client replaying the log resolves the retraction there: each undo cancels the most recent non-undo event. Filter undo rows at the display layer.The scout sends no payload fields. The server stamps retractsSeq — the seq of the press the
undo cancelled (null when nothing remained to cancel, or on a log recorded before the stamp
existed) — onto the payload it serves, on the live frame and in the /history backfill alike,
so a display can strike the retracted row directly without replaying:scout_status — liveness advisory
scout_status — liveness advisory
Server-originated — not a scout press. Emitted by the liveness monitor when the scout’s status changes. See Core Concepts — Advisories.
seq is null on these frames, and the full snapshot is still included so no re-sync is needed.