theScore API: Free Endpoints from the Scores App Feed, Not theScore Bet
The undocumented JSON feed at api.thescore.com behind theScore media app: no key, tested 2 November 2026.
Last updated:
What Is theScore API?
theScore API is the JSON feed at api.thescore.com that runs theScore sports media app: scores, schedules, box scores, play-by-play, standings and player pages. It is unofficial and undocumented. theScore publishes no developer docs for it, asks for no key and charges nothing. Developers who search for the score api usually mean this feed, which belongs to the scores app. theScore Bet, the sportsbook, is a separate product. Looking for odds APIs that carry theScore Bet lines? See theScore Bet odds API guide.
We called every endpoint on this page with plain curl on 2 November 2026 and ran the code samples as written in Python (requests) and Node (fetch). The feed behaves a lot like the ESPN API. Both are undocumented, both cover the same major leagues, and either one can change without notice. theScore's terms allow personal, non-commercial use, so read Limitations and Terms before you build on it.
Base URLs
One host serves the data. A second serves the images that responses point to.
| Host | What it serves |
|---|---|
api.thescore.com | Every JSON endpoint on this page. Paths start with a league slug: /nba, /nfl, /epl |
assets-sports-gcp.thescore.com | Team logos and player headshots, linked from fields such as logos.large (HTTP 200 in our test) |
feeds.thescore.com | The RSS feeds named in rss_url fields. Both feed URLs we tried answered 404 |
Objects link to each other through api_uri. Event 2462797 carries "api_uri": "/nba/events/2462797", its box score carries /nba/box_scores/247125, and each team carries a path such as /nba/teams/18. Put the host in front of one and you have the next URL.
What It Covers
https://api.thescore.com/leagues returned 100 leagues, each with the slug that opens every path. These are the ones developers ask about most, with the season size from /{league}/schedule (tested November 2026).
| League | Slug | Season in /schedule |
|---|---|---|
| NBA | nba | 1,267 games |
| NFL | nfl | 334 games, HOF game to Super Bowl |
| NHL | nhl | 1,409 games |
| MLB | mlb | 2,990 games, through the World Series |
| NCAA basketball, football | ncaab, ncaaf | 6,011 and 1,692 games |
| Premier League | epl | 380 matches |
| La Liga, Serie A | liga, seri | 380 matches each |
| Bundesliga, Champions League | bund, chlg | 306 and 234 matches |
| MLS, WNBA, CFL | mls, wnba, cfl | 510, 374 and 94 games |
| ATP, PGA Tour | atp, pga | 78 and 55 tournaments |
Serie A is seri: /seria/events/current answered 404. The list also carries the KHL, IPL cricket, Formula 1, NASCAR, MMA and the World Cup. Tennis and golf use a different shape. Their events/current returns one tournament object with start_date and end_date in place of a list of games: /atp/events/current returned the Rolex Paris Masters.
Key Endpoints
Paths follow /{league}/{resource} or /{league}/{resource}/{id}. Every row below answered HTTP 200 on 2 November 2026, and the examples use the ids we tested.
| Endpoint | What it returns | Example |
|---|---|---|
/{league}/events/current | Games theScore treats as current. 5 rows unless you add rpp | /nba/events/current?rpp=20 |
/{league}/events/{id} | One game: teams, score, venue, TV, betting line | /nba/events/2462797 |
/{league}/events?id.in= | Several games by id, as a list | /nba/events?id.in=2462799,2462800,2462801 |
/{league}/schedule | The season in groups, each with event_ids | /nfl/schedule |
/{league}/box_scores/{id} | Score by period, team totals, clock, attendance | /nba/box_scores/247125 |
/{league}/box_scores/{id}/player_records | One stat line per player | /nba/box_scores/247125/player_records |
/{league}/events/{id}/play_by_play_records | Every play of the game | /nba/events/2462797/play_by_play_records |
/{league}/teams | Every team in the league | /nhl/teams |
/{league}/teams/{id} | One team with its standing | /nhl/teams/1 (Boston Bruins) |
/{league}/teams/{id}/events/upcoming | The team's next 5 games | /nba/teams/11/events/upcoming |
/{league}/teams/{id}/events/previous | The team's last 5 games | /nba/teams/11/events/previous |
/{league}/teams/{id}/players | The roster, with season stats | /nba/teams/11/players |
/{league}/teams/{id}/injuries | The team's injury report | /nba/teams/11/injuries |
/{league}/players/{id} | One player: position, number, team, injury | /nba/players/182546 |
/{league}/standings | One standings row per team | /nba/standings |
/{league}/leaders | Stat leaders, 50 rows across categories | /nba/leaders |
/leagues | 100 leagues, each with its slug and season | /leagues |
Some paths that look right do not exist. /nba/events/2462799/play_by_play, /nba/teams/11/roster and /nba/odds/12853680 answered 404. League-wide /nba/injuries answered 200 with an empty list while /nba/teams/11/injuries listed five Atlanta Hawks players, and /nhl/injuries answered 404. Read injuries team by team.
The Events Endpoint
https://api.thescore.com/{league}/events/{id}
An event is one game, and everything else hangs off it: the box score link, the play-by-play flag and a betting line. Our test game was event 2462797, the Toronto Raptors at the Los Angeles Lakers, a 131 to 125 Lakers win (43 KB).
| Field | Type | What it holds |
|---|---|---|
id | integer | The event id: 2462797 |
game_date | string | Start time with a UTC offset: Mon, 02 Nov 2026 02:00:00 -0000 |
status | string | pre_game, in_progress, half_over or final |
away_team, home_team | object | full_name, abbreviation, id and api_uri (/nba/teams/18) |
box_score | object or null | Its api_uri, score.home.score and progress.clock_label ("Final") |
has_play_by_play_records | boolean | True when the play-by-play path has plays |
odd | object | line "LAL -3.5", over_under "224.5", closing "LAL -3.5, o/u 224.5" |
timestamped_odds | array | Line history: 46 snapshots, each with money_line_home, point_spread_home and total |
game_description | string | Top performers: "L. Dončić (LAL): 45 PTS, 15 REB, 5 STL" |
stadium, location | string | "Crypto.com Arena", "Los Angeles, CA, USA" |
Games further out can have no box score: all five of Atlanta's upcoming games had box_score set to null. The feed names no sportsbook for odd or timestamped_odds, so treat them as a reference line. For theScore Bet's own prices, see theScore Bet API.
Box score, player lines and play-by-play
/nba/box_scores/247125 returned line_scores by quarter (Lakers 36, 30, 38, 27), team_records with team totals and attendance "19,057". /nba/box_scores/247125/player_records returned 35 player lines, led by Luka Dončić with 45 points and 15 rebounds. /nba/events/2462797/play_by_play_records returned 521 plays, each with description, event_type, progress.clock_label and the score after it. Live games work too: Atlanta at Indiana (2462799) had 126 plays at 10:06 of the second quarter.
Other sports change the play fields. NFL plays add down and distance (166 plays, 1.3 MB, for event 140696). MLB gave one record per half-inning, 18 for World Series game 100780, and Premier League records carry a category such as Goal or Corner.
Parameters and Date Filters
| Parameter | What it does | Example |
|---|---|---|
id.in | Comma-separated event ids. Returns those games as a list | /nba/events?id.in=2462799,2462800,2462801 (3 games) |
game_date.in | Two ISO 8601 times. Returns the games whose game_date falls between them | /nba/events?game_date.in=2026-11-01T08:00:00Z,2026-11-02T08:00:00Z (4 games) |
rpp | Rows per response. Raises or lowers the default | /nba/leaders?rpp=5 (5 rows in place of 50) |
page | No effect in our test: page 1 and page 2 returned the same rows | /nba/events?rpp=5&page=2 |
rpp matters most on events/current: without it, /nba/events/current returned 5 games while 9 were in progress, and ?rpp=20 returned all 9. Leave every filter off /nba/events and you get the whole season, 1,267 games in one 8.9 MB response.
For one US day, run game_date.in from 08:00 UTC to 08:00 UTC the next day. That window returned the four NBA games of Sunday 1 November. Midnight to midnight UTC returned six: four from Saturday night in the US and two from Sunday afternoon. A bad value such as game_date.in=yesterday,today returns 400.
The schedule as an index
/nfl/schedule returned current_season, 26 groups from "HOF" to "Super Bowl", and current_group, Week 8 with 14 event ids. Daily leagues group by date and tennis and golf by month. Pass a group's event_ids to id.in to get the games.
Group labels follow each game's UTC date. At 01:11 UTC on 3 November (Monday evening in the US), current_group was "Nov 2" and held two games from the night before, while that evening's games sat in "Nov 3". Trust game_date and status over the label.
Code Examples
Games on a date in Python
import requests
# NBA games of Sunday 1 November 2026, US time (08:00 UTC to 08:00 UTC)
url = ('https://api.thescore.com/nba/events'
'?game_date.in=2026-11-01T08:00:00Z,2026-11-02T08:00:00Z')
for game in requests.get(url, timeout=10).json():
score = (game.get('box_score') or {}).get('score', {})
print(game['away_team']['full_name'], score.get('away', {}).get('score'), 'at',
game['home_team']['full_name'], score.get('home', {}).get('score'),
game['status'])
It printed four lines, the last one "Toronto Raptors 125 at Los Angeles Lakers 131 final". The box_score guard covers dates far ahead, where games have no box score yet.
Live games and one event with cURL
# Every NBA game theScore treats as current, up to 20
curl 'https://api.thescore.com/nba/events/current?rpp=20'
# One finished game, with its line and box score link
curl 'https://api.thescore.com/nba/events/2462797'
Play-by-play in JavaScript
// Run as an .mjs file in Node 18+
const url = 'https://api.thescore.com/nba/events/2462797/play_by_play_records';
const plays = await fetch(url).then(r => r.json());
const last = plays[plays.length - 1];
console.log(plays.length, 'plays');
console.log(last.progress.clock_label, last.description);
console.log(`Final: ${last.away_score_after} to ${last.home_score_after}`);
It printed 521 plays and the last one, a Jamison Battle dunk at 0:01 of the fourth. Responses carry access-control-allow-origin: *, the header a browser needs before it lets a page read a cross-origin fetch.
Errors You Will See
404 Not Found
A bad league slug, a bad id and an unknown path all return 404 with this body (from /seria/events/current):
{"api_uri":"/error/events/404","error":{"request":"https://api.thescore.com/seria/events/current","code":404,"reason":"Not Found"}}
The same shape came back for /xyz/events/current, /nba/events/999999999, /nba/events/abc, /nba/teams/99999 and /nba/players/0.
400 Bad Request
/nba/events?game_date.in=yesterday,today returned 400. The filter wants two ISO 8601 times such as 2026-11-01T08:00:00Z.
200 with an empty list
We saw three causes. No games in the window: /mlb/events/current was empty after the World Series, while /mlb/schedule still listed the season. A bad id.in value: /nba/events?id.in=abc returned [] in place of an error. And the league-wide injuries path, covered above.
No 403 and no 429
None of our 128 calls to api.thescore.com was blocked or throttled. Each one sent the client's default headers (curl, Python requests or Node fetch), with no key, cookie or browser header.
Limitations and Terms
Unofficial, undocumented, personal use only
theScore's Terms of Use (last revised January 1, 2023, from Score Media and Gaming Inc.) grant users "a limited, non-exclusive, non-transferable, non-sublicensable, revocable license to: (i) access and view Content (as defined below) from the Service for your personal, non-commercial use only". In its list of things you shall not do, section 7 includes: "use spiders, crawlers, robots or any other similar means to access the Service or substantially download, reproduce or archive any portion of the Service".
The licence covers a personal script that follows your own teams. A public app, a paid product or a bulk archive falls outside it, and section 7 also rules out heavy load and commercial use. The terms are at thescore.com/pages/terms, which redirects to theScore's help centre.
- No docs, no promise: theScore can change or close any path on this page without notice.
- robots.txt says no crawlers: api.thescore.com/robots.txt disallows every path for every user agent.
- No published rate limit: our calls ran at about one a second with no 429 and no
X-RateLimitheader.Cache-Controlsaidmax-age=10on live games, 300 on a finished game and 7200 on past dates, so polling a live game faster than every 10 seconds gains nothing. - Licensed text inside: the
recap_dataon our test game was a wire-service story, one more reason not to republish the feed.
A product built on this feed needs a licence from theScore. For production apps with an SLA, compare licensed sports data providers. For odds, browse the directory.
Client Libraries and Related Guides
We link no client library for this feed. A GitHub search on 2 November 2026 turned up one maintained Python wrapper, and it sends a copied Chrome User-Agent plus Origin and Referer headers on every call. You do not need them: every call in our tests answered 200 with the default headers of curl, Python requests and Node fetch. Section 7 of theScore's terms also bars forged headers that disguise where a request comes from, so a plain client is the one to write.
For the same leagues from a second undocumented source, see the ESPN API guide. For open historical data, see free sports datasets and free sports APIs.
Frequently Asked Questions
api.thescore.com charges nothing and needs no sign-up. theScore's Terms of Use grant a licence for personal, non-commercial use only and forbid robots, crawlers and bulk downloads. A hobby script fits that licence. A commercial product does not.odd and a history in timestamped_odds, with no sportsbook named. For odds APIs that carry theScore Bet prices, see theScore Bet API.https://api.thescore.com/leagues returned 100 leagues. They include the NFL (nfl), NBA (nba), MLB, NHL, WNBA, CFL, NCAA football and basketball, the Premier League (epl), La Liga (liga), Serie A (seri), the Bundesliga (bund), the Champions League (chlg), MLS, ATP tennis and PGA Tour golf.Cache-Control header caches live games for 10 seconds, so poll no faster than that and cache what you fetch.https://api.thescore.com/nba/events/current?rpp=20. Without rpp it returned only 5 games while 9 were live. Each game has away_team.full_name, home_team.full_name, box_score.score and status. For a past date, use game_date.in with two ISO 8601 times.Need More Reliable Sports Data?
theScore API suits personal projects. A product needs a licence, an SLA and support. Compare licensed providers in our directory.