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.comAuthentication
All API requests require authentication using JWT tokens. Include your API key in the Authorization header:
Authorization: Bearer YOUR_API_KEYNote: 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.
| Tier | Calls/Month | Calls/Second |
|---|---|---|
| Free | 125 (1,000 first month) | 1 |
| Starter | 10,000 | 5 |
| Pro | 50,000 | 20 |
| Scale | 500,000 | 100+ |
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 onlySports & Leagues
/v1/sportsGet 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"
}
]
}/v1/sports/:sport/leaguesGet 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
/sports/{sport}/leagues/{league}/teamsGet 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
/sports/{sport}/leagues/{league}/teams/{teamId}/rosterCurrent 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
athleteslist - ✓ Per player: id, name, jersey, position, age, height/weight
- ✓ Experience, status, and headshot (proxied)
/sports/{sport}/leagues/{league}/teams/{teamId}/depthchartTeam 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
/sports/{sport}/leagues/{league}/injuriesCurrent 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"/sports/{sport}/leagues/{league}/player-availabilityCoverage 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 idstatus- 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"/sports/{sport}/leagues/{league}/player-availability/historyLeague-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"
}
]
}/sports/{sport}/leagues/{league}/athletes/{athleteId}/availability-historyFull 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"/sports/{sport}/leagues/{league}/transactionsRecent 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 historyteam- Filter to a single team idseason- 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"/sports/{sport}/leagues/{league}/newsLatest 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 idathlete- Filter to articles tagged with an athlete idsince/from,to- ISO date bounds onpublished(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"/sports/{sport}/leagues/{league}/news/historyArchived 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 onpublishedteam- Filter to articles tagged with a team idathlete- Filter to articles tagged with an athlete idlimit- 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
/sports/{sport}/leagues/{league}/athletesGet 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"/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"/sports/{sport}/leagues/{league}/athletes/searchFind 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"/sports/{sport}/leagues/{league}/athletes/{athleteId}/gamelogPer-game (and per-week) stat lines for an athlete in a season.
Query Parameters
season- Season year (required)week- Filter to a single week numberseasonType- 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
/sports/{sport}/leagues/{league}/seasonsGet 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"/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
/sports/{sport}/leagues/{league}/eventsGet 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"/sports/{sport}/leagues/{league}/events/liveGet 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"
}
}
]
}/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"/sports/{sport}/leagues/{league}/seasons/{year}/scheduleEvents 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=postseasonincludeOdds- 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"/sports/{sport}/leagues/{league}/seasons/{year}/weeksList 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"/sports/basketball/leagues/mens-college-basketball/seasons/{year}/tournamentThe 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
/sports/{sport}/leagues/{league}/events/{eventId}/playsGet 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). Setfalsefor 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
}
}
}/sports/{sport}/leagues/{league}/events/{eventId}/penaltiesGet 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"/sports/{sport}/leagues/{league}/events/{eventId}/rosterGame-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
}
]
}
]
}
}/sports/{sport}/leagues/{league}/events/{eventId}/winprobabilityPer-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.
/sports/{sport}/leagues/{league}/events/{eventId}/oddsCurrent 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 withweek)
Each event in the response will include an odds property when available. Using includeOdds=true may increase latency and usage.
/sports/{sport}/leagues/{league}/events/{eventId}/odds/historyHistorical 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
/sports/{sport}/leagues/{league}/teamsGet 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
/sports/{sport}/leagues/{league}/athletesGet 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
hasNextPagein meta - ✓ Use
totalPagesto show progress
Rate Limit Headers
Check these headers in every response:
X-RateLimit-Limit: 50000
X-RateLimit-Remaining: 49995
X-RateLimit-Reset: 1642636800000 // Unix timestampWebSocket 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
- Get a token — POST to
/api/websocket/authwith your API key. You receive a WebSocket URL and a short-lived token (1 hour). - Connect — Open a WebSocket to the URL and pass the token (e.g.
?token=...orAuthorization: Bearer ...). - Subscribe — Send a
subscribemessage with an event type and optional filters (sport, league, eventId). You can subscribe to multiple event types and filter sets. - Receive — The server pushes JSON messages when events occur. Each message has a
type,timestamp, anddatapayload.
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 type | Also accepted | When you get notified |
|---|---|---|
event_score_change | score_update | A score changes in a live game (goal, point, etc.) |
event_live | — | A game transitions to live |
event_status_change | status_change | Game status changes (e.g. scheduled → in-progress → final) |
event_play | play_event | A new play-by-play event (play, goal, card, etc.) |
event_final | — | A game ends |
event_odds_change | — | Betting 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']}")