Play-by-play API

Plays for one game in chronological order: text, type, period, clock, score after the play, scoring flags, down-and-distance for football and the athletes involved. Paginated; limit up to 1000 returns a whole game in one call. Data is aggregated from public sources and is typically 20-30 seconds behind live play (about 1 second after our source). There is no SLA.

Paths and parameters

GET/api/v1/sports/{sport}/leagues/{league}/events/{eventId}/plays

Get play-by-play. Plays in chronological order, paginated. Use `limit` up to 1000 to fetch a whole game in one call.

  • sport (path, required): Sport slug: football, basketball, baseball, hockey, soccer.
  • league (path, required): League slug, e.g. nfl, college-football, nba, mens-college-basketball, mlb, nhl, eng.1, usa.1.
  • eventId (path, required): Event (game) id, as returned by the events endpoints.
  • limit (query): Maximum plays to return (default 25, max 1000).
  • page (query): Page number (1-based).
  • enrich (query): Resolve athlete names, teams and positions for play participants (default true). Pass false for faster, id-only results.

GET/api/v1/sports/{sport}/leagues/{league}/events/{eventId}/penalties

Get penalty plays. Only the penalty plays of an event; all plays are scanned, not just one page.

  • sport (path, required): Sport slug: football, basketball, baseball, hockey, soccer.
  • league (path, required): League slug, e.g. nfl, college-football, nba, mens-college-basketball, mlb, nhl, eng.1, usa.1.
  • eventId (path, required): Event (game) id, as returned by the events endpoints.
  • enrich (query): Resolve athlete names, teams and positions for play participants (default true). Pass false for faster, id-only results.

Live example

Request

curl -H "Authorization: Bearer $RSA_API_KEY" \
  "https://www.realtimesportsapi.com/api/v1/sports/football/leagues/nfl/events/401872965/plays?limit=3"

Response captured from live data at 2026-10-05 02:10 UTC (refreshed every few minutes). Long arrays are trimmed; meta.rateLimit values are illustrative for a Free key.

Response

{
  "success": true,
  "data": [
    {
      "id": "4018729651",
      "sequenceNumber": "100",
      "text": "GAME",
      "shortText": "Game",
      "alternativeText": "GAME",
      "type": {
        "id": "70",
        "text": "Coin Toss"
      },
      "period": 1,
      "clock": {
        "value": 900,
        "displayValue": "15:00"
      },
      "homeScore": 0,
      "awayScore": 0,
      "scoringPlay": false,
      "scoreValue": 0,
      "situation": {
        "down": 0,
        "distance": 0,
        "yardLine": 0,
        "yardsToEndzone": 0
      },
      "endSituation": {
        "down": 0,
        "distance": 0,
        "yardLine": 0,
        "yardsToEndzone": 65
      },
      "yardsGained": 0,
      "athletes": [],
      "priority": false,
      "modified": "2026-10-04T16:46Z"
    },
    {
      "id": "40187296539",
      "sequenceNumber": "3900",
      "text": "D.Stevens kicks 61 yards from WAS 35 to IND 4. S.McGowan to IND 32 for 28 yards (D.Brown; P.Butler).",
      "shortText": "Drew Stevens 61 Yd Kickoff Seth McGowan 28 Yd Kickoff Return",
      "alternativeText": "D.Stevens kicks 61 yards from WAS 35 to IND 4. S.McGowan to IND 32 for 28 yards (D.Brown; P.Butler).",
      "type": {
        "id": "53",
        "text": "Kickoff",
        "abbreviation": "K"
      },
      "period": 1,
      "clock": {
        "value": 900,
        "displayValue": "15:00"
      },
      "wallClock": "2026-10-04T13:32:18Z",
      "homeScore": 0,
      "awayScore": 0,
      "scoringPlay": false,
      "scoreValue": 0,
      "situation": {
        "down": 0,
        "distance": 0,
        "yardLine": 35,
        "yardsToEndzone": 65
      },
      "endSituation": {
        "down": 1,
        "distance": 10,
        "yardLine": 68,
        "yardsToEndzone": 68
      },
      "yardsGained": 28,
      "athletes": [
        {
          "id": "5081335",
          "name": "Drew Stevens",
          "displayName": "Drew Stevens",
          "shortName": "D. Stevens",
          "position": "PK",
          "team": {
            "id": "28"
          },
          "role": "kicker",
          "type": "kicker",
          "order": 1
        },
        {
          "id": "4686468",
          "name": "Seth McGowan",
          "displayName": "Seth McGowan",
          "shortName": "S. McGowan",
          "position": "RB",
          "team": {
            "id": "11"
          },
          "role": "returner",
          "type": "returner",
          "order": 2
        },
        {
          "id": "4361577",
          "name": "Dyami Brown",
          "displayName": "Dyami Brown",
          "shortName": "D. Brown",
          "position": "WR",
          "team": {
            "id": "28"
          },
          "role": "assistedBy",
          "type": "assistedBy",
          "order": 3
        },
        "... 1 more"
      ],
      "priority": false,
      "modified": "2026-10-04T16:46Z"
    },
    {
      "id": "40187296562",
      "sequenceNumber": "6200",
      "text": "(Shotgun) D.Jones pass incomplete short left to J.Taylor (J.Kinlaw).",
      "shortText": "Daniel Jones Incomplete Pass, Intended For Jonathan Taylor",
      "alternativeText": "(Shotgun) D.Jones pass incomplete short left to J.Taylor (J.Kinlaw).",
      "type": {
        "id": "3",
        "text": "Pass Incompletion"
      },
      "period": 1,
      "clock": {
        "value": 894,
        "displayValue": "14:54"
      },
      "wallClock": "2026-10-04T13:33:01Z",
      "homeScore": 0,
      "awayScore": 0,
      "scoringPlay": false,
      "scoreValue": 0,
      "situation": {
        "down": 1,
        "distance": 10,
        "yardLine": 68,
        "yardsToEndzone": 68,
        "downDistanceText": "1st & 10 at IND 32",
        "possessionText": "IND 32"
      },
      "endSituation": {
        "down": 2,
        "distance": 10,
        "yardLine": 68,
        "yardsToEndzone": 68
      },
      "yardsGained": 0,
      "athletes": [
        {
          "id": "3917792",
          "name": "Daniel Jones",
          "displayName": "Daniel Jones",
          "shortName": "D. Jones",
          "position": "QB",
          "team": {
            "id": "11"
          },
          "role": "passer",
          "type": "passer",
          "order": 1
        },
        {
          "id": "4242335",
          "name": "Jonathan Taylor",
          "displayName": "Jonathan Taylor",
          "shortName": "J. Taylor",
          "position": "RB",
          "team": {
            "id": "11"
          },
          "role": "receiver",
          "type": "receiver",
          "order": 2
        },
        {
          "id": "4242335",
          "name": "Jonathan Taylor",
          "displayName": "Jonathan Taylor",
          "shortName": "J. Taylor",
          "position": "RB",
          "team": {
            "id": "11"
          },
          "role": "receiver",
          "type": "receiver",
          "order": 3
        },
        "... 1 more"
      ],
      "priority": false,
      "modified": "2026-10-04T16:46Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "pageSize": 3,
      "total": 184,
      "totalPages": 62,
      "hasNextPage": true,
      "hasPreviousPage": false
    },
    "rateLimit": {
      "limit": 125,
      "remaining": 124,
      "reset": 1793491200000
    }
  }
}

Fields

FieldTypeNotes
idstring
sequenceNumberstring
textstring
shortTextstring
alternativeTextstring
typeobject
periodinteger
clockobject
wallClockstring
homeScoreinteger
awayScoreinteger
scoringPlayboolean
scoreValueinteger
scoringTypestring
situationobject
endSituationobject
yardsGainedinteger
teamIdstring
athletesPlayAthlete[]
priorityboolean
modifiedstring

League support

Checked against live data on 2026-10-04: 28 available, 0 limited, 1 seasonal or not verified, 0 not available.

Available
Available
Seasonal / not verified
Available
Available
Available
Available
Available
Available
Available
Available
Available
Available
Available
Available

Code samples

curl

curl -H "Authorization: Bearer $RSA_API_KEY" \
  "https://www.realtimesportsapi.com/api/v1/sports/football/leagues/nfl/events/401872965/plays?limit=3"

JavaScript (fetch)

const res = await fetch("https://www.realtimesportsapi.com/api/v1/sports/football/leagues/nfl/events/401872965/plays?limit=3", {
  headers: { Authorization: `Bearer ${process.env.RSA_API_KEY}` }
});
const { success, data, meta } = await res.json();
console.log(data, meta.rateLimit);

Python (requests)

import os, requests

res = requests.get(
    "https://www.realtimesportsapi.com/api/v1/sports/football/leagues/nfl/events/401872965/plays?limit=3",
    headers={"Authorization": f"Bearer {os.environ['RSA_API_KEY']}"},
    timeout=10,
)
body = res.json()
print(body["data"])

MCP prompt (Claude, Cursor, ChatGPT)

Using the Realtime Sports MCP server (https://www.realtimesportsapi.com/api/mcp), call get_plays with sport "football" and league "nfl" and pick a finished game from get_events and summarize its scoring plays for NFL.

Connect the hosted MCP server first: setup guide. Each tool call counts as one API call.

Rate limits and pricing

PlanPriceCallsRateWebSocketWebhooks
Free$0125/mo (1,000 first 30 days)1/s500 msgs/moNo
Starter$29/mo ($290/yr)10,000/mo5/sShares monthly poolShares monthly pool
Growth$49/mo ($490/yr)25,000/mo10/sShares monthly poolShares monthly pool
Pro$99/mo ($990/yr)50,000/mo20/s100,000 msgs/mo25,000/mo
Scale$299/mo ($2,990/yr)500,000/mo100/s500,000 msgs/mo100,000/mo

Every successful REST call counts as one call. Over the limit you get HTTP 429 with a Retry-After header. No SLA. Full pricing.

FAQ

What does the play-by-play endpoint return?
Plays for one game in chronological order: text, type, period, clock, score after the play, scoring flags, down-and-distance for football and the athletes involved. Paginated; limit up to 1000 returns a whole game in one call.
Which leagues support play-by-play?
Verified on 2026-10-04: NFL, College Football, NBA, MLB, NHL, MLS, U.S. Open Cup, Premier League, Champions League, Europa League, FA Cup, LaLiga, Serie A, Liga MX, FIFA World Cup, Women's Super League, Women's Champions League, Conference League, English League Cup, Bundesliga, Ligue 1, NWSL, EFL Championship, World Cup Qualifying (UEFA), World Cup Qualifying (CONMEBOL), World Cup Qualifying (AFC), World Cup Qualifying (CAF), World Cup Qualifying (CONCACAF). Seasonal or not verified: Men's College Basketball.
Is it free to try?
Yes. The Free plan is $0 with 125 calls per month (1,000 in the first 30 days) at 1 request per second, no card required. Every successful call counts as one call.
How fresh is the data?
Data is aggregated from public sources and is typically 20-30 seconds behind live play (about 1 second after our source). There is no SLA.
Can I get updates pushed instead of polling?
Webhooks are included on every paid plan (Starter, Growth, Pro, Scale). WebSocket is included on paid plans, and the Free plan gets a 500-message monthly preview.