balldontlie dropped keyless access β€” host your own NBA-shaped API

For years, balldontlie was the teach-yourself-fetch sports API: www.balldontlie.io/api/v1/players, no key, no signup, real NBA data. It's in React course capstones, data-science notebooks, and a thousand "build an NBA stats app" tutorials. All of those URLs are now dead (we re-checked while writing this; our status page for it re-checks every 30 minutes):

$ curl https://www.balldontlie.io/api/v1/players
<!DOCTYPE html>…            // HTTP 404 β€” an HTML page, res.json() throws

$ curl https://api.balldontlie.io/v1/players
Unauthorized                 // HTTP 401 β€” every request needs an account API key

To be fair: balldontlie didn't die β€” it grew up. The current API is alive, maintained, and covers more sports than ever; it just requires creating an account and sending the key in an Authorization header, and the free tier is rate-limited to about 5 requests a minute, with advanced stats behind paid tiers. Fine for a personal project. Rough for the tutorial/classroom/CI use the old keyless API was loved for: a page of students burns 5 req/min instantly, keys don't belong in front-end example code, and a test suite shouldn't 429 because the demo API is metered.

1. One curl: your own NBA-shaped API

We host a starter dataset β€” all 30 NBA teams with balldontlie's exact field names (abbreviation, city, conference, division, full_name, name) plus 60 notable players (first_name, last_name, position, height_feet, height_inches, weight_pounds, and a teamId link). Pipe it into the importer:

curl -s https://mockbird.mockbird.workers.dev/data/nba.db.json \
| curl -s -X POST 'https://mockbird.mockbird.workers.dev/api/projects/import?name=nba' \
    --data-binary @-

The response contains your project id and an adminKey (save it). Your API is live immediately β€” no signup, no key, CORS on, no per-minute meter (limits are a flat 10k requests/day per project):

https://mockbird.mockbird.workers.dev/m/YOUR_ID/teams?limit=30
https://mockbird.mockbird.workers.dev/m/YOUR_ID/players

2. Every balldontlie URL, translated

balldontlieYour Mockbird API
/api/v1/teams/teams?limit=30 (default page size is 20)
/api/v1/players/players
/api/v1/players/28/players/28
/api/v1/players?search=curry/players?q=curry (or ?last_name_like=curry)
?page=2&per_page=5?page=2&limit=5
nested "team": {…} object on every player/players/28?_expand=team β€” joins the team record in via teamId; works on lists too
β€” (no equivalent)/teams/10/players β€” a team's roster as a nested route
β€” (no equivalent)/players?height_feet_gte=7 β€” range filters on any numeric field

And the response envelope. balldontlie wraps everything in {"data": […], "meta": {…}} β€” tutorial code destructures res.data everywhere. Mockbird returns a bare array by default, but a response-envelope template reproduces the original shape, either per-request or as a project-wide default:

curl 'https://mockbird.mockbird.workers.dev/m/YOUR_ID/players?limit=5&page=2&mock_envelope=%7B%22data%22%3A%22%24data%22%2C%22meta%22%3A%7B%22total_count%22%3A%22%24total%22%2C%22current_page%22%3A%22%24page%22%2C%22per_page%22%3A%22%24limit%22%7D%7D'

{"data":[…5 players…],
 "meta":{"total_count":60,"current_page":2,"per_page":5}}

That URL-encoded blob is just {"data":"$data","meta":{"total_count":"$total","current_page":"$page","per_page":"$limit"}}. Set it once as the project default in the dashboard's Response envelope card and existing res.data.map(…) tutorial code works unchanged.

3. When a trade happens, you PATCH it

The starter rosters are a snapshot β€” two notable players per team as of when we wrote the dataset. NBA rosters churn constantly, and that's the point: this is your data, with full CRUD. The next blockbuster trade is a one-liner:

curl -X PATCH "https://mockbird.mockbird.workers.dev/m/YOUR_ID/players/28" \
  -H 'content-type: application/json' -d '{"teamId": 1}'

GET /players/28?_expand=team now shows the new team. Add rookies with POST, cut players with DELETE, or paste a bigger roster file into the dashboard import panel (up to 1,000 records per collection). The same project also serves GraphQL over the same data, delay/error simulation for loading-state demos, and a db.json export so you can leave with your data anytime.

4. Honest comparison

balldontlie todayYour Mockbird project
Old tutorial URLs (/api/v1/…)✘ 404n/a β€” new base URL either way
Signup / API keyaccount + key in every requestnone
Rate limit (free)~5 requests/minute10k requests/day per project, no per-minute meter
Dataβœ” real, live NBA data back to 1979 β€” games, box scores, season averages (this is what you're paying the key for, and for a real stats app it's worth it)a frozen 30-team / 60-player starter snapshot; no games or stats
Writes✘ read-onlyβœ” full CRUD β€” trade, cut, sign players
Deterministic for tests/teaching✘ live data shifts under youβœ” same data every run; snapshots to save/restore states
Front-end safekey ends up in client code or a proxykeyless by design (optional mock auth if you want 401s to test)

Use the real thing when you need real stats. If your app's value is actual NBA numbers β€” live scores, season averages, historical box scores β€” sign up for balldontlie and put the key behind a small server-side proxy; no mock can substitute for real data. Mockbird replaces the other thing balldontlie was being used for: a free, keyless, NBA-shaped REST API to teach fetch calls, build UI against, and run tests on.

Create yours

The one-liner in section 1 is the whole setup β€” or open the dashboard and paste the dataset into the import panel. balldontlie joins the long list of once-keyless tutorial APIs that changed shape or vanished β€” ReqRes grew an upsell wrapper, restful-api.dev added an anonymous cap, boredapi and the Numbers API are gone outright (the live status board tracks 71 of them). Same fix works for all: ready-made quotes, activities, countries, number-facts, timezones, and currencies datasets, or host any CSV as an API.

⚑ Skip the terminal: this link creates a live, seeded e-commerce backend (products, orders, customers, reviews) in the dashboard β€” real URL, data browser already open, no signup. Or import your own OpenAPI spec, db.json, CSV, Postman collection, or HAR and mock your exact shapes.