Getting Started

Quickstart

Make your first call to the StatsRadar API in under five minutes. Every account — including the free tier — can call all endpoints against sandbox demo games, so you can explore the full data shape before paying anything.

1. Get your API key

Sign up and create a key from the dashboard. Keys are scoped to an environment — start with a test key, which only reaches sandbox data. Every request sends the key as a bearer token — see Authentication.

2. Make your first call

List this week's matches. Copy, paste, run:

terminal
curl "https://api.statsradar.io/v1/matches?from=2026-07-01T00:00:00Z&until=2026-07-08T00:00:00Z" \
  -H "Authorization: Bearer $STATSRADAR_KEY"

Every response shares the same envelope — data plus an errorCode that is null on success:

{
  "data": [{
    "league": { "leagueId": "2074414626342305792", "name": "PBA" },
    "season": { "name": "Season 50", "type": "Philippine Cup" },
    "match": {
      "matchId": "2074795629401489408",
      "status": "live",
      "scheduledStartTime": "2026-07-01T10:00:00Z",
      "venueName": "Philippine Arena",
      "teams": [
        { "teamId": "2074418534968066048", "name": "Taguig Falcons",
          "abbreviation": "TGF", "isHomeTeam": true,  "score": "71" },
        { "teamId": "2074418534968066050", "name": "Cebu Mariners",
          "abbreviation": "CEB", "isHomeTeam": false, "score": "68" }
      ]
    }
  }],
  "errorCode": null
}

3. Understand the data model

One consistent schema across every league. Resources form a hierarchy, and every ID is stable and globally unique:

League Season Match Team Player Box Score

Match lifecycle

Every match carries a status following this lifecycle — scheduled → delayed → live → completed → closed:

scheduled Match is planned, scheduled start time is in the future
postponed Postponed and awaiting rescheduling; scheduled start time updated upon rescheduling
delayed Scheduled start time has passed but the match has not yet begun
live Match is in progress, live scores available
completed Match has ended, scores available but not yet verified
closed Scores verified and finalized
cancelled Match will not be played
API Reference →
Every endpoint, parameter and schema, generated from our OpenAPI spec.
Core concepts →
The data model, response envelope, match lifecycle and time conventions.
Getting Started

Authentication

Every StatsRadar API endpoint requires authentication. Send your API key as a bearer token in the Authorization header of each request.

The Authorization header

Pass the key using the standard HTTP bearer scheme:

terminal
curl "https://api.statsradar.io/v1/leagues" \
  -H "Authorization: Bearer $STATSRADAR_KEY"

Keys are scoped to an environment — a test key reaches sandbox data only, a live key reaches production data. Create and rotate keys from your dashboard.

Unauthorized requests

A request with a missing or invalid key returns 401 with the standard envelope:

{
  "data": null,
  "errorCode": "UNAUTHORIZED"
}

Your key also determines which leagues you can read — GET /v1/leagues returns exactly the leagues your key is authorized for.

Keep keys secret

Never embed API keys in client-side code, mobile apps or public repositories. Call the API from your backend and proxy what your frontend needs. If a key may have been exposed, rotate it immediately from the dashboard.

Core Concepts

Data model

One consistent schema across every league. Resources form a hierarchy, and every ID is a stable, globally unique string.

League Season Match Team Player Box Score

Entities

League
League metadata. /v1/leagues returns the leagues your API key is authorized to read.
leagueId, name
Season
Season metadata — a name like "Season 50" plus a league-defined type such as "Philippine Cup".
name, type
Match
A match with its lifecycle status, timestamps and the two participating teams.
matchId, status, scheduledStartTime, actualStartTime, actualEndTime, cancelledTime, closedTime, venueName, teams
Team
Team information within a match. isWon and score are null before the result exists.
teamId, name, abbreviation, logo, isHomeTeam, isWon, score
Player
A player, as rostered on a team or as a match participant with lineup status and availability.
playerId, name, firstName, middleName, lastName, avatar, jerseyNumber, position, lineupStatus, status, teamId
Box score
Per-player statistics for one match. Shot groups carry attempted / made / rate-in-percent; fourPointers* only where the league supports four-point shots.
secondsPlayed, points, fieldGoals*, twoPointers*, threePointers*, fourPointers*, freeThrows*, assists, rebounds, defensiveRebounds, offensiveRebounds, steals, blocks, personalFouls, turnovers

IDs

All identifiers — leagueId, matchId, teamId, playerId — are strings, stable across requests and globally unique across leagues. Treat them as opaque: don't parse or derive meaning from them.

Nullable fields

Fields whose value doesn't exist yet are null, not omitted — e.g. a match's actualStartTime before tip-off, a team's isWon and score before a result exists, or a player's boxScore before they've recorded statistics.

Core Concepts

Response envelope

Every endpoint returns the same JSON envelope: a data payload plus an errorCode that is null on success.

Success

data holds the result — an array for list endpoints, an object for detail endpoints:

{
  "data": [
    { "leagueId": "2074414626342305792", "name": "PBA" }
  ],
  "errorCode": null
}

Errors

On failure, data is null and errorCode identifies the problem. The HTTP status code always matches the error code:

{
  "data": null,
  "errorCode": "BAD_REQUEST"
}
BAD_REQUEST 400 Invalid or missing parameters — e.g. a time range over 7 days, or until not strictly after from.
UNAUTHORIZED 401 Missing or invalid API key in the Authorization header.
RESOURCE_NOT_FOUND 404 The requested resource (league, team, match…) does not exist.
INTERNAL_ERROR 500 Something went wrong on our side. Safe to retry with backoff.

Branch on errorCode (or the HTTP status) rather than parsing messages — the set of codes is stable and message text may change.

Core Concepts

Match lifecycle

Every match carries a status field. The main flow is scheduled → delayed → live → completed → closed, with two branches for postponements and cancellations.

Statuses

scheduled Match is planned, scheduled start time is in the future
postponed Postponed and awaiting rescheduling; scheduled start time updated upon rescheduling
delayed Scheduled start time has passed but the match has not yet begun
live Match is in progress, live scores available
completed Match has ended, scores available but not yet verified
closed Scores verified and finalized
cancelled Match will not be played

Transitions

A match in scheduled or delayed can branch to postponed, and returns to scheduled once rescheduled — with an updated scheduledStartTime.

Any state before closed — that is scheduled, postponed, delayed, live or completed — can transition to cancelled. Once closed, scores are verified and final.

Timestamps per status

A match's time fields fill in as it progresses through the lifecycle; each is null until its milestone is reached:

scheduledStartTimeAlways present. Updated when a postponed match is rescheduled.
actualStartTimeSet when the match goes live.
actualEndTimeSet when the match is completed.
closedTimeSet when scores are verified and the match is closed.
cancelledTimeSet only when the match is cancelled.

Live updates

While a match is live, its score and status update in real time on the match endpoints. Scores visible in completed may still receive corrections; treat closed as the finalized record.

Core Concepts

Time & timezones

All timestamps in the API — request parameters and response fields alike — use ISO 8601 in UTC, e.g. 2026-07-01T10:00:00Z. Convert to local time in your application.

Time-range queries

Match listing endpoints filter on the scheduled start time with a from / until pair:

fromStart of the range — inclusive.
untilEnd of the range — exclusive. Must be strictly after from.

The maximum range is 7 days; a longer range returns 400 BAD_REQUEST. To cover a season, page through consecutive 7-day windows — the exclusive until means windows chain without overlap:

terminal
curl "https://api.statsradar.io/v1/matches?from=2026-07-01T00:00:00Z&until=2026-07-08T00:00:00Z" \
  -H "Authorization: Bearer $STATSRADAR_KEY"

Match time fields

Matches carry scheduledStartTime, actualStartTime, actualEndTime, closedTime and cancelledTime — all ISO 8601 UTC, and null until the corresponding lifecycle milestone is reached. See Match lifecycle.

API Reference / Leagues
GET /v1/leagues Free+

Get leagues

Returns the leagues your API key is authorized to read. Use the returned leagueId to scope every other league-level request.

Parameters

No parameters.

Errors

401 UNAUTHORIZED — missing or invalid API key.
500 INTERNAL_ERROR — something went wrong on our side.
curl "https://api.statsradar.io/v1/leagues" \
  -H "Authorization: Bearer $STATSRADAR_KEY"
Response · 200
{
  "data": [
    {
      "leagueId": "2074414626342305792",
      "name": "PBA"
    },
    {
      "leagueId": "2074414626342305793",
      "name": "MPBL"
    }
  ],
  "errorCode": null
}
Signed in? Try it runs this request with your own API key against live or sandbox data.
API Reference / Matches
GET /v1/matches Free+

Get matches by scheduled start time range

Returns matches whose scheduled start time falls in the given range, grouped by league and season. During live matches, score and status update in real time. Also available scoped to one league via /v1/leagues/{leagueId}/matches.

Query parameters

from string required
Start of the scheduled start time range (inclusive), ISO 8601 UTC format. e.g. 2026-07-01T00:00:00Z
until string required
End of the scheduled start time range (exclusive), ISO 8601 UTC format. Must be strictly after from. Maximum range is 7 days.

Errors

400 BAD_REQUEST — invalid or missing parameters.
401 UNAUTHORIZED — missing or invalid API key.
500 INTERNAL_ERROR — something went wrong on our side.
curl "https://api.statsradar.io/v1/matches?from=2026-07-01T00:00:00Z&until=2026-07-08T00:00:00Z" \
  -H "Authorization: Bearer $STATSRADAR_KEY"
Response · 200
{
  "data": [{
    "league": {
      "leagueId": "2074414626342305792",
      "name": "PBA"
    },
    "season": {
      "name": "Season 50",
      "type": "Philippine Cup"
    },
    "match": {
      "matchId": "2074795629401489408",
      "status": "completed",
      "scheduledStartTime": "2026-07-01T10:00:00Z",
      "actualStartTime": "2026-07-01T10:05:00Z",
      "actualEndTime": "2026-07-01T12:15:00Z",
      "cancelledTime": null,
      "closedTime": null,
      "venueName": "Philippine Arena",
      "teams": [{
        "teamId": "2074418534968066048",
        "name": "Taguig Falcons",
        "abbreviation": "TGF",
        "logo": "https://cdn.statsradar.io/tgf.png",
        "isHomeTeam": true,
        "isWon": true,
        "score": "105"
      }, {
        "teamId": "2074418534968066050",
        "name": "Cebu Mariners",
        "abbreviation": "CEB",
        "logo": "https://cdn.statsradar.io/ceb.png",
        "isHomeTeam": false,
        "isWon": false,
        "score": "98"
      }]
    }
  }],
  "errorCode": null
}
Signed in? Try it runs this request with your own API key against live or sandbox data.
API Reference / Matches
GET /v1/leagues/{leagueId}/matches Free+

Get matches of a league by scheduled start time range

Returns matches of a single league whose scheduled start time falls in the given range, grouped by season. Same match shape as /v1/matches, without the league wrapper.

Path parameters

leagueId string required
League ID. e.g. 2074414626342305792

Query parameters

from string required
Start of the scheduled start time range (inclusive), ISO 8601 UTC format. e.g. 2026-07-01T00:00:00Z
until string required
End of the scheduled start time range (exclusive), ISO 8601 UTC format. Must be strictly after from. Maximum range is 7 days.

Errors

400 BAD_REQUEST — invalid or missing parameters.
404 RESOURCE_NOT_FOUND — the requested resource does not exist.
401 UNAUTHORIZED — missing or invalid API key.
500 INTERNAL_ERROR — something went wrong on our side.
curl "https://api.statsradar.io/v1/leagues/2074414626342305792/matches?from=2026-07-01T00:00:00Z&until=2026-07-08T00:00:00Z" \
  -H "Authorization: Bearer $STATSRADAR_KEY"
Response · 200
{
  "data": [{
    "season": {
      "name": "Season 50",
      "type": "Philippine Cup"
    },
    "match": {
      "matchId": "2074795629401489408",
      "status": "live",
      "scheduledStartTime": "2026-07-01T10:00:00Z",
      "actualStartTime": "2026-07-01T10:05:00Z",
      "actualEndTime": null,
      "cancelledTime": null,
      "closedTime": null,
      "venueName": "Philippine Arena",
      "teams": [{
        "teamId": "2074418534968066048",
        "name": "Taguig Falcons",
        "abbreviation": "TGF",
        "logo": "https://cdn.statsradar.io/tgf.png",
        "isHomeTeam": true,
        "isWon": null,
        "score": "71"
      }, {
        "teamId": "2074418534968066050",
        "name": "Cebu Mariners",
        "abbreviation": "CEB",
        "logo": "https://cdn.statsradar.io/ceb.png",
        "isHomeTeam": false,
        "isWon": null,
        "score": "68"
      }]
    }
  }],
  "errorCode": null
}
Signed in? Try it runs this request with your own API key against live or sandbox data.
API Reference / Matches
GET /v1/matches/{matchId} Free+

Get match detail by match ID

Returns detailed information for one match, including every participating player with lineup status, availability and a per-player box score. boxScore is null until the player has recorded statistics in the match.

Path parameters

matchId string required
Match ID. e.g. 2074795629401489408

Notes

position is one of SF (small forward), PF (power forward), PG (point guard), SG (shooting guard), C (center).
lineupStatus is one of undecided (lineup decision not yet made), starter (in the starting lineup), substitute (on the bench).
status is active (available to play in this match) or out (will not play in this match).
The fourPointers* box score fields are present only for leagues where four-point shots are supported.

Errors

404 RESOURCE_NOT_FOUND — the requested resource does not exist.
401 UNAUTHORIZED — missing or invalid API key.
500 INTERNAL_ERROR — something went wrong on our side.
curl "https://api.statsradar.io/v1/matches/2074795629401489408" \
  -H "Authorization: Bearer $STATSRADAR_KEY"
Response · 200
{
  "data": {
    "league": {
      "leagueId": "2074414626342305792",
      "name": "PBA"
    },
    "season": {
      "name": "Season 50",
      "type": "Philippine Cup"
    },
    "match": {
      "matchId": "2074795629401489408",
      "status": "completed",
      "scheduledStartTime": "2026-07-01T10:00:00Z",
      "actualStartTime": "2026-07-01T10:05:00Z",
      "actualEndTime": "2026-07-01T12:15:00Z",
      "cancelledTime": null,
      "closedTime": null,
      "venueName": "Philippine Arena",
      "teams": [{
        "teamId": "2074418534968066048",
        "name": "Taguig Falcons",
        "abbreviation": "TGF",
        "logo": "https://cdn.statsradar.io/tgf.png",
        "isHomeTeam": true,
        "isWon": true,
        "score": "105"
      }, {
        "teamId": "2074418534968066050",
        "name": "Cebu Mariners",
        "abbreviation": "CEB",
        "logo": "https://cdn.statsradar.io/ceb.png",
        "isHomeTeam": false,
        "isWon": false,
        "score": "98"
      }],
      "players": [{
        "playerId": "2074428573690757122",
        "name": "John Michael Doe",
        "firstName": "John",
        "middleName": "Michael",
        "lastName": "Doe",
        "avatar": "https://cdn.statsradar.io/avatars/doe.png",
        "jerseyNumber": "10",
        "position": "PG",
        "lineupStatus": "starter",
        "status": "active",
        "teamId": "2074418534968066048",
        "boxScore": {
          "secondsPlayed": 1440,
          "points": 20,
          "fieldGoalsAttempted": 15,
          "fieldGoalsMade": 8,
          "fieldGoalsRateInPercent": "53.33",
          "twoPointersAttempted": 12,
          "twoPointersMade": 8,
          "twoPointersRateInPercent": "66.67",
          "threePointersAttempted": 3,
          "threePointersMade": 0,
          "threePointersRateInPercent": "0.0",
          "freeThrowsAttempted": 4,
          "freeThrowsMade": 4,
          "freeThrowsRateInPercent": "100.0",
          "assists": 1,
          "rebounds": 3,
          "defensiveRebounds": 2,
          "offensiveRebounds": 1,
          "steals": 1,
          "blocks": 0,
          "personalFouls": 0,
          "turnovers": 0
        }
      }]
    }
  },
  "errorCode": null
}
Signed in? Try it runs this request with your own API key against live or sandbox data.
API Reference / Teams
GET /v1/leagues/{leagueId}/teams Free+

Get teams of a league

Returns the teams of a league, with full name, abbreviation and logo URL.

Path parameters

leagueId string required
League ID. e.g. 2074414626342305792

Errors

400 BAD_REQUEST — invalid or missing parameters.
404 RESOURCE_NOT_FOUND — the requested resource does not exist.
401 UNAUTHORIZED — missing or invalid API key.
500 INTERNAL_ERROR — something went wrong on our side.
curl "https://api.statsradar.io/v1/leagues/2074414626342305792/teams" \
  -H "Authorization: Bearer $STATSRADAR_KEY"
Response · 200
{
  "data": [
    {
      "teamId": "2074418534968066048",
      "name": "Barangay Ginebra San Miguel",
      "abbreviation": "GIN",
      "logo": "https://cdn.statsradar.io/logos/ginebra.png"
    },
    {
      "teamId": "2074418534968066050",
      "name": "Cebu Mariners",
      "abbreviation": "CEB",
      "logo": "https://cdn.statsradar.io/logos/ceb.png"
    }
  ],
  "errorCode": null
}
Signed in? Try it runs this request with your own API key against live or sandbox data.
API Reference / Teams
GET /v1/leagues/{leagueId}/teams/{teamId}/players Free+

Get players currently on a team

Returns players currently on a team, including name parts, avatar, jersey number and position.

Path parameters

leagueId string required
League ID. e.g. 2074414626342305792
teamId string required
Team ID. e.g. 2074418534968066048

Notes

middleName is an empty string when the player has none.
position is one of SF, PF, PG, SG, C.

Errors

400 BAD_REQUEST — invalid or missing parameters.
404 RESOURCE_NOT_FOUND — the requested resource does not exist.
401 UNAUTHORIZED — missing or invalid API key.
500 INTERNAL_ERROR — something went wrong on our side.
curl "https://api.statsradar.io/v1/leagues/2074414626342305792/teams/2074418534968066048/players" \
  -H "Authorization: Bearer $STATSRADAR_KEY"
Response · 200
{
  "data": [
    {
      "playerId": "2074428573690757122",
      "name": "John Michael Doe",
      "firstName": "John",
      "middleName": "Michael",
      "lastName": "Doe",
      "avatar": "https://cdn.statsradar.io/avatars/doe.png",
      "jerseyNumber": "10",
      "position": "PG"
    }
  ],
  "errorCode": null
}
Signed in? Try it runs this request with your own API key against live or sandbox data.
API Reference / Players
GET /v1/leagues/{leagueId}/players/injuries Free+

Get currently injured players of a league

Returns currently injured players of a league. Only injuries the player has not recovered from yet are included; each player’s injuries are ordered newest first and the list is never empty.

Path parameters

leagueId string required
League ID. e.g. 2074414626342305792

Notes

bodyPart is one of: achilles_tendon, ankle, arm, back, calf, chest, collarbone, elbow, finger, foot, forearm, groin, hamstring, hand, hip, knee, lower_back, neck, quad, ribs, shoulder, thigh, toe, wrist, other.

Errors

400 BAD_REQUEST — invalid or missing parameters.
404 RESOURCE_NOT_FOUND — the requested resource does not exist.
401 UNAUTHORIZED — missing or invalid API key.
500 INTERNAL_ERROR — something went wrong on our side.
curl "https://api.statsradar.io/v1/leagues/2074414626342305792/players/injuries" \
  -H "Authorization: Bearer $STATSRADAR_KEY"
Response · 200
{
  "data": [
    {
      "playerId": "2074428573690757122",
      "injuries": [
        {
          "bodyPart": "ankle",
          "injuryTime": "2026-06-04T00:00:00Z"
        }
      ]
    }
  ],
  "errorCode": null
}
Signed in? Try it runs this request with your own API key against live or sandbox data.