Tutorial · 8 min · endpoints verified 2026-09-17

How to build a soccer player production board

Rank the production a competition actually serves, goals, appearances and minutes, while keeping empty leaderboards and unresolved player identity explicit.

API coverage and endpoint overview: Explore the soccer API

Why this is hard

A player board must survive uneven competition depth

Domestic leagues and tournaments do not all expose the same advanced statistics. A reusable product begins with measured coverage and renders only the player rows the selected competition actually serves.

  • Never substitute a big-five xG row into a competition that does not serve xG.
  • Use the competition slug from coverage rather than matching a display name by hand.
  • Treat a missing leaderboard as unavailable, not as a table full of zeroes.
  • Open a player profile only after canonical identity is present or uniquely resolved.

Path 1 · recommended

Have your AI agent build it

Use MCP to establish coverage and match context, then read the competition leaderboard over REST.

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

  • find_players

    Find canonical player IDs by name for use with player-stat tools.

  • 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 a soccer player production board for the competition I name. Check football coverage first, call its top-scorers route, and render only served goals, appearances and minutes. Keep an honest empty state when no leaderboard is published, and do not borrow xG or players from another league.

What the agent cannot reach

The MCP server does not expose competition scorer leaderboards. Use REST for that call, and do not treat a name-only row as canonical player identity.

Path 2 · hand-coded

Build it yourself

Make the coverage check and empty state part of the product, not an afterthought.

  1. 01

    Check the live coverage map first

    Ask the coverage endpoint what is served before you make a field required in your interface. An unavailable field should produce an honest empty state, not a guessed value.

    Verify soccer coveragebash
    curl -s "https://api.bigballsdata.com/v1/coverage?sport=football" \
      -H "x-api-key: $BBS_API_KEY"
  2. 02

    Request the selected competition only

    Replace the league slug with the exact value returned by coverage. An empty data array is a valid result and must not trigger a fallback to another competition.

    Competition production leadersbash
    curl -s "https://api.bigballsdata.com/v1/leagues/$LEAGUE/top-scorers?limit=50" \
      -H "x-api-key: $BBS_API_KEY"
  3. 03

    Render availability before rank

    Filter only malformed rows. Keep served zeroes, nulls and the response timestamp distinct so the interface can explain what is measured.

    Honest production rowstypescript
    const rows = Array.isArray(response.data) ? response.data : [];
    const view = rows.map((row) => ({
      player: row.player_name,
      goals: row.goals ?? null,
      appearances: row.matches ?? null,
      minutes: row.minutes ?? null,
    }));
    const unavailable = view.length === 0;

Reference

Every endpoint this tutorial uses

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

MethodPathReturnsWhy you need itPlan
GET/v1/coverage?sport=footballMeasured competition and dataset coveragePrevents a generic soccer interface from claiming one league's depth for every competition.Free
GET/v1/leagues/:id/top-scorersCompetition-scoped production leaders when publishedSupplies the board without requiring xG, xA or another unsupported enrichment.Free

Pricing, honestly

Free proves the production board

Coverage and served scorer rows are enough to validate the interface. Solo becomes relevant when the selected competition also serves paid player presentation or intelligence fields.

Free key

jsonjson
Coverage, competition identity and published production rows.

Solo

jsonjson
Player media and supported intelligence fields where the selected competition serves them.
  • An upgrade does not create a missing competition leaderboard.
  • Headshots remain a separate Solo capability.
  • Keep advanced metrics conditional on measured coverage.

More tutorials

Other build guides

Known gaps

What remains competition-specific

The shared schema does not imply identical depth.

  • Some tournament leaderboards can be empty between editions.
  • Name-only source rows cannot safely open a canonical player profile.
  • xG and assist boards remain separate capabilities with narrower coverage.

Questions

Does every soccer competition have a scorer leaderboard?
No. Check coverage and render the unavailable state instead of substituting another competition.
Can I treat a missing statistic as zero?
No. Null or absent means unavailable; a numeric zero is a measured result.
Does this tutorial require xG?
No. It deliberately builds from production fields and treats advanced metrics as optional enrichment.

Build the honest production board

Start with one competition slug, preserve the empty state, and add player detail only after identity resolves.