Match state
Every WebSocket frame carries a fullMatchState snapshot. The history backfill returns events only — to rebuild this state from the log, replay the events; each event’s entry below specifies its exact effect on state. Fields are camelCase on the wire. See the Sports overview for the conventions and cross-sport events (score_set, match_end, undo, scout_status) shared across every sport.
Score
Phase and clock
Soccer runs on a continuous clock, so there is no separate live/dead clock state.phase is the broad match segment.
Location
Pending slots
Both slots are independent and can be non-null at the same time (e.g. a penalty awarded while a VAR review is open).PendingSetPiece
OpenVar
Discipline
Display metadata
The side display names are not onMatchState. They are fixed at session creation and ride the top-level matchup {a, b} on every WS frame and on the /api/history / /api/health responses (from the session manifest). Scoring and playersOnPitch counts stay on the abstract A/B sides.
Enum values
Phase values
Zone values
zone is just which half the ball is in. Combine it with inBox (whether it’s in the penalty area) and possession (who has the ball) for the full picture:
Events
Events arrive on the WebSocket asframe.event. The type field is the discriminator; payload carries the event’s fields minus type.
All payload field names are camelCase on the wire.
Location
location — ball position update
location — ball position update
state.zone, state.inBox, and state.possession in a single press — three separate facts stated together. zone is which half the ball is in; in_box is whether it is in the penalty area; team is who has the ball. Pure context — it never changes the score, phase, or live.panic — imminent goal signal
panic — imminent goal signal
Shots and goals
shot — goal attempt on its way
shot — goal attempt on its way
missed_shot (no goal) or goal. Multiple shots can chain in a single attack — each gets its own shot + resolution. A goal can also arrive without a preceding shot (tap-ins, deflections, scrambles).missed_shot — shot did not score
missed_shot — shot did not score
shot that doesn’t result in a goal. Saved vs. blocked vs. off-target is not distinguished.goal — ball in the net
goal — ball in the net
score[team] right away. If a VAR review is open, treat the score as provisional.A goal is independent of shot — it never needs a preceding shot. state.scoreUnderReview tells you whether the score is provisional.goal_disallowed — VAR chalks off the goal
goal_disallowed — VAR chalks off the goal
score[team]. This is the normal way the score goes down. It does not close the review (it is a correction, not a resolution): only var_resolve does that.Different from undo: goal_disallowed records a real refereeing decision, while undo takes back a scout’s mistaken press.score_set — manual score correction
score_set — manual score correction
Fouls and set pieces
foul — foul committed
foul — foul committed
free_kick_awarded outside the box, penalty_awarded inside it.free_kick_awarded — free kick given
free_kick_awarded — free kick given
pendingSetPiece as a free kick. The scout asserts this explicitly — it is never derived from a foul. Stage one of a two-stage sequence: free_kick_awarded → free_kick.free_kick — free kick taken
free_kick — free kick taken
live and clears pendingSetPiece. The delivery of the awarded free kick.No payload fields.foul_rescinded — a pending set piece is taken back
foul_rescinded — a pending set piece is taken back
goal_disallowed. It takes no payload, since there is only ever one pending set piece to clear. It is a correction, not a resolution, so it does not close the review.No payload fields.corner — corner kick awarded
corner — corner kick awarded
pendingSetPiece as a corner.corner_kick — corner kick taken
corner_kick — corner kick taken
live and clears pendingSetPiece. Distinct from corner (the award): the award is the dead-ball lull before the restart; the kick is the live-ball release that ends it.penalty_awarded — penalty given
penalty_awarded — penalty given
pendingSetPiece as a penalty. Stage one of a three-stage sequence: penalty_awarded → pen_kick → pen_scored | pen_missed.pen_kick — taker stepping up
pen_kick — taker stepping up
pen_scored — penalty converted
pen_scored — penalty converted
score. No team field — it inherits from the open penalty.No payload fields.pen_missed — penalty not scored
pen_missed — penalty not scored
pendingSetPiece. No team field — it inherits from the open penalty. Whether it was saved or off-target is left to the slower official feed.No payload fields.VAR
var_review — VAR freeze
var_review — VAR freeze
openVar; if subject is "goal" or "goal_line", it also sets scoreUnderReview. The review opening is itself the signal, before any outcome.Only var_resolve closes it. Corrections that arrive while the review is open (goal_disallowed, card_rescinded, foul_rescinded, and fresh goal / penalty_awarded / red_card) take effect immediately but leave the review open, so an overturn with several effects all stays within one review until it resolves.Every frame from the review’s opening through its resolution carries the same state.openVar.varId, so you can tell which review is in progress without tracking anything client-side.var_resolve — the review closes
var_resolve — the review closes
openVar and scoreUnderReview, whatever the outcome. A review that changed nothing is just var_review → var_resolve with nothing in between; an overturn is the corrections (goal_disallowed, card_rescinded, foul_rescinded, or fresh events) followed by this resolve.No payload fields.Discipline
red_card — player sent off
red_card — player sent off
playersOnPitch[team] permanently and increments redCards[team]. A sending-off during a VAR review is a correction, not a resolution — it does not close the review; the freeze lifts only on var_resolve.A side reduced to six players cannot continue (Law 3): the match is abandoned, with phase → FINAL and live cleared. Six is the floor — a further red against a six-player side does nothing.yellow_card — caution
yellow_card — caution
yellowCards[team]. Use for second-yellow-risk tracking.card_rescinded — a card is taken back
card_rescinded — a card is taken back
goal_disallowed). A red restores a player to playersOnPitch[team] (+1, capped at 11); a yellow removes one from yellowCards[team]. A red downgraded to a yellow is card_rescinded (red) followed by yellow_card. It is a correction, not a resolution, so it does not close the review.Phase and clock
kickoff — half begins
kickoff — half begins
PREGAME → 1H, HT → 2HSets live. Carries no payload — it states one thing: the half is underway.No payload fields.half_end — half whistle
half_end — half whistle
1H → HT, 2H → FTClears live. The next kickoff moves out of the break.No payload fields.dead — ball out of play
dead — ball out of play
live. Pressed for any stoppage — throw-ins, goal-kicks, and longer breaks (serious injury, long VAR delay, cooling break) alike. Play resumes on the next live.No payload fields.live — play resumes mid-half
live — play resumes mid-half
dead stoppage mid-half. Sets live. For between-phase resumes use kickoff (it also advances the phase). For set-piece resumes use free_kick or corner_kick (they also clear pendingSetPiece).No payload fields.match_end — match over
match_end — match over
phase → FINAL. Disarms any pending phase advance. Consumers should close the WebSocket after receiving this — no further frames will arrive.No payload fields.phase — phase correction
phase — phase correction
half_end and kickoff; this event is for corrections only and should be rare.Server advisory
scout_status — liveness signal
scout_status — liveness signal
WireEvent.seq is null on these frames.Meta
undo — retract last press
undo — retract last press
undo appear in /history as raw events. A client replaying the log resolves it there: each undo cancels the most recent non-undo event.Different from goal_disallowed: undo corrects a scout’s mistake, while goal_disallowed records a real refereeing event.The scout sends no payload fields; the served payload carries the server-stamped retractsSeq — the seq of the press the undo cancelled (null when nothing remained) — on the live frame and in /history alike, so a display can strike the retracted row without replaying.