Tutorial · 10 min · endpoints verified 2026-09-22

How to build an NBA matchup page

Follow the correct game identifier into one matchup response, then render team and player sections only when their samples are populated.

API coverage and endpoint overview: Explore the NBA API

Why this is hard

The hard part is identity and partial context, not layout

The matchup route assembles several useful blocks, but each block can have a different absence rule. A durable page needs one id chain and independent empty states.

  • The NBA games response can expose both canonical and league-native ids.
  • Team season stats can be null before a usable box-score sample exists.
  • Last-five form is null until the route has the documented minimum sample.
  • Player media and per-player season averages are independently nullable.

Path 1 · recommended

Have your AI agent build it

Use MCP for the canonical game list and REST for the NBA matchup package.

1. Connect the MCP server

Add the server in your MCP client and sign in with your Big Balls account. Your client registers itself and handles the token exchange — there is no key to copy.

MCP client configjson
{
  "mcpServers": {
    "bigballs-sports-data": {
      "url": "https://mcp.bigballsdata.com/mcp"
    }
  }
}

2. Tools your agent gets

  • get_matches

    Live, upcoming or historical matches for a sport or league.

  • get_coverage

    Machine-readable map of what we hold and what we do not.

3. Ask for what you want

Paste this at your agent. It is written to make the model check coverage before it designs anything, which is what stops it inventing a field we do not serve.

Prompttext
Build an NBA matchup page. Get the NBA match list first and preserve every
identifier exactly as returned. Call the NBA matchup REST route with the id it
documents. Render team season stats, last five, rest days and players as
independent panels; if one block is null, keep the rest of the page useful.

What the agent cannot reach

The matchup route is not an MCP tool. The agent must call it over REST and must not assume the shared match UUID is accepted where the route requires another game id.

Path 2 · hand-coded

Build it yourself

The workflow starts from the NBA-native game list because it publishes the identifier relationship the matchup route needs.

  1. 01

    List NBA games and keep both ids

    Request the NBA game list and preserve match_id and game_id in separate properties. Their names carry different contracts.

    List NBA gamesbash
    curl -s "https://api.bigballsdata.com/v1/nba/games?limit=10" \
      -H "Authorization: Bearer $BBS_API_KEY"
  2. 02

    Follow the matchup identifier

    Use the id documented by the matchup route. Fail visibly on a 400 rather than retrying the other id silently.

    Fetch the matchup packagebash
    curl -s "https://api.bigballsdata.com/v1/nba/games/$MATCH_ID/matchup" \
      -H "Authorization: Bearer $BBS_API_KEY"
  3. 03

    Render each block independently

    Let season stats, form, roster rows and head-to-head history declare their own availability. A null section should not erase populated siblings.

    Keep null boundaries localtypescript
    const view = {
      meta: matchup.match_meta,
      homeStats: matchup.home_team?.season_stats ?? null,
      homeForm: matchup.home_team?.last_5 ?? null,
      homePlayers: matchup.home_team?.players ?? [],
      headToHead: matchup.h2h ?? null,
    };

Reference

Every endpoint this tutorial uses

All on the gateway at api.bigballsdata.com. Verified against production on 2026-09-22.

MethodPathReturnsWhy you need itPlan
GET/v1/nba/gamesNBA-native games with the identifiers needed for detail routesThe safe starting point for the matchup id chain.Free
GET/v1/nba/games/:id/matchupMatch meta, team stats, form, players and head-to-head blocksThe page payload in one request. Read the identifier guide.Free

Pricing, honestly

The matchup page works on Free

The games and matchup routes have Free entry points. Optional modelled player tiers or rolling projections carry their own plan floor and should be added as separate panels.

Free matchup page

texttext
GET /v1/nba/games
GET /v1/nba/games/:id/matchup

Optional Solo models

texttext
GET /v1/players/:id/tier
GET /v1/players/:id/rolling-stats
  • The primary page is Free.
  • A null season block is a data state, not a paywall.
  • Solo model endpoints are optional enrichments.
  • Odds remain a separate Edge product.

More tutorials

Other build guides

Known gaps

What the first preview does not invent

Keep every panel backed by its response block.

  • No fake projected starters when a lineup is absent.
  • No synthesized team rating from partial box-score fields.
  • No image URL reconstructed from an NBA id.

Questions

Which id does the matchup route take?
Use the identifier documented and returned by the NBA games surface. Preserve canonical and native ids separately.
Why can last_5 be null?
The route withholds the block until it has the documented sample rather than returning a misleading partial form strip.
Does a null season_stats block mean the route failed?
No. It can mean the team has no qualifying box-score rows for that season while other matchup blocks remain useful.
Are roster headshots guaranteed?
No. headshot_url is nullable and needs an initials fallback.

Build the matchup page

Start from the NBA game list, follow the documented id, and let each panel prove its own data.