API Documentation

Welcome to the Realtime Sports API documentation. This API provides real-time access to NFL and College Football data including events, plays, penalties, teams, officials, and athletes.

Base URL

https://realtimesportsapi.com

Authentication

All API requests require authentication using JWT tokens. Include your API key in the Authorization header:

Authorization: Bearer YOUR_API_KEY

Note: Get your API key from the dashboard.

Rate Limits

Rate limits vary by subscription tier. Monthly call limits reset at the start of each month.

TierCalls/MonthCalls/Second
Free125 (1,000 first month)1
Starter10,0005
Pro50,00020
Scale500,000100+

API Structure

The API follows a hierarchical structure: Sport → League → Resource

/api/v1/sports
  /{sport}/leagues
    /{league}
      /teams                    # All teams in league
      /athletes                 # All athletes (paginated)
        /{athleteId}            # Single athlete
      /seasons                  # Historical seasons
        /{year}                 # Season details
      /events                   # All events
        /live                   # Live events only
        /{eventId}              # Single event
          /plays                # Play-by-play (paginated)
          /penalties            # Penalties only

Sports & Leagues

GET/v1/sports

Get all available sports.

Example Request

curl -X GET "https://realtimesportsapi.com/api/v1/sports" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

{
  "success": true,
  "data": [
    {
      "id": "20",
      "name": "Football",
      "slug": "football",
      "displayName": "Football"
    },
    {
      "id": "40",
      "name": "Basketball",
      "slug": "basketball",
      "displayName": "Basketball"
    }
  ]
}
GET/v1/sports/:sport/leagues

Get all leagues for a specific sport.

Example Request

curl -X GET "https://realtimesportsapi.com/api/v1/sports/football/leagues" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

{
  "success": true,
  "data": [
    {
      "id": "28",
      "name": "National Football League",
      "slug": "nfl",
      "abbreviation": "NFL",
      "currentSeason": 2025
    },
    {
      "id": "35",
      "name": "NCAA Football",
      "slug": "college-football",
      "abbreviation": "NCAA"
    }
  ]
}

Teams

GET/sports/{sport}/leagues/{league}/teams

Get all teams for a league.

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/baseball/leagues/mlb/teams" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response Includes

  • ✓ Team names, abbreviations, slugs
  • ✓ Logos (default & dark theme, proxied)
  • ✓ Team colors (hex codes)
  • ✓ Venue information (stadium, capacity)
  • ✓ Records and standings
GET/sports/{sport}/leagues/{league}/teams/{teamId}/roster

Current active roster for a team, grouped by position plus a flat list.

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/teams/12/roster" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response Includes

  • ✓ Position groups plus a flat athletes list
  • ✓ Per player: id, name, jersey, position, age, height/weight
  • ✓ Experience, status, and headshot (proxied)
GET/sports/{sport}/leagues/{league}/teams/{teamId}/depthchart

Team depth chart: formations → positions → rank-ordered athletes (with names).

Query Parameters

  • season - Season year (defaults to current year)

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/teams/12/depthchart?season=2024" \
  -H "Authorization: Bearer YOUR_API_KEY"

Injuries, News & Transactions

GET/sports/{sport}/leagues/{league}/injuries

Current injuries grouped by team (plus a flat list). Each entry includes player, status, fantasy status, body part, and date.

Note: Populated in-season. Expect a short/empty list in the deep off-season; the NFL report fills in once training camps open.

Query Parameters

  • team - Filter to a single team id

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/basketball/leagues/nba/injuries" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET/sports/{sport}/leagues/{league}/player-availability

Coverage note: the league-wide response is truncated by our data provider to the 25 most recent records per team (limit/page have no effect on it). For a team's complete current report — one latest record per athlete, including a structured statusType (e.g. INJURY_STATUS_IR) — pass ?team={teamId} on this endpoint or on /injuries. Entries with status Active are informational news notes, not availability designations; filter with ?status=.

Normalized per-player availability. Each player carries a single availability value — OUT, DOUBTFUL, QUESTIONABLE, PROBABLE, DAY_TO_DAY, INJURED_RESERVE, SUSPENDED, AVAILABLE, or UNKNOWN — so you can gate lineups without parsing free-text injury notes.

Query Parameters

  • team - Filter to a single team id
  • status - Filter to a normalized availability value (e.g. OUT)

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/player-availability?status=OUT" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET/sports/{sport}/leagues/{league}/player-availability/history

League-wide feed of availability changes, newest first. We snapshot the injury report every 30 minutes and record a transition whenever a player's designation, injury type, team, or report date changes — including when a player drops off the report (changeType: "cleared"). Each record carries previousAvailability so you can see e.g. QUESTIONABLE → OUT. History begins from the date tracking was enabled (NFL: Aug 2026); it is not backfilled.

Query: ?team={teamId}, ?status=OUT (normalized value), ?since=ISO, ?limit= (max 500). Covers NFL, college football, NBA, MLB, NHL. Records observed from Sep 2026 onward also carry the season context at observation time — seasonYear, seasonType (1 pre / 2 regular / 3 post), and week for weekly leagues (NFL/CFB) — so a change can be joined to that week's schedule via teamId + week on the events endpoints.

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/player-availability/history?status=OUT&since=2026-09-01T00:00:00Z" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

{
  "success": true,
  "data": [
    {
      "athleteId": "3886633",
      "name": "Hjalte Froholdt",
      "position": "C",
      "teamId": "22",
      "teamName": "Arizona Cardinals",
      "availability": "OUT",
      "previousAvailability": "QUESTIONABLE",
      "status": "Out",
      "previousStatus": "Questionable",
      "reason": "Hamstring",
      "detail": "Froholdt was ruled out Friday...",
      "reportDate": "2026-09-04T21:10Z",
      "observedAt": "2026-09-04T21:30:02.118Z",
      "seasonYear": 2026,
      "seasonType": 2,
      "week": 1,
      "changeType": "change"
    }
  ]
}
GET/sports/{sport}/leagues/{league}/athletes/{athleteId}/availability-history

Full designation timeline for one player (newest first) plus their current state. Same record shape as the league feed. Query: ?from=ISO, ?to=ISO, ?limit=.

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/athletes/3886633/availability-history" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET/sports/{sport}/leagues/{league}/transactions

Recent transactions newest-first: signings, IL/DL moves, call-ups, releases, and trades. Each item includes date, description, and the team involved.

Query Parameters

  • limit - Number of transactions (default: 25)
  • page - Page through history
  • team - Filter to a single team id
  • season - Season year (defaults to current season)

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/baseball/leagues/mlb/transactions?limit=25" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET/sports/{sport}/leagues/{league}/news

Latest news articles for a league: headline, description, images, link, published date, and the athletes/teams the article is tagged with (stable ids that join to /athletes/{id} and /teams/{id}). The provider exposes a rolling window of the ~50 most recent articles per league — for anything older, use /news/history below.

Query Parameters

  • limit - Number of articles (default: 10, max 50)
  • team - Filter to a single team id
  • athlete - Filter to articles tagged with an athlete id
  • since / from, to - ISO date bounds on published (within the rolling window)
  • page - 1-based page within the window

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/news?athlete=3139477&limit=5" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET/sports/{sport}/leagues/{league}/news/history

Archived news articles, newest first — same article shape as /news. We archive each league's feed hourly, so unlike the live endpoint this one is queryable by arbitrary date range. The archive accumulates from Sep 2, 2026 (the provider offers no earlier history, so it is not backfilled). Covers NFL, college football, NBA, MLB, NHL.

Query Parameters

  • from, to - ISO date bounds on published
  • team - Filter to articles tagged with a team id
  • athlete - Filter to articles tagged with an athlete id
  • limit - Articles per page (default: 25, max 100)
  • page - 1-based page

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/news/history?athlete=3139477&from=2026-09-02T00:00:00Z" \
  -H "Authorization: Bearer YOUR_API_KEY"

Athletes

GET/sports/{sport}/leagues/{league}/athletes

Get all athletes for a league (paginated).

Note: MLB has 36,000+ athletes. Always use pagination!

Query Parameters

  • page - Page number (default: 1)
  • limit - Results per page (default: 25)

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/baseball/leagues/mlb/athletes?page=1&limit=25" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET/sports/{sport}/leagues/{league}/athletes/{athleteId}

Get single athlete by ID.

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/baseball/leagues/mlb/athletes/30836" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response Includes

  • ✓ Full name, position, jersey number
  • ✓ Headshot (proxied image)
  • ✓ Team affiliation
  • ✓ Age and stats availability

Statistics Scoping (Query Parameters)

  • season - Scope statistics to a season year (e.g. 2024)
  • seasonType - 1=preseason, 2=regular, 3=postseason (requires season)
  • Omit both for career/current totals.
curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/athletes/3139477?season=2024&seasonType=2" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET/sports/{sport}/leagues/{league}/athletes/search

Find players by name, scoped to the sport/league.

Query Parameters

  • query - Player name to search for (required)
  • limit - Max results (default: 25)

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/athletes/search?query=mahomes" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET/sports/{sport}/leagues/{league}/athletes/{athleteId}/gamelog

Per-game (and per-week) stat lines for an athlete in a season.

Query Parameters

  • season - Season year (required)
  • week - Filter to a single week number
  • seasonType - 1=preseason, 2=regular, 3=postseason

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/athletes/3139477/gamelog?season=2024&week=10" \
  -H "Authorization: Bearer YOUR_API_KEY"

Seasons

GET/sports/{sport}/leagues/{league}/seasons

Get all seasons for a league (historical data).

Note: MLB has 150+ seasons dating back to 1870s!

Query Parameters

  • page - Page number (default: 1)
  • limit - Results per page (default: 25)

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/seasons?limit=5" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET/sports/{sport}/leagues/{league}/seasons/{year}

Get details for a specific season.

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/baseball/leagues/mlb/seasons/2025" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response Includes

  • ✓ Season year and display name
  • ✓ Current season type (preseason, regular, postseason, offseason)
  • ✓ Start and end dates
  • ✓ All season types with dates

Events

GET/sports/{sport}/leagues/{league}/events

Get all events for a league.

Query Parameters

  • limit - Results per page (default: 50)

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/events?limit=10" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET/sports/{sport}/leagues/{league}/events/live

Get currently live events only.

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/events/live" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

{
  "success": true,
  "data": [
    {
      "id": "401772982",
      "name": "Buffalo Bills at Denver Broncos",
      "shortName": "BUF @ DEN",
      "date": "2026-01-17T21:30Z",
      "status": {
        "state": "in",
        "period": 3,
        "clock": "10:45"
      },
      "homeTeam": {
        "id": "7",
        "name": "Denver Broncos",
        "abbreviation": "DEN",
        "logo": "/api/images/proxy?url=...",
        "color": "0a2343",
        "score": 21
      },
      "awayTeam": {
        "id": "2",
        "name": "Buffalo Bills",
        "abbreviation": "BUF",
        "score": 17
      },
      "venue": {
        "name": "Empower Field at Mile High",
        "city": "Denver",
        "state": "CO"
      }
    }
  ]
}
GET/sports/{sport}/leagues/{league}/events/{eventId}

Get single event with full details.

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/events/401772982" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET/sports/{sport}/leagues/{league}/seasons/{year}/schedule

Events for a season, optionally by week. Supported for week-based leagues (NFL, college football). Upcoming games for future seasons are served live when not yet stored (meta.source is synced or live).

Query Parameters

  • week - Week number (optional)
  • seasonType - 1=preseason, 2=regular (default), 3=postseason
  • includeOdds - true to attach current odds

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/seasons/2026/schedule?week=1" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET/sports/{sport}/leagues/{league}/seasons/{year}/weeks

List of weeks for a season (number, seasonType, label, start/end dates). NFL and college football only.

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/seasons/2026/weeks" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET/sports/basketball/leagues/mens-college-basketball/seasons/{year}/tournament

The 68-team NCAA tournament (March Madness) for a season. Each game is annotated with region, round, and a First Four flag; NIT/CBI games are excluded.

Query Parameters

  • round - Filter by round (e.g. First Four, 1st Round, Sweet 16)
  • region - Filter by region (e.g. South)
  • firstFour - true for only the 4 play-in games, false for the 63 main-bracket games

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/basketball/leagues/mens-college-basketball/seasons/2025/tournament?firstFour=false" \
  -H "Authorization: Bearer YOUR_API_KEY"

Plays & Pagination

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

Get plays for an event (paginated - games can have 200+ plays).

Query Parameters

  • page - Page number (default: 1)
  • limit - Plays per page (default: 25, max: 100)
  • enrich - Resolve athlete id/name/team/position (default: true). Set false for a faster response with only role/order.

Each play's athletes[] identifies the players involved with id, name, position, and team, alongside their role (passer, rusher, tackler, kicker, …) and order — useful for score-event attribution and fantasy analytics.

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/events/401772982/plays?page=1&limit=25" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

{
  "success": true,
  "data": [
    {
      "id": "40177298265",
      "text": "B.Nix pass to P.Bryant for 12 yards",
      "type": { "id": "24", "text": "Pass Reception" },
      "period": 1,
      "clock": { "displayValue": "14:56" },
      "situation": {
        "down": 1,
        "distance": 10,
        "yardLine": 26,
        "downDistanceText": "1st & 10 at DEN 26"
      },
      "yardsGained": 12,
      "athletes": [
        { "id": "4426338", "name": "Bo Nix", "position": "QB", "team": { "id": "7" }, "role": "passer", "order": 1 },
        { "id": "4373678", "name": "Pat Bryant", "position": "WR", "team": { "id": "7" }, "role": "receiver", "order": 2 }
      ]
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "pageSize": 25,
      "total": 213,
      "totalPages": 9,
      "hasNextPage": true
    }
  }
}
GET/sports/{sport}/leagues/{league}/events/{eventId}/penalties

Get penalties only from an event.

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/events/401772982/penalties" \
  -H "Authorization: Bearer YOUR_API_KEY"
GET/sports/{sport}/leagues/{league}/events/{eventId}/roster

Game-specific rosters: every player on each team's game roster with per-game availability flags — starter, didNotPlay, and active (on the field; live games only). The provider publishes game rosters at kickoff (the endpoint returns 404 ROSTER_NOT_PUBLISHED before then), so this is a kickoff-onward and historical source — for pre-game designations use /player-availability. Works for completed games, so it doubles as historical starter/DNP data. Player id is the same stable athlete ID used by /plays, /boxscore, and /athletes/{id}.

Query: ?team={teamId} for one side, ?starters=true for starters only, ?enrich=false to skip athlete lookups (ids + flags only).

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/events/401671733/roster?starters=true" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

{
  "success": true,
  "data": {
    "eventId": "401671733",
    "teams": [
      {
        "team": { "id": "18", "name": "New Orleans Saints", "abbreviation": "NO" },
        "homeAway": "home",
        "summary": { "total": 67, "starters": 22, "didNotPlay": 1 },
        "players": [
          {
            "id": "13971",
            "name": "Cameron Jordan",
            "jersey": "94",
            "position": "DE",
            "starter": true,
            "didNotPlay": false,
            "active": false
          }
        ]
      }
    ]
  }
}
GET/sports/{sport}/leagues/{league}/events/{eventId}/winprobability

Per-play win probability series for an event, plus drive summaries. Each point carries a playId that joins to /plays, so you can compute win-probability-added per play. Drives include result, yards, time elapsed, start/end field position and the list of play IDs. Pass ?drives=false to omit drives.

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/events/401671733/winprobability" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

{
  "success": true,
  "data": {
    "eventId": "401671733",
    "winProbability": [
      { "playId": "401671733237", "homeWinPercentage": 0.5033, "awayWinPercentage": 0.4967, "tiePercentage": 0 }
    ],
    "drives": [
      {
        "id": "4016717331",
        "team": { "id": "1", "name": "Atlanta Falcons", "abbreviation": "ATL" },
        "description": "6 plays, 17 yards, 1:58",
        "result": "PUNT",
        "isScore": false,
        "yards": 17,
        "offensivePlays": 6,
        "start": { "period": 1, "clock": "15:00", "yardLine": 74, "text": "ATL 26" },
        "end":   { "period": 1, "clock": "13:02", "yardLine": 57, "text": "ATL 43" },
        "playIds": ["4016717331", "..."]
      }
    ]
  }
}

Betting & Odds

Get current odds (spread, moneyline, over/under), odds history for line movement, and real-time odds updates via webhooks and WebSockets. Ideal for betting apps, sportsbooks, and sharp tools.

GET/sports/{sport}/leagues/{league}/events/{eventId}/odds

Current betting odds for an event: spread, moneyline, and over/under. Same shape used when you request includeOdds=true on event or list endpoints.

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/events/401772982/odds" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

{
  "success": true,
  "data": {
    "spread": { "line": -3.5, "home": -110, "away": -110 },
    "moneyline": { "home": -180, "away": 150 },
    "overUnder": { "total": 48.5, "over": -110, "under": -110 },
    "provider": "ESPN",
    "updatedAt": "2026-01-28T20:00:00Z"
  }
}

Odds on event and list endpoints

Avoid N+1 calls by requesting odds with events in one go. Add includeOdds=true to:

  • Single event: GET .../events/{eventId}?includeOdds=true
  • Live events: GET .../events/live?includeOdds=true
  • League events: GET .../events?includeOdds=true
  • Season schedule: GET .../seasons/{season}/schedule?includeOdds=true (optional with week)

Each event in the response will include an odds property when available. Using includeOdds=true may increase latency and usage.

GET/sports/{sport}/leagues/{league}/events/{eventId}/odds/history

Historical odds for line movement, closing line, or movement alerts. Use limit (default 100) to control how many history entries are returned.

curl "https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/events/401772982/odds/history?limit=50" \
  -H "Authorization: Bearer YOUR_API_KEY"

Real-time odds updates

When lines move, get notified without polling:

  • Webhook: Subscribe to event.odds_change. Your endpoint receives a POST when odds for that event change.
  • WebSocket: Listen for event_odds_change (any paid plan). Payload includes event id and updated odds.

Configure webhooks in your dashboard. See the Webhooks and WebSockets sections below for subscription details.

Example: Fetch live games with odds

// Live NFL games with current odds (one request)
const res = await fetch(
  'https://realtimesportsapi.com/api/v1/sports/football/leagues/nfl/events/live?includeOdds=true',
  { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }
);
const { data: games } = await res.json();
games.forEach(g => {
  console.log(g.name, g.odds?.spread?.line, g.odds?.overUnder?.total);
});

JavaScript Example

const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://realtimesportsapi.com/api/v1';

// Discover sports and leagues
async function discoverAPI() {
  // Get all sports
  const sports = await fetch(`${BASE_URL}/sports`, {
    headers: { 'Authorization': `Bearer ${API_KEY}` }
  }).then(r => r.json());
  
  console.log('Sports:', sports.data);
  
  // Get football leagues
  const leagues = await fetch(`${BASE_URL}/sports/football/leagues`, {
    headers: { 'Authorization': `Bearer ${API_KEY}` }
  }).then(r => r.json());
  
  console.log('Leagues:', leagues.data);
}

// Get live NFL games
async function getLiveNFLGames() {
  const response = await fetch(
    `${BASE_URL}/sports/football/leagues/nfl/events/live`,
    { headers: { 'Authorization': `Bearer ${API_KEY}` } }
  );
  
  const data = await response.json();
  
  if (data.success) {
    console.log('Live games:', data.data);
  }
}

// Get plays with pagination
async function getPlays(eventId, page = 1) {
  const response = await fetch(
    `${BASE_URL}/sports/football/leagues/nfl/events/${eventId}/plays?page=${page}&limit=25`,
    { headers: { 'Authorization': `Bearer ${API_KEY}` } }
  );
  
  const data = await response.json();
  
  console.log(`Page ${page}: ${data.data.length} plays`);
  console.log(`Total: ${data.meta.pagination.total} plays`);
  
  return data;
}

// Get all plays (all pages)
async function getAllPlays(eventId) {
  const allPlays = [];
  let page = 1;
  let hasMore = true;
  
  while (hasMore) {
    const response = await getPlays(eventId, page);
    allPlays.push(...response.data);
    hasMore = response.meta.pagination.hasNextPage;
    page++;
  }
  
  return allPlays;
}

// Usage
discoverAPI();
getLiveNFLGames();
getAllPlays('401772982').then(plays => {
  console.log(`Fetched ${plays.length} total plays`);
});

Teams & Athletes

GET/sports/{sport}/leagues/{league}/teams

Get all teams for a league.

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/baseball/leagues/mlb/teams" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response Includes

  • ✓ Team names, abbreviations, colors
  • ✓ Logos (proxied through our CDN)
  • ✓ Venue information
  • ✓ Records and standings
GET/sports/{sport}/leagues/{league}/athletes

Get athletes (paginated - MLB has 36,000+!).

Example Request

curl "https://realtimesportsapi.com/api/v1/sports/baseball/leagues/mlb/athletes?page=1&limit=25" \
  -H "Authorization: Bearer YOUR_API_KEY"

Special Features

Image Proxying

All images (team logos, athlete headshots) are automatically proxied through our CDN.

// Team logos are proxied
"logo": "https://realtimesportsapi.com/api/images/proxy?url=..."

// Direct image access (no auth required)
<img src="/api/images/proxy?url=..." alt="Team Logo" />

Pagination Best Practices

  • ✓ Plays: Default 25 per page (games have 200+ plays)
  • ✓ Athletes: Default 25 per page (MLB: 36,000+)
  • ✓ Check hasNextPage in meta
  • ✓ Use totalPages to show progress

Rate Limit Headers

Check these headers in every response:

X-RateLimit-Limit: 50000
X-RateLimit-Remaining: 49995
X-RateLimit-Reset: 1642636800000  // Unix timestamp

WebSocket Support (paid plans)

Stream real-time sports data directly to your application. Connect once, then subscribe to the event types you care about and optionally filter by sport, league, or a specific game so you only receive the notifications you need.

Note: WebSocket support is included with every paid plan (free tier gets a 500-message monthly preview). Get your API key and connection URL from your dashboard.

How it works

  1. Get a token — POST to /api/websocket/auth with your API key. You receive a WebSocket URL and a short-lived token (1 hour).
  2. Connect — Open a WebSocket to the URL and pass the token (e.g. ?token=... or Authorization: Bearer ...).
  3. Subscribe — Send a subscribe message with an event type and optional filters (sport, league, eventId). You can subscribe to multiple event types and filter sets.
  4. Receive — The server pushes JSON messages when events occur. Each message has a type, timestamp, and data payload.

1. Get a WebSocket token

Call our auth endpoint with your API key. The response includes the WebSocket server URL and a token valid for 1 hour.

const response = await fetch('https://realtimesportsapi.com/api/websocket/auth', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  }
});
const { data } = await response.json();
// data.url  - WebSocket server URL (use wss:// in production)
// data.token - Token (expires in 1 hour)

2. Connect

Open a WebSocket to data.url and pass the token. For long tokens, some clients support Authorization: Bearer <token> on the handshake instead of the query string.

const ws = new WebSocket(`${data.url}?token=${data.token}`);

ws.onopen = () => console.log('Connected');
ws.onmessage = (e) => {
  const msg = JSON.parse(e.data);
  if (msg.type === 'pong' && msg.data?.message) console.log(msg.data.message);
  else if (msg.error) console.error(msg.error);
  else console.log(msg.type, msg.data);
};
ws.onclose = () => console.log('Disconnected');

3. Event types: what you can subscribe to

Choose one or more event types. You can use either the canonical or legacy name; both work the same.

Event typeAlso acceptedWhen you get notified
event_score_changescore_updateA score changes in a live game (goal, point, etc.)
event_liveA game transitions to live
event_status_changestatus_changeGame status changes (e.g. scheduled → in-progress → final)
event_playplay_eventA new play-by-play event (play, goal, card, etc.)
event_finalA game ends
event_odds_changeBetting odds for an event change significantly

4. Filtering: control what you receive

When you subscribe, you can omit filters to get all events of that type, or narrow by sport, league, and/or eventId. The more filters you set, the more specific the stream.

  • No filters — You receive every event of that type across all sports and leagues.
  • sport + league — Only events for that league (e.g. all NFL games, all Premier League games).
  • eventId — Only that single game. Use with sport/league if you want to be explicit.

Example sport / league values: football / nfl, basketball / nba, soccer / usa.1 or eng.1, hockey / nhl, baseball / mlb. Same values as in the REST API.

// All score changes, all sports
ws.send(JSON.stringify({ type: 'subscribe', event: 'event_score_change' }));

// Only NFL score changes
ws.send(JSON.stringify({
  type: 'subscribe',
  event: 'event_score_change',
  filters: { sport: 'football', league: 'nfl' }
}));

// Only one game (e.g. play-by-play for event 401772982)
ws.send(JSON.stringify({
  type: 'subscribe',
  event: 'event_play',
  filters: { sport: 'football', league: 'nfl', eventId: '401772982' }
}));

// Optional: throttle delivery (default is immediate)
// frequency: 'asap' | '30s' | '1m' | '5m' | '10m' | '30m'
ws.send(JSON.stringify({
  type: 'subscribe',
  event: 'event_score_change',
  filters: { sport: 'soccer', league: 'usa.1' },
  frequency: '30s'
}));

5. What you receive: message format

Every message from the server is JSON with type and timestamp. For event notifications, type matches the event type (e.g. event_score_change) and data contains the payload. Example score change:

{
  "type": "event_score_change",
  "timestamp": "2026-02-18T12:05:00.000Z",
  "data": {
    "eventId": "401772982",
    "sport": "football",
    "league": "nfl",
    "name": "Team A at Team B",
    "homeTeam": { "id": "...", "name": "Team B", "score": 14 },
    "awayTeam": { "id": "...", "name": "Team A", "score": 7 },
    "previousScore": { "home": 7, "away": 7 }
  }
}

Other server message types: subscribed / unsubscribed (after you subscribe/unsubscribe), pong (welcome or response to your ping), error (with error.code and error.message).

Keepalive: The server sends a WebSocket ping every 2 minutes so connections stay open behind proxies. If your client still disconnects after a few minutes, send { "type": "ping" } every 1–2 minutes; the server responds with pong.

6. Unsubscribe and full example

To stop receiving an event type, send unsubscribe with the same event and filters you used to subscribe.

class RealtimeSportsWebSocket {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.ws = null;
    this.token = null;
  }

  async connect() {
    const res = await fetch('https://realtimesportsapi.com/api/websocket/auth', {
      method: 'POST',
      headers: { 'Authorization': `Bearer ${this.apiKey}`, 'Content-Type': 'application/json' }
    });
    const { data } = await res.json();
    this.ws = new WebSocket(`${data.url}?token=${data.token}`);

    this.ws.onopen = () => {
      this.subscribe('event_score_change', { sport: 'football', league: 'nfl' });
      this.subscribe('event_play', { sport: 'football', league: 'nfl', eventId: '401772982' });
    };
    this.ws.onmessage = (e) => {
      const msg = JSON.parse(e.data);
      if (msg.type === 'event_score_change') console.log('Score:', msg.data);
      else if (msg.type === 'event_play') console.log('Play:', msg.data);
      else if (msg.type === 'error') console.error(msg.error);
    };
    this.ws.onclose = () => setTimeout(() => this.connect(), 5000);
  }

  subscribe(eventType, filters = {}, frequency = 'asap') {
    if (this.ws?.readyState === WebSocket.OPEN)
      this.ws.send(JSON.stringify({ type: 'subscribe', event: eventType, filters, frequency }));
  }
  unsubscribe(eventType, filters = {}) {
    if (this.ws?.readyState === WebSocket.OPEN)
      this.ws.send(JSON.stringify({ type: 'unsubscribe', event: eventType, filters }));
  }
  disconnect() { this.ws?.close(); }
}

const client = new RealtimeSportsWebSocket('YOUR_API_KEY');
client.connect();

Webhooks (paid plans)

Receive real-time notifications when sports events occur. Webhooks send HTTP POST requests to your server when events happen, eliminating the need to poll our API.

Note: Webhooks are available on every paid plan. Upgrade from your dashboard.

What are Webhooks?

Webhooks allow you to receive real-time notifications when events occur in sports games. Instead of polling our API, we send HTTP POST requests to your server when:

  • A game goes live
  • Scores change
  • Game status changes (scheduled → in-progress → final)
  • New plays occur
  • A game ends

Available Event Types

event.live

Triggered when a game goes live (status changes to in-progress)

event.score_change

Triggered when the score changes during a game

event.status_change

Triggered when game status changes (scheduled → in-progress → final)

event.play

Triggered when a new play occurs in a game

event.final

Triggered when a game ends (status changes to final)

Webhook Payload Format

Each webhook request includes the following headers and payload:

// Headers
X-Webhook-Signature: 3f9a1c...        // hex HMAC-SHA256 of the raw body (no prefix)
X-Webhook-Event: event.score_change     // Event type
Content-Type: application/json
User-Agent: RealtimeSportsAPI/1.0

// Payload
{
  "event": "event.score_change",
  "timestamp": "2024-01-15T20:30:00.000Z",
  "data": {
    "eventId": "401772982",
    "sport": "football",
    "league": "nfl",
    "homeTeam": {
      "id": "2",
      "name": "Kansas City Chiefs",
      "score": 24
    },
    "awayTeam": {
      "id": "3",
      "name": "Buffalo Bills",
      "score": 17
    },
    "status": {
      "type": {
        "id": "1",
        "name": "STATUS_IN_PROGRESS",
        "state": "in",
        "completed": false
      },
      "period": 3,
      "clock": {
        "value": 1200,
        "displayValue": "20:00"
      }
    }
  }
}

Signature Verification

Always verify webhook signatures to ensure requests are from Realtime Sports API. The X-Webhook-Signature header is the lowercase hex HMAC-SHA256 of the raw request body bytes, keyed with your webhook's signing secret. There is no sha256= prefix.

Managing webhooks from your own code (API key): the endpoints below authenticate with your API key (Authorization: Bearer YOUR_API_KEY), require a paid plan, and return { success, data, meta } (errors: { success: false, error: { code, message } } with 400/403/404/500). Webhook objects never include the secret except in the create response.

GET    /api/v1/webhooks                      list
POST   /api/v1/webhooks                      create   { url, events[], leagues?[], frequency? }  -> includes secret (once)
GET    /api/v1/webhooks/{id}                 read
PATCH  /api/v1/webhooks/{id}                 update   any of { url, events, leagues, frequency, active }
DELETE /api/v1/webhooks/{id}                 delete
GET    /api/v1/webhooks/{id}/secret          reveal signing secret
POST   /api/v1/webhooks/{id}/secret          rotate signing secret
POST   /api/v1/webhooks/{id}/test            { eventType? } or { deliveryId? }  -> sends a signed sample / replays
GET    /api/v1/webhooks/{id}/deliveries      recent failed deliveries

# Disable (takes effect immediately) / re-enable
curl -X PATCH https://realtimesportsapi.com/api/v1/webhooks/WEBHOOK_ID \
  -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"active": false}'

# Response
{ "success": true,
  "data": { "id": "…", "url": "…", "events": ["event.live","event.final"], "leagues": ["nfl"], "frequency": "asap",
            "active": false, "consecutiveFailures": 0, "deactivatedReason": null, "deactivatedAt": null,
            "createdAt": "…", "updatedAt": "…" },
  "meta": { "rateLimit": { "limit": 60, "remaining": 59, "reset": 1700000000000 } } }

Enable / disable semantics: active: false stops deliveries immediately — the delivery service watches the webhook registry in real time (typically under a second); a request already in flight to your endpoint is not recalled. active: true re-enables, and this also clears an automatic deactivation: deactivatedReason is reset and the consecutive-failure counter returns to 0. A webhook is auto-deactivated (deactivatedReason: "repeated_failures") after 5 consecutive failed deliveries (non-2xx, timeout > 10s, or connection error); any successful delivery resets the counter. Management calls are rate-limited like other API calls but do not count toward your monthly call quota.

Testing and delivery history: from the webhook card in your dashboard, the test panel sends a signed, production-shaped sample of any event type (event.live, score_change, status_change, play, final) to your URL — with an extra X-Webhook-Test: true header and data.test: true — and shows the HTTP status, latency, the exact request headers/body sent, and your response body. Failed deliveries can be replayed with their original payload (X-Webhook-Test: replay). API equivalent: POST /api/webhooks/{webhookId}/test with { firebaseUid, eventType } or { firebaseUid, deliveryId }. Show failed deliveries (or GET /api/webhooks/{webhookId}/deliveries) lists recent failed attempts with the response code and body; successful deliveries aren't stored individually but count toward monthly usage. After 5 consecutive failures a webhook is automatically deactivated — re-enable it from the dashboard once your endpoint is fixed. Editing a webhook's URL, events or leagues never changes its secret; only Rotate does.

Where to find the secret: it is returned once in the secret field when you create a webhook via the API, and you can reveal or rotate it at any time from the webhook card in your dashboard ("Show secret" / "Rotate"), or via GET /api/webhooks/{webhookId}/secret?firebaseUid=…. Compute the HMAC over the raw body — if you re-serialize a parsed JSON object the bytes may differ and the check will fail.

// Node.js example
const crypto = require('crypto');

// rawBody must be the exact bytes received (Buffer or string), not a re-serialized object
function verifyWebhookSignature(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  const provided = String(signature || '');
  if (provided.length !== expected.length) return false;

  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(provided));
}

// In your webhook endpoint — use a raw body parser on this route
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const secret = process.env.RTS_WEBHOOK_SECRET; // From the dashboard ("Show secret")

  if (!verifyWebhookSignature(req.body, signature, secret)) {
    return res.status(401).send('Invalid signature');
  }

  // Process webhook
  const { event, data } = JSON.parse(req.body.toString('utf8'));
  console.log(`Received ${event}:`, data);

  res.status(200).send('OK');
});

Complete Example

// Express.js webhook endpoint example
const express = require('express');
const crypto = require('crypto');
const app = express();

app.use(express.json());

// Your webhook secret (from webhook creation)
const WEBHOOK_SECRET = 'your-webhook-secret';

function verifySignature(payload, signature) {
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(JSON.stringify(payload))
    .digest('hex');
  
  const provided = signature.replace('sha256=', '');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(provided)
  );
}

app.post('/webhook', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const eventType = req.headers['x-webhook-event'];
  
  // Verify signature
  if (!verifySignature(req.body, signature)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  const { event, timestamp, data } = req.body;
  
  // Handle different event types
  switch (event) {
    case 'event.live':
      console.log(`Game went live: ${data.name}`);
      // Notify users, update database, etc.
      break;
      
    case 'event.score_change':
      console.log(`Score update: ${data.awayTeam.name} ${data.awayTeam.score} - ${data.homeTeam.score} ${data.homeTeam.name}`);
      // Update scores in your app
      break;
      
    case 'event.status_change':
      console.log(`Status changed: ${data.status.type.name}`);
      // Update game status
      break;
      
    case 'event.play':
      console.log(`New play: ${data.play.text}`);
      // Display play in your app
      break;
      
    case 'event.final':
      console.log(`Game ended: Final score ${data.awayTeam.score} - ${data.homeTeam.score}`);
      // Show final results
      break;
  }
  
  // Always return 200 OK
  res.status(200).json({ received: true });
});

app.listen(3000, () => {
  console.log('Webhook server listening on port 3000');
});

Best Practices

  • ✓ Always verify webhook signatures to prevent unauthorized requests
  • ✓ Return 200 OK immediately, then process the webhook asynchronously
  • ✓ Use HTTPS for your webhook endpoint
  • ✓ Implement idempotency to handle duplicate deliveries
  • ✓ Set up retry logic for failed webhook deliveries
  • ✓ Monitor webhook delivery status in your dashboard
  • ✓ Keep your webhook secret secure and never expose it in client-side code

Python Example

import requests

API_KEY = 'YOUR_API_KEY'
BASE_URL = 'https://realtimesportsapi.com/api/v1'

class RealtimeSportsAPI:
    def __init__(self, api_key):
        self.api_key = api_key
        self.base_url = BASE_URL
        self.headers = {'Authorization': f'Bearer {api_key}'}
    
    def get_sports(self):
        """Get all available sports"""
        response = requests.get(f'{self.base_url}/sports', headers=self.headers)
        return response.json()['data']
    
    def get_leagues(self, sport):
        """Get leagues for a sport"""
        response = requests.get(
            f'{self.base_url}/sports/{sport}/leagues',
            headers=self.headers
        )
        return response.json()['data']
    
    def get_live_games(self, sport, league):
        """Get live games for a league"""
        response = requests.get(
            f'{self.base_url}/sports/{sport}/leagues/{league}/events/live',
            headers=self.headers
        )
        return response.json()['data']
    
    def get_plays(self, sport, league, event_id, page=1, limit=25):
        """Get plays for an event (paginated)"""
        response = requests.get(
            f'{self.base_url}/sports/{sport}/leagues/{league}/events/{event_id}/plays',
            params={'page': page, 'limit': limit},
            headers=self.headers
        )
        return response.json()

# Usage
api = RealtimeSportsAPI(API_KEY)

# Discover sports
sports = api.get_sports()
print(f"Available sports: {[s['name'] for s in sports]}")

# Get live NFL games
nfl_games = api.get_live_games('football', 'nfl')
for game in nfl_games:
    print(f"{game['name']}: {game['awayTeam']['score']} - {game['homeTeam']['score']}")

# Get plays with pagination
plays_response = api.get_plays('football', 'nfl', '401772982', page=1)
print(f"Page 1: {len(plays_response['data'])} plays")
print(f"Total: {plays_response['meta']['pagination']['total']} plays")
print(f"Total pages: {plays_response['meta']['pagination']['totalPages']}")