---
title: "Live NFL/NCAAF play-by-play"
method: GET
path: "/v1/live-stats/american_football/{matchId}/plays"
tags: ["live-stats"]
---

# Live NFL/NCAAF play-by-play

`GET /v1/live-stats/american_football/{matchId}/plays`

## Request

- Base URL: `https://api.bigballsdata.com`
- URL: `https://api.bigballsdata.com/v1/live-stats/american_football/{matchId}/plays`
- Auth: one of:
  - API key in header `x-api-key`
  - HTTP bearer

Descriptive play-by-play for one match, during the game and after it
finishes. NFL, NCAAF and NCAAF FCS. **Pro plan or higher**. The shared
NFL play-by-play gate protects this route alongside the
`american_football` sport entitlement.

SOURCE, STATED RATHER THAN LEFT TO AN ORDERING. `football_plays`
carries rows from two vendors; this endpoint serves ONLY the rows
from our licensed paid aggregator. The other vendor's rows exist in
storage as derivation input and are never served; that vendor's
licence is `redistribute: no`, while the paid aggregator's
all-sports redistribution grant (2026-09-09) covers this table's
rows outright.

DIFFERENT TABLE FROM `GET /v1/nfl/games/{gameId}/plays`. That endpoint
reads `public_nfl_plays` (EPA/WP, NFL only, rebuilt nightly, keyed
on the league-standard text game id). This one reads
`football_plays` (keyed on the same match UUID every other
`/v1/live-stats/*` and `/v1/matches/*` endpoint uses), sourced from
the paid aggregator and updated while a game is in progress. The two
are never blended in one response; ask for both if you want both.

FRESHNESS. `meta.as_of` is the timestamp the freshest play last
changed; `meta.stale` says whether we would expect to have learned
something more recently than that. A feed that has stopped updating
mid-game and one that is simply quiet are indistinguishable without
those two fields.

## Path parameters

- `matchId` string, uuid, required

## Query parameters

- `scoring_only` boolean

## Response `200`

ok

- object
  - `data` object
    - `match_id` string, uuid
    - `sport` string
    - `status` 'scheduled' | 'in_progress' | 'finished'
    - `plays` object[]
      - `sequence_number` integer, nullable
      - `period` integer, nullable
      - `clock` string, nullable
      - `play_type` string, nullable
      - `description` string, nullable
      - `down` integer, nullable
      - `distance` integer, nullable
      - `yards_to_endzone` integer, nullable
      - `yards_gained` integer, nullable
      - `end_down` integer, nullable
      - `end_distance` integer, nullable
      - `end_yards_to_endzone` integer, nullable
      - `kick_distance` integer, nullable: Attempted field-goal distance in yards, on field-goal plays only. Null on every other play type, and null on a field goal whose text does not state a distance: an absence, never 0. Where a play describes a blocked kick returned by the defence, the returned yardage is NOT reported here: that number is the return, not the kick.
      - `field_goal_result` 'made' | 'missed' | 'blocked' | 'null', nullable: Outcome of a field-goal attempt. `blocked` is kept distinct from `missed` because a blocked kick is not a miss the kicker owns. Null on every play that is not a field-goal attempt. `null` is listed in the enum as well as in `nullable`: an enum without it forbids exactly the value the sentence above promises, and that is the common case (176 of 179 plays on the 2026-09-25 sample).
      - `kicker_player_id` string, uuid, nullable: BigBalls player id of the kicker on a field-goal or extra-point attempt, the same id `/v1/players/{id}` and the post-game surfaces use, so the live feed and the box score join on an id instead of on a name. NULL IS COMMON AND EXPECTED; DO NOT ASSUME 100% COVERAGE. Participant data is written on roughly 84% of plays (measured 2026-09-13: 81.5-85.8% per match across 11 matches), so this is null on the remaining ~16% even for plays whose text plainly describes a kick. It is also null when the play names no kicker, when the individual resolves to no player we carry, and when the id would be ambiguous; in that last case we return null deliberately rather than choose between two players. Treat null as "not stated", never as "no kicker", and do not fall back to parsing the name out of `description`: name matching is precisely the failure this field exists to remove. Precedence when both roles appear on one play: `field_goal_kicker` wins over `xp_kicker`. Punters and kickoff specialists are NOT folded in here; they appear in `participants` under their own roles.
      - `participants` object[]: Everyone the play names, each as a role plus a BigBalls player id: passer, rusher, receiver, tackler and the rest, on the same terms as `kicker_player_id`. Always present, but EMPTY on the ~16% of plays that carry no participant data, so `[]` means "not stated", not "nobody was involved". A member's `player_id` is null when that individual resolves to no player we carry, or would be ambiguous. Roles observed to date: passer, rusher, receiver, tackler, sacker, fumbler, recoverer, interception_returner, penalized, field_goal_kicker, xp_kicker, kickoff_kicker, kickoff_returner, punter, punt_returner. Treat the set as open; new roles may appear without a version bump.
        - `role` string
        - `player_id` string, uuid, nullable
      - `scoring_play` boolean
      - `home_score` integer, nullable
      - `away_score` integer, nullable
      - `home_win_probability` number, nullable: NFL/paid-aggregator only, and only from the 2018 season. Null is absence, never 0.5.
  - `meta` object
    - `source` string
    - `fetched_at` string, date-time
    - `cached` boolean
    - `cache_age_ms` integer
    - `as_of` string, date-time, nullable
    - `stale` boolean
    - `count` integer
    - `note` string: Present only when `plays` is empty, explaining that no play-by-play has been written for this match yet.

## Other responses

- `400`: invalid matchId, or sport mismatch (this feed only serves american_football)
- `403`: plan does not include NFL play-by-play, or sport not entitled
- `404`: match not found. An empty plays array is NOT a 404; see the 200 above.

---

[API](https://skmtc.dev/bigballsdata/apis/big-ball-sports-api.md) · [All operations](https://skmtc.dev/bigballsdata/apis/big-ball-sports-api/llms.txt) · [OpenAPI document](https://skmtc.dev/bigballsdata/apis/big-ball-sports-api/revisions/31fb54ac414e?raw)
