Skip to main content
The live snapshot is the data shape that carries real-time match state across both REST and WebSocket surfaces. Whether you poll on demand or receive pushed updates, the structure is consistent within a sportdata shape that carries real-time match state across both REST and WebSocket surfaces. Whether you poll on demand or receive pushed updates, the structure is consistent within a sport.
The snapshot schema depends on the sport. Always branch on the sport field. This page documents the soccer snapshot first, then the cricket snapshot (which has a completely different shape — no clock, phase, stats, or events; instead an innings score, batting/bowling cards, a current-over ticker, and a per-innings scorecard). The American football snapshot follows, with a count-down quarter clock, down and distance, the last play, and a per-player box_score. Other sports will follow over time; treat unknown fields as optional.

Used by

  • GET /matches/{id}/live — returns the snapshot directly
  • GET /matches/{id}/result — returns the snapshot as half_time and full_time objects
  • WebSocket snapshot and update frames — the snapshot is the data field

The soccer live snapshot object

Returned with "sport": "soccer".

Top-level fields

The snapshot schema depends on the sport. Always branch on the sport field. This page documents the soccer snapshot first, then the cricket snapshot (which has a completely different shape — no clock, phase, stats, or events; instead an innings score, batting/bowling cards, a current-over ticker, and a per-innings scorecard). The American football snapshot follows, with a count-down quarter clock, down and distance, the last play, and a per-player box_score. Other sports will follow over time; treat unknown fields as optional.

Used by

  • GET /matches/{id}/live — returns the snapshot directly
  • GET /matches/{id}/result — returns the snapshot as half_time and full_time objects
  • WebSocket snapshot and update frames — the snapshot is the data field

The soccer live snapshot object

Returned with "sport": "soccer".

Top-level fields

integer
required
Schema version. Currently 1Schema version. Currently 1.
integer
Your match id. Present on WebSocket frames for multiplexing; omitted on REST responsesYour match id. Present on WebSocket frames for multiplexing; omitted on REST responses.
object
Upstream reference ids. Clients can usually ignore this objectUpstream reference ids. Clients can usually ignore this object.
string
required
"soccer""soccer".
string
required
League or competition name, e.g. "USA MLS Next Pro League"League or competition name, e.g. "USA MLS Next Pro League".
string
required
Home team nameHome team name.
string
required
Away team nameAway team name.
string
required
Current match state: live, ht (half-time), ft (full-time), or not_startedCurrent match state: live, ht (half-time), ft (full-time), or not_started.
object
required
Match clock. See Clock belowtch clock. See Clock below.
object
required
Current score. See Score belowCurrent score. See Score below.
object
required
Decoded current game state. See Phase belowDecoded current game state. See Phase below.
object
required
Map of stat key → {"home": int, "away": int}. See StatisticsMap of stat key → {"home": int, "away": int}. See Statistics.
array | null
Timeline incidents. null if no events have occurred yet. See Events.
object
Last event-anchored ball position on the pitch. See Ball Position.
datetime
required
When this snapshot was produced, in ISO 8601 UTC.
array | null
Timeline incidents. null if no events have occurred yet. See Events.
object
Last event-anchored ball position on the pitch. See Ball Position.
datetime
required
When this snapshot was produced, in ISO 8601 UTC.

ScorScore

The current match score as {"home": int, "away": int}, with an optional shootout tally when a penalty shootout has beguncurrent match score as {"home": int, "away": int}, with an optional shootout tally when a penalty shootout has begun.

Clock

Displaying a live timer

minute:second is the clock as of as_of, not as of right now. How you turn it into a ticking timer depends on which surface you read from:
  • REST (GET /matches/{id}/live) — the server projects the clock forward to request time before responding. When running is true, minute:second is already current and as_of is set to the response time. Display minute:second as-is.
  • WebSocket snapshot and update frames — frames carry the clock as of the last provider update, so consumers must advance it themselves between frames. While running is true:
    When running is false (half-time, full-time, stoppages), do not project — display minute:second as-is. A new frame will reset the anchor when play resumes.
The clock only ticks within the current period; period transitions (e.g. 1H → HT → 2H) always arrive in a real frame, so the projected value can run uncapped through stoppage time and snaps back if the provider pauses silently.

Phase

The phase object describes what is happening on the pitch right now.

Full soccer example

The cricket live snapshot object

Returned with "sport": "cricket" from the same surfaces as the soccer snapshot — GET /matches/{id}/live and the WebSocket data field. The shape is different: an innings score, the batting and bowling cards, a current-over ticker, the last decoded incident, and a full per-innings scorecard. There is no clock, phase, stats, events, or ball.

Reading a cricket snapshot

The payload has two layers — a quick-glance live state and the full card:
  • Live, at a glance (top level): score (the current innings total), over (the over in progress), batsmen (the two at the crease), bowler (current spell), and last_event. This is everything you need for a compact live scoreboard — e.g. “West Indies 138/3 (40.1) — Jangoo 20*, Da Silva 12* — Dinusha 9-0-25-1”.
  • Full detail (scorecard): every innings of the match in order, each with its complete batting and bowling cards, fall of wickets, and an over-by-over breakdown (overs: runs in that over plus cumulative score — the data behind a worm or run-rate graph). Use this for a full scorecard view.
The top-level score/batsmen/bowler/over describe the same innings that is flagged "live": true in scorecard. They come from two separate provider feeds, so they can differ by a ball or two for a moment; the next frame reconciles them. scorecard is omitted until the match is live mid-session — limited-overs games have up to two innings, a Test up to four.
Multi-day Tests. Between days a Test is at stumps: the live snapshot freezes at the last ball — no new frames until play resumes the next day — and the catalog match object’s status becomes CLOSE_OF_PLAY (see Match status values), so the match stays visible in /matches and /matches/live rather than disappearing overnight. The snapshot’s own status (below) is the in-play state and is distinct from that catalog lifecycle status.

Top-level fields

integer
Your match id. Present on WebSocket frames.
string
required
"cricket".
string
required
Competition or match name, e.g. "West Indies vs Sri Lanka - 1st Test".
string
required
Home team name.
string
required
Away team name.
string
required
Current match state: live, ht (half-time), et (extra time in progress), shootout (penalty shootout in progress), ft (full-time — used for both regulation full-time and after extra time), or not_started.Current match state: live, ht (half-time), et (extra time in progress), shootout (penalty shootout in progress), ft (full-time — used for both regulation full-time and after extra time), or not_started.Current match state: not_started, live, innings_break, stopped (rain, bad light, tea, …), or ended.
string
required
Format: test, t20, one_day (50-over), the_hundred, or limited_overs (overs not yet known).
integer
required
Current innings number.
string
required
Side at the crease: "home" or "away".
object
required
The batting side’s innings score. See Cricket score below.
string
Raw score string from the provider; for a multi-innings match it may carry prior innings too.
object
required
Current-over ticker. See Over below.
array
required
The two batters at the crease. See Batsman below.
object
required
Current bowler’s spell figures. See Bowler below.
object
The decoded last incident. See Last event below.
array
Full per-innings card (all innings, in order). See Scorecard below. Omitted until the match is live mid-session.
datetime
required
When this snapshot was produced, in ISO 8601 UTC.

Cricket score

The batting side’s current innings total.

Over

Ticker for the over in progress.

Batsman

Each entry in batsmen describes one of the two batters at the crease.

Bowler

The current bowler’s spell figures.

Scorecard

scorecard is an array of innings — every innings of the match, in order. The live innings is flagged with "live": true; finished innings carry their final figures; innings yet to bat are present but omit score.

Last event

The decoded last incident on the field.

Full cricket example

The batting and bowling arrays above are trimmed to one or two rows for brevity; a real innings carries every batter and bowler.

The American football live snapshot object

Returned with "sport": "americanfootball" for NFL, NCAAF, and other American football competitions. It comes from the same surfaces as the soccer snapshot: GET /matches/{id}/live and the WebSocket data field. Use it to render a live scoreboard with the game clock, down and distance, the last play, team stats, and a per-player box score. The shape combines a count-down quarter clock and per-quarter scores with football-only state: timeouts, possession (down, distance, ball spot, and current drive), last_play, efficiency splits, and box_score. There is no phase, events, or ball.
home is the team hosting the game. For US-style "Away @ Home" fixtures, such as "PHI Eagles @ CHI Bears", home is the team after the @ (CHI Bears) and away is the team before it (PHI Eagles). For "Home v Away" fixtures, home is the first team. Every home/away key in the snapshot uses the same mapping: score, periods, timeouts, stats, efficiency, possession.team, last_event.team, last_play.team, box score, and player teams.
Migration: remove any home/away swap workaround. Previously, snapshots for "Away @ Home" basketball and American football fixtures reported the two sides mirrored, with the away team in home. SportriX now reports these fixtures correctly. If your integration swapped home and away for @ fixtures to compensate, remove that workaround. Otherwise your client now flips the sides. "Home v Away" fixtures are unchanged.

Top-level fields

integer
Your match id. Present on WebSocket frames.
object
Upstream reference ids. Carries fixture_id. Clients can usually ignore this object.
string
required
"americanfootball".
string
Competition name, e.g. "NFL".
string
required
Name of the team hosting the game. For "Away @ Home" fixtures, this is the team after the @.
string
required
Name of the visiting team. For "Away @ Home" fixtures, this is the team before the @.
string
required
Current game state: not_started, live, ht (half-time), stopped (play paused without ending the period), or ended. When a started game leaves the live feed, SportriX publishes a final snapshot with "status": "ended". GET /matches/{id}/live also returns this final snapshot. See Ended frames.
string
Current period: Q1, Q2, Q3, Q4, OT, OT2, and so on.
object
required
Game clock. Same fields as the soccer Clock, with "direction": "down": minute:second is the time remaining in the period. See American football clock below.
object
required
Current score as {"home": int, "away": int}.
array
Per-quarter scoring: {"label": "Q1", "home": int, "away": int}, one entry per period played.
object
Timeouts remaining as {"home": int, "away": int}.
object
Current down and distance. See Possession below.
object
The latest decoded feed card of any kind (e.g. "play in progress"). Has vc, team, code, and label, like the cricket Last event.
object
The latest completed play. See Last play below.
object
required
Map of team stat key → {"home": int, "away": int}. See the enumerations for common keys.
object
Made/attempted splits per team. See Efficiency below.
object
Fractional team stats as {"home": float, "away": float}: yards_per_play, yards_per_pass, yards_per_rush.
object
Per-player stat lines by team and section. See Box score below.
datetime
required
When this snapshot was produced, in ISO 8601 UTC.
timeouts, possession, last_play, efficiency, stats_float, and box_score are optional. Each is omitted when the provider hasn’t supplied that data for the game.

American football clock

The quarter clock counts down. clock.direction is "down", and minute:second is the time left in the period as of as_of. On WebSocket frames, while running is true, subtract the elapsed time instead of adding it:
When running is false, display minute:second as-is.

Possession

The offense’s current down and distance.

Last play

last_play is the latest completed play. It stays set while the feed moves on to the next “possession” or “play in progress” card, so you can keep showing it until the next play completes. last_event always carries the newest card.

Efficiency

Each key maps to {"home": {"made": int, "attempted": int}, "away": {...}}.

Box score

box_score holds per-player lines as {"home": {section: [line, ...]}, "away": {...}}. Only players with a line in a section appear. Each line has:
  • id: stable provider player id.
  • name: display name, e.g. "J Hurts".
  • stats: map of stat key → number. Keys depend on the section, e.g. passing has completions, attempts, yards, avg, td, int, and rating.
Sections: passing, rushing, receiving, defense, fumbles, interceptions, kick_returns, punt_returns, kicking, punting. Iterate the stats keys rather than assuming a fixed set.

Full American football example

The stats, efficiency, and box_score objects above are trimmed for brevity. A live game carries many more keys, sections, and players.

Appendix: enumerations

Snapshot sport: soccer, cricket, americanfootball. Other sports may appear in future. Branch on this field. Snapshot status — soccer: not_started, live, ht, ft. Snapshot status — cricket: not_started, live, innings_break, stopped (rain, bad light, tea, …), ended. Cricket match_type: test, t20, one_day (50-over), the_hundred, limited_overs (overs not yet known). Clock period (soccer): 1H, 2H, HT, FT (and similar period codes). Event type (soccer): goal, corner, yellow_card, red_card, penalty, substitution, shootout, event. Common soccer stat keys: shots_on_target, shots_off_target, attacks, dangerous_attacks, possession, corners, yellow_cards, red_cards. Cricket last_event.label is drawn from the provider’s incident table, e.g. runs, bye, wide, no ball, wicket, bowled, LBW, caught, stumped, run out, bowling, maiden over, end of over, duck, century, review, innings break, match ended.

Clock

Displaying a live timer

minute:second is the clock as of as_of, not as of right now. How you turn it into a ticking timer depends on which surface you read from:
  • REST (GET /matches/{id}/live) — the server projects the clock forward to request time before responding. When running is true, minute:second is already current and as_of is set to the response time. Display minute:second as-is.
  • WebSocket snapshot and update frames — frames carry the clock as of the last provider update, so consumers must advance it themselves between frames. While running is true:
    When running is false (half-time, full-time, stoppages), do not project — display minute:second as-is. A new frame will reset the anchor when play resumes.
The clock only ticks within the current period; period transitions (e.g. 1H → HT → 2H) always arrive in a real frame, so the projected value can run uncapped through stoppage time and snaps back if the provider pauses silently.

Phase

The phase object describes what is happening on the pitch right now.

Full soccer example

The cricket live snapshot object

Returned with "sport": "cricket" from the same surfaces as the soccer snapshot — GET /matches/{id}/live and the WebSocket data field. The shape is different: an innings score, the batting and bowling cards, a current-over ticker, the last decoded incident, and a full per-innings scorecard. There is no clock, phase, stats, events, or ball.

Reading a cricket snapshot

The payload has two layers — a quick-glance live state and the full card:
  • Live, at a glance (top level): score (the current innings total), over (the over in progress), batsmen (the two at the crease), bowler (current spell), and last_event. This is everything you need for a compact live scoreboard — e.g. “West Indies 138/3 (40.1) — Jangoo 20*, Da Silva 12* — Dinusha 9-0-25-1”.
  • Full detail (scorecard): every innings of the match in order, each with its complete batting and bowling cards, fall of wickets, and an over-by-over breakdown (overs: runs in that over plus cumulative score — the data behind a worm or run-rate graph). Use this for a full scorecard view.
The top-level score/batsmen/bowler/over describe the same innings that is flagged "live": true in scorecard. They come from two separate provider feeds, so they can differ by a ball or two for a moment; the next frame reconciles them. scorecard is omitted until the match is live mid-session — limited-overs games have up to two innings, a Test up to four.
Multi-day Tests. Between days a Test is at stumps: the live snapshot freezes at the last ball — no new frames until play resumes the next day — and the catalog match object’s status becomes CLOSE_OF_PLAY (see Match status values), so the match stays visible in /matches and /matches/live rather than disappearing overnight. The snapshot’s own status (below) is the in-play state and is distinct from that catalog lifecycle status.

Top-level fields

integer
Your match id. Present on WebSocket frames.
string
required
"cricket".
string
required
Competition or match name, e.g. "West Indies vs Sri Lanka - 1st Test".
string
required
Home team name.
string
required
Away team name.
string
required
Current match state: not_started, live, innings_break, stopped (rain, bad light, tea, …), or ended.
string
required
Format: test, t20, one_day (50-over), the_hundred, or limited_overs (overs not yet known).
integer
required
Current innings number.
string
required
Side at the crease: "home" or "away".
object
required
The batting side’s innings score. See Cricket score below.
string
Raw score string from the provider; for a multi-innings match it may carry prior innings too.
object
required
Current-over ticker. See Over below.
object
required
Map of stat key → {"home": int, "away": int} (integer counters). See StatisticsMap of stat key → {"home": int, "away": int} (integer counters). See Statistics.
object
Expected goals per side, {"home": float, "away": float}. Optional — omitted when the provider doesn’t supply it (common in smaller leagues)Expected goals per side, {"home": float, "away": float}. Optional — omitted when the provider doesn’t supply it (common in smaller leagues).
object
Fractional stats map — same shape as stats but with float values, for stats that are naturally percentages or ratios (e.g. passing_accuracy, crossing_accuracy in 0–1; action_area as an attacking-third share). Optional. See StatisticsFractional stats map — same shape as stats but with float values, for stats that are naturally percentages or ratios (e.g. passing_accuracy, crossing_accuracy in 0–1; action_area as an attacking-third share). Optional. See Statistics.
array
Per-minute pressure series — an array of floats in [-1, 1], oldest first. Positive values mean the home side is pressing, negative values the away side. OptionalPer-minute pressure series — an array of floats in [-1, 1], oldest first. Positive values mean the home side is pressing, negative values the away side. Optional.
object
Each team’s recent results coming into this match, as {"home": [...], "away": [...]}. See Form below. OptionalEach team’s recent results coming into this match, as {"home": [...], "away": [...]}. See Form below. Optional.
array
required
The two batters at the crease. See Batsman below.
object
required
Current bowler’s spell figures. See Bowler below.
array
Chronological list of goalscorers. See Goals below. Optional.
array
10-minute incident buckets, oldest first. See Intervals below. Optional.
array
Per-player match tallies (shots, assists, saves, …). See Players below. Optional.
object
The decoded last incident. See Last event below.
object
Ball position on the pitch. While a live animation position is streaming, ball follows it (only x/y/event set); otherwise it anchors to the last notable event (goal, shot, …) with detail and minute filled. See Ball Position.
array
Full per-innings card (all innings, in order). See Scorecard below. Omitted until the match is live mid-session.
datetime
required
When this snapshot was produced, in ISO 8601 UTC.
Fields marked optional above are omitted when the provider doesn’t supply them — smaller leagues often lack xg, momentum, and players. Guard for their presence rather than assuming they’re always set.

Cricket score

array
required
The two batters at the crease. See Batsman below.
object
required
Current bowler’s spell figures. See Bowler below.
array
Chronological list of goalscorers. See Goals below. Optional.
array
10-minute incident buckets, oldest first. See Intervals below. Optional.
array
Per-player match tallies (shots, assists, saves, …). See Players below. Optional.
object
The decoded last incident. See Last event below.
object
Ball position on the pitch. While a live animation position is streaming, ball follows it (only x/y/event set); otherwise it anchors to the last notable event (goal, shot, …) with detail and minute filled. See Ball Position.
array
Full per-innings card (all innings, in order). See Scorecard below. Omitted until the match is live mid-session.
datetime
required
When this snapshot was produced, in ISO 8601 UTC.
Fields marked optional above are omitted when the provider doesn’t supply them — smaller leagues often lack xg, momentum, and players. Guard for their presence rather than assuming they’re always set.

Cricket score

The batting side’s current innings total.

Over

Ticker for the over in progress.

Batsman

Each entry in batsmen describes one of the two batters at the crease.

Bowler

The current bowler’s spell figures.

Scorecard

scorecard is an array of innings — every innings of the match, in order. The live innings is flagged with "live": true; finished innings carry their final figures; innings yet to bat are present but omit score.

Last event

The decoded last incident on the field.
Match against code, not label. Labels are display text and may be refined over time — for example, codes that used to read "General alert" now carry their specific meaning — so any client logic that depends on the phase should key off the stable code.

Form

form decodes each team’s last matches coming into this one. Each entry describes one previous fixture, most recent first.

Goals

Each entry in goals is one scorer, in chronological order. This is the goalscorer list you’d render alongside the match score; the events array carries every incident, goals is the pre-filtered subset.

Intervals

Each entry in intervals is one 10-minute bucket of incident counts, oldest first. Buckets have a fixed per-side shape, so summing across buckets reconciles with the match counters in stats. Use this for a “shots by phase of match” or interval-based betting view without post-processing the events timeline yourself.

Players

Each entry in players is one player’s cumulative match tallies — the data behind a per-player markets view (shots, cards, assists).

Full cricket example

The batting and bowling arrays above are trimmed to one or two rows for brevity; a real innings carries every batter and bowler.

Appendix: enumerations

Snapshot sport: soccer, cricket, americanfootball. Other sports may appear in future. Branch on this field. The batting side’s current innings total.

Over

Ticker for the over in progress.

Batsman

Each entry in batsmen describes one of the two batters at the crease.

Bowler

The current bowler’s spell figures.

Scorecard

scorecard is an array of innings — every innings of the match, in order. The live innings is flagged with "live": true; finished innings carry their final figures; innings yet to bat are present but omit score.

Last event

The decoded last incident on the field.
Match against code, not label. Labels are display text and may be refined over time — for example, codes that used to read "General alert" now carry their specific meaning — so any client logic that depends on the phase should key off the stable code.

Form

form decodes each team’s last matches coming into this one. Each entry describes one previous fixture, most recent first.

Goals

Each entry in goals is one scorer, in chronological order. This is the goalscorer list you’d render alongside the match score; the events array carries every incident, goals is the pre-filtered subset.

Intervals

Each entry in intervals is one 10-minute bucket of incident counts, oldest first. Buckets have a fixed per-side shape, so summing across buckets reconciles with the match counters in stats. Use this for a “shots by phase of match” or interval-based betting view without post-processing the events timeline yourself.

Players

Each entry in players is one player’s cumulative match tallies — the data behind a per-player markets view (shots, cards, assists).

Full cricket example

The batting and bowling arrays above are trimmed to one or two rows for brevity; a real innings carries every batter and bowler.

Appendix: enumerations

Snapshot sport: soccer, cricket, americanfootball. Other sports may appear in future. Branch on this field. Snapshot status — soccer: not_started, live, ht, et (extra time), shootout, ft (regulation or after extra time)tatus — soccer: not_started, live, ht, et (extra time), shootout, ft (regulation or after extra time). Snapshot status — cricket: not_started, live, innings_break, stopped (rain, bad light, tea, …), endedcricket: not_started, live, innings_break, stopped (rain, bad light, tea, …), ended. Cricket match_type: test, t20, one_day (50-over), the_hundred, limited_overs (overs not yet known)Cricket match_type: test, t20, one_day (50-over), the_hundred, limited_overs (overs not yet known). Clock period (soccer): 1H, 2H, HT, FT, ET1, ET2 (extra-time halves), ET (break between them), AET (full time after extra time), SO (penalty shootoutlock period (soccer): 1H, 2H, HT, FT, ET1, ET2 (extra-time halves), ET (break between them), AET (full time after extra time), SO (penalty shootout). Event type (soccer): goal, corner, yellow_card, red_card, penalty, substitution, shot_on_target, shot_off_target, offside, assist, period_score (HT/FT/AET score markers), shootout (penalty-shootout kicks), event. Treat unknown types as eventEvent type (soccer): goal, corner, yellow_card, red_card, penalty, substitution, shot_on_target, shot_off_target, offside, assist, period_score (HT/FT/AET score markers), shootout (penalty-shootout kicks), event. Treat unknown types as event. Common soccer stat keys (integer counters in stats): shots_on_target, shots_off_target, attacks, dangerous_attacks, possession (percentage), corners, yellow_cards, red_cards, throw_ins, free_kicks, goal_kicks, penalties, substitutions, keeper_saves, key_passes, crossesCommon soccer stat keys (integer counters in stats): shots_on_target, shots_off_target, attacks, dangerous_attacks, possession (percentage), corners, yellow_cards, red_cards, throw_ins, free_kicks, goal_kicks, penalties, substitutions, keeper_saves, key_passes, crosses. Fractional stat keys (float values in stats_float): passing_accuracy, crossing_accuracy (both 0–1), action_area (attacking-third share, %)Fractional stat keys (float values in stats_float): passing_accuracy, crossing_accuracy (both 0–1), action_area (attacking-third share, %). Cricket last_event.label is drawn from the provider’s incident table, e.g. runs, bye, wide, no ball, wicket, bowled, LBW, caught, stumped, run out, bowling, maiden over, end of over, duck, century, review, innings break, match ended. Catalog match status (for the match object, not the live snapshot): NOT_STARTED, STARTED, CLOSE_OF_PLAY (multi-day cricket Test between days), FINISHED.Catalog match status (for the match object, not the live snapshot): NOT_STARTED, STARTED, CLOSE_OF_PLAY (multi-day cricket Test between days), FINISHED.Catalog match status (for the match object, not the live snapshot): NOT_STARTED, STARTED, CLOSE_OF_PLAY (multi-day cricket Test between days), FINISHED.

American football enumerations

Snapshot status — American football: not_started, live, ht, stopped, ended. ended is always the status of the final snapshot for a game that started. Period (American football): Q1, Q2, Q3, Q4, OT, OT2, … last_play.type: kickoff, pass_complete, pass_incomplete, pass_attempt, rush, interception, fumble, sack, punt, punt_downed, return, field_goal, field_goal_missed, field_goal_blocked, extra_point, extra_point_missed, extra_point_blocked, two_point_conversion, two_point_conversion_failed, two_point_conversion_fumbled, touchdown, safety, touchback, kneel, fair_catch, penalty_accepted, penalty_declined, out_of_bounds, turnover_on_downs, recovery. Common American football stat keys (integer counters in stats): total_yards, first_downs, passing_yards, rushing_yards, rush_attempts, plays, drives, turnovers, sacks, penalties, penalty_yards, possession_seconds. Iterate keys rather than assuming a fixed set.