Skip to content

MLB Stats API: Free Endpoints for Schedules, Live Games and Player Stats

MLB's own JSON feed, no key required. We called every endpoint below in November 2026.

Last updated:

What is the MLB Stats API?

The MLB Stats API is the JSON backend that MLB Advanced Media runs for MLB's own apps, and developers also search for it as the MLB Gameday API. It's free, it needs no API key, and it isn't documented for outside developers: MLB publishes no public docs, and the root of statsapi.mlb.com serves a sign-in page titled "Please Login". The responses carry a copyright line that points at MLB's usage notice, covered under terms.

We called every endpoint on this page on 2 November 2026 with the default headers of curl, Python requests and Node fetch. The examples use Game 5 of the 2026 World Series: Brewers 4, Rays 1, gamePk 849799. The feed has no betting lines; for prices on the same games, see MLB odds APIs. The baseball/mlb scoreboard of the ESPN API lists the same games under other ids: ESPN calls this game 401908046.

Base URLs

Two hosts carry the data, and a third holds the usage notice.

HostWhat it serves
https://statsapi.mlb.com/api/v1Schedule, teams, rosters, standings, people, stats, box scores and line scores
https://statsapi.mlb.com/api/v1.1The live game feed, /game/{gamePk}/feed/live. The same path under v1 returned 404
https://baseballsavant.mlb.comStatcast pitch data as CSV (see below)
http://gdx.mlb.com/components/copyright.txtThe usage notice that every response links to

What It Covers

/api/v1/sports returned 20 levels of baseball, and you pass the id as sportId:

  • MLB: sportId=1, 30 teams
  • Minor leagues: 11 Triple-A, 12 Double-A, 13 High-A, 14 Single-A, 16 Rookie
  • Elsewhere: 31 Nippon Professional Baseball, 32 Korean Baseball Organization, 17 Winter Leagues, 22 College Baseball, 51 International Baseball

We tested MLB and Triple-A. /api/v1/teams?sportId=11 returned 30 clubs, and the feed for Rochester 15, Buffalo 8 on 20 September 2026 (gamePk 816903) held 96 plays and 378 pitches with velocity. The season list at /api/v1/seasons/all?sportId=1 runs from 1876 to 2027; we did not test how far back the game feeds go. For decades of play-by-play in flat files, Retrosheet and the Lahman database are on our free sports datasets page.

Key Endpoints

Every path sits under https://statsapi.mlb.com, and each one returned HTTP 200 in our test.

EndpointWhat it returnsExample
/api/v1/scheduleGames for a day or a date range, each with a gamePk, teams, score and status/api/v1/schedule?sportId=1&date=2026-10-28
/api/v1/teamsEvery team at one level, with league, division and venue/api/v1/teams?sportId=1
/api/v1/teams/{teamId}/rosterThe active roster: 20 Brewers on 2 November, in the offseason. rosterType=40Man gave 33/api/v1/teams/158/roster
/api/v1/standingsOne record per division: wins, losses, games back, streak/api/v1/standings?leagueId=103,104&season=2026
/api/v1/people/{personId}Name, position, bats and throws, debut date/api/v1/people/660271 (Shohei Ohtani)
/api/v1/people/{personId}/statsA stat line; stats is required/api/v1/people/660271/stats?stats=season&season=2026&group=hitting
/api/v1.1/game/{gamePk}/feed/liveThe whole game (see below)/api/v1.1/game/849799/feed/live
/api/v1/game/{gamePk}/boxscoreBox score only, 174 KB for our test game/api/v1/game/849799/boxscore
/api/v1/game/{gamePk}/linescoreRuns, hits and errors by inning, 3.7 KB/api/v1/game/849799/linescore
/api/v1/sportsThe 20 levels and their sportId/api/v1/sports
/api/v1/seasonsKey dates of the current season/api/v1/seasons?sportId=1

Watch the types. Rate stats come back as strings: Ohtani's 2026 line had avg ".275" and ops ".889" next to the integer homeRuns 30. Standings give the short team name ("Rays") and a division id with no name, so match the id against /api/v1/teams, where 201 is the American League East.

The Live Game Feed (feed/live)

The live feed is the endpoint developers look for most. One call returns the whole game: players, weather, every plate appearance, every pitch with speed and spin, the box score and the line score.

URL
https://statsapi.mlb.com/api/v1.1/game/{gamePk}/feed/live

The gamePk comes from the schedule, where each game also carries a link field that already points at its feed. Our World Series Game 5 response was 764 KB with 70 plays and 255 pitches, and a Triple-A game ran to 993 KB, so cache what you fetch.

FieldTypeWhat it holds
gameData.datetime.officialDatestringThe game's date, "2026-10-28". Group games by it: the UTC gameDate of this night game read 29 October
gameData.status.detailedStatestring"Final" here. "In Progress" and "Postponed" also appeared in our tests
gameData.playersobject52 players, keyed "ID" plus the person id (ID694192)
gameData.absChallengesobjectBall-strike challenges: each team had 1 successful challenge and 2 left
liveData.plays.allPlaysarrayOne entry per plate appearance: result.event, result.description, about.inning, matchup.batter
liveData.plays.scoringPlaysarrayIndexes into allPlays: [10, 33, 40, 43, 68]
allPlays[].playEvents[].pitchDataobjectstartSpeed (95.8 on the first pitch), breaks.spinRate (2341), zone
allPlays[].playEvents[].hitDataobjectlaunchSpeed, launchAngle and trajectory on balls in play
liveData.linescoreobjectInnings and totals, the same object as the linescore endpoint
liveData.boxscoreobjectTeam and player stats; the boxscore endpoint adds fuller team objects
liveData.decisionsobjectWinning and losing pitcher: Jacob Misiorowski, Drew Rasmussen
metaDataobjectwait (10) and timeStamp, the last update in UTC ("20261029_031311")

Replay a game at any moment

/api/v1.1/game/849799/feed/live/timestamps returned 445 timecodes. Pass one back as ?timecode= and the feed shows the game as it stood then: timecode=20261029_013436 gave 36 plays, top of the 5th, Brewers up 2-0, status "In Progress".

Parameters and Date Filters

The schedule accepts a date range, which ESPN's scoreboard does not. startDate=2026-10-01&endDate=2026-10-31 returned all 33 October postseason games on 22 dates; ESPN's dates=20261001-20261031 returned HTTP 400.

ParameterWhat it doesExample
dateOne day. YYYY-MM-DD and MM/DD/YYYY both worked; YYYYMMDD returned 400date=2026-10-28
startDate, endDateA range, in the same formatstartDate=2026-10-01&endDate=2026-10-31
sportIdThe level, 1 for MLB. The schedule returns 400 without itsportId=11
gameTypeR regular season, F Wild Card, D Division Series, L League Championship Series, W World Seriesseason=2026&gameType=W (5 games)
teamIdOne team's gamesteamId=158 (13 Brewers games in October)
hydrateAdds linked objects to each game or personhydrate=probablePitcher,linescore
fieldsKeeps only the keys you namefields=dates,date,games,gamePk,description

hydrate=probablePitcher,linescore grew the 28 October schedule from 1.7 KB to 5.5 KB. On /api/v1/people/660271, hydrate=currentTeam added the Dodgers (id 119), which the plain call leaves out. A misspelled hydrate=notAField returned 200 and the plain response, with no warning. fields cut the October range from 46.9 KB to 2.4 KB.

A postponed game keeps its gamePk: ALCS Game 4 (849817) is listed on 16 October as "Postponed" and on 18 October as "Final".

Code Examples

Scoring plays from the live feed, in Python

Python
import requests

# 2026 World Series, Game 5: Brewers at Rays
game_pk = 849799
url = f'https://statsapi.mlb.com/api/v1.1/game/{game_pk}/feed/live'
feed = requests.get(url, timeout=30).json()

plays = feed['liveData']['plays']
print(feed['gameData']['status']['detailedState'], len(plays['allPlays']), 'plays')
for i in plays['scoringPlays']:
    play = plays['allPlays'][i]
    about, result = play['about'], play['result']
    print(about['inning'], about['halfInning'], result['event'], f"{result['awayScore']}-{result['homeScore']}")

It printed Final 70 plays, then five lines from 2 top Single 1-0 to 9 bottom Double 4-1.

One day's schedule with starters and line scores, in cURL

cURL
curl 'https://statsapi.mlb.com/api/v1/schedule?sportId=1&date=2026-10-28&hydrate=probablePitcher,linescore'

Division leaders, in JavaScript

JavaScript
const url = 'https://statsapi.mlb.com/api/v1/standings?leagueId=103,104&season=2026';
const data = await fetch(url).then(r => r.json());
for (const record of data.records) {
  const leader = record.teamRecords[0];
  console.log(record.division.id, leader.team.name, `${leader.wins}-${leader.losses}`);
}

We ran it as a .mjs file with Node 22. It printed six lines, from 201 Rays 98-64 to 203 Dodgers 100-62. The responses carry access-control-allow-origin: *, the header a browser needs before a web page on another host can read them.

Statcast CSV from Baseball Savant

For pitch-level data in one flat file, Baseball Savant, an MLB site, exports Statcast searches as CSV. This call returned the 255 pitches of World Series Game 5, one row each, with 119 columns:

URL
https://baseballsavant.mlb.com/statcast_search/csv?all=true&hfGT=W%7C&player_type=batter&game_date_gt=2026-10-28&game_date_lt=2026-10-28&type=details

The columns include game_pk (the same 849799), pitch_name, release_speed, launch_speed, bat_speed and delta_home_win_exp. The hardest-hit ball was William Contreras at a launch_speed of 108.5. hfGT picks the game type: hfGT=R%7C for 30 and 31 October returned only the header row, because no regular-season games were played on those dates. The file starts with a byte order mark, so open it as utf-8-sig in Python.

Errors You Will See

400 Bad Request

A bad request gets a JSON body with a messageNumber and a message. The ones we caused:

  • No sportId: /api/v1/schedule?date=2026-10-28 gave message 7, "Missing required parameter sportId or gamePk"
  • A bad date: date=20261028, date=2026-13-45 and date=yesterday each gave message 11, "Invalid Request with value: 20261028"
  • A text gamePk: /api/v1.1/game/abc/feed/live also gave message 11
  • No stats on the stats endpoint: message 5, "Required request parameter 'stats' for method parameter type List is not present"

404 Not Found

An unknown person id (/api/v1/people/1) returned message 10, "Object not found". A wrong path returns a different body, {"error":"Not Found","status":404} with the path. We got it for the feed under v1: /api/v1/game/849799/feed/live is a 404, while v1.1 works.

200 with an empty game

A numeric gamePk that matches no game still returns HTTP 200. /api/v1.1/game/999999999/feed/live gave a 1.3 KB skeleton with gamePk 0, detailedState "Unknown" and an empty allPlays, and the boxscore endpoint did the same. Check gameData.status.detailedState before you trust a feed.

An empty dates array on the schedule means no games that day: 31 October 2026 had none, because the World Series ended on the 28th.

Limitations and Terms

Personal, non-commercial use only

The copyright line in the responses links to MLB's notice at gdx.mlb.com/components/copyright.txt. It says: "Only individual, non-commercial, non-bulk use of the Materials is permitted." Any other use needs prior written permission from MLB Advanced Media.

In plain terms, the notice covers one person's non-commercial use, such as a personal project. It does not cover a commercial app or bulk downloads. MLB.com's Terms of Use go further: clause (xi) of their conduct rules bars automated scripts that collect information from MLB's digital properties. Read both before you build on this feed.

  • No public docs: endpoints can change without notice. The community wiki is the nearest reference.
  • No published rate limit: no response carried a rate-limit header, and 20 back-to-back requests all returned 200. Responses came from a cache with max-age=10 on the feed and 20 on the schedule, so polling faster than every 10 seconds gains little.
  • No support or uptime promise: MLB offers none for outside use.
  • No odds: the feed has no betting lines. MLB odds APIs cover that.

When your app earns money, serves many users or needs an uptime promise, move to licensed sports data providers. They sell MLB data under a commercial license, with support.

Browse API Providers →

Community Resources

MLB has no public docs, so these community projects are the best map of the API. We fetched each one in November 2026.

Frequently Asked Questions

Yes. Every endpoint on this page answered with no key, account or payment in our November 2026 test. MLB's usage notice limits what you do with the data: individual, non-commercial, non-bulk use only. Commercial use needs written permission from MLB Advanced Media.
MLB Advanced Media runs it for MLB's own apps, so the data is MLB's own. MLB does not document it for outside developers, though. There are no public docs, the root of statsapi.mlb.com is a sign-in page, and MLB promises nothing about stability. The best endpoint list is a community wiki on GitHub.
No. Send a plain GET request with your HTTP client's default headers. We used curl, Python requests and Node fetch with no key, token or cookie, and every endpoint on this page returned 200. The responses also carry access-control-allow-origin: *, so browser code can read them.
MLB plus 19 other levels, listed at /api/v1/sports: Triple-A (sportId 11) down to Rookie ball (16), Winter Leagues, college and high school baseball, international play, and Japan's NPB (31) and Korea's KBO (32). We tested MLB and Triple-A, and a Triple-A feed from September 2026 had full pitch data.
MLB publishes none. No response we got carried a rate-limit header, and 20 back-to-back requests all returned 200. Responses come from a cache with max-age=10 on the live feed and 20 on the schedule, so polling the feed faster than every 10 seconds gains little. Cache what you fetch, and stay clear of bulk use, which the notice forbids.
Call https://statsapi.mlb.com/api/v1/schedule?sportId=1&date=YYYY-MM-DD and read dates[0].games. Each game has a gamePk, both teams, the score and status.detailedState. Add hydrate=probablePitcher,linescore for the starters and inning scores. In the offseason dates is empty because no games are on.
Use the live game feed, https://statsapi.mlb.com/api/v1.1/game/{gamePk}/feed/live. liveData.plays.allPlays holds every plate appearance, and each one's playEvents hold the pitches with speed and spin. Our World Series test game had 70 plays and 255 pitches. The path needs v1.1: under v1 it returned 404.
Not for a commercial product without written permission from MLB: the notice allows individual, non-commercial, non-bulk use only. The API also has no docs, no support and no uptime promise. For a paid app, compare licensed sports data providers, or browse the API directory for MLB odds and stats.

Need Licensed MLB Data?

The MLB Stats API suits personal projects. A commercial app needs a license, support and an uptime promise. Compare licensed providers in our directory.