Skip to content

Getting the Data

API Host & Endpoints

API requests should be made to:

https://api.cleaningtheglass.com/pro/

The API provides the following endpoints:

EndpointDescription
GET /game_statusCheck the processing status of games
GET /markingsRetrieve the markings data for a specific game
GET /entities/teamsRetrieve NBA and Las Vegas Summer League team reference data
GET /entities/leaguesDiscover available league groups and exact league IDs
GET /entities/playersRetrieve NBA and Las Vegas Summer League player reference data
GET /entities/gamesRetrieve NBA and Las Vegas Summer League game metadata
GET /entities/game_playersRetrieve player participation data for a specific game

Authentication

API requests require authentication via an API key which we will provide to you. Include your key in the X-API-KEY header of every request:

bash
curl --request GET \
  --url 'https://api.cleaningtheglass.com/pro/game_status' \
  --header 'X-API-KEY: YOUR_API_KEY'

Authentication Errors

ScenarioResponseHTTP Status
Missing API key"Authorization Required. Please include your API key in the X-API-KEY header."403
Invalid API key"Authorization Error: invalid API key."403
Insufficient permissions"Authorization Error: API key does not have access to processed data."403

NBA-Family Entity Endpoints

Leagues

GET /entities/leagues

Returns the currently available league groups and seasons. NBA uses exact ID 00; Las Vegas Summer League uses exact ID 15. Other Summer League tournaments and G League are not currently exposed.

League-aware endpoints accept repeatable exact filters, for example ?league_id=00&league_id=15. Omitting the parameter defaults to NBA (00); unknown and unavailable IDs return 400.

The entity endpoints return reference data for NBA and Las Vegas Summer League games, players, and teams.

Teams

GET /entities/teams

Returns NBA and Las Vegas Summer League team identifiers, league IDs, names, and abbreviations.

ParameterRequiredTypeDescription
league_idNostring, repeatableExact league ID. Defaults to NBA (00)
bash
curl --request GET \
  --url 'https://api.cleaningtheglass.com/pro/entities/teams' \
  --header 'X-API-KEY: YOUR_API_KEY'
json
{
  "data": [
    {
      "team_id_nba": 1610612757,
      "league_id": "00",
      "name": "Portland Trail Blazers",
      "abbreviation": "POR"
    }
  ]
}

Response Fields

FieldTypeDescription
team_id_nbaintegerNBA team ID
league_idstringExact league ID: 00 for NBA or 15 for Las Vegas Summer League
namestringFull team name
abbreviationstringThree-letter team abbreviation

Players

GET /entities/players

Returns NBA and Las Vegas Summer League player reference data. A player can appear once per requested league with league-specific roster metadata while retaining the same NBA player ID. For game-specific participation data, use the game_players endpoint.

ParameterRequiredTypeDescription
league_idNostring, repeatableExact league ID. Defaults to NBA (00)
active_onlyNobooleanIf true, only return currently active roster players
seasonNointegerReturn players whose NBA career span includes this season start year
limitNointegerMaximum number of rows to return. Default: 1000, max: 5000
bash
curl --request GET \
  --url 'https://api.cleaningtheglass.com/pro/entities/players?active_only=true&limit=1000' \
  --header 'X-API-KEY: YOUR_API_KEY'
json
{
  "data": [
    {
      "player_id_nba": 203999,
      "league_id": "00",
      "first_name": "Nikola",
      "last_name": "Jokic",
      "player_slug": "nikola-jokic",
      "position": "C",
      "height": "6-11",
      "weight": "284",
      "jersey_num": "15",
      "last_affiliation": "Serbia",
      "last_affiliation_type": "International",
      "country": "Serbia",
      "draft_year": 2014,
      "draft_round": 2,
      "draft_number": 41,
      "roster_status": true,
      "from_year": 2015,
      "to_year": 2025,
      "season_experience": 10,
      "birth_date": "1995-02-19",
      "age": 30
    }
  ]
}

Response Fields

FieldTypeDescription
player_id_nbaintegerNBA player ID
league_idstringExact league ID for this player row
first_namestringPlayer first name
last_namestringPlayer last name
player_slugstringNBA slug for the player
positionstringListed player position
heightstringListed player height
weightstringListed player weight
jersey_numstringListed jersey number
last_affiliationstringPlayer's listed prior affiliation
last_affiliation_typestringType of prior affiliation, such as college or international
countrystringPlayer country
draft_yearintegerNBA draft year
draft_roundintegerNBA draft round
draft_numberintegerOverall draft pick number
roster_statusbooleanWhether the player is currently listed as active
from_yearintegerFirst NBA season start year in the player index
to_yearintegerLast NBA season start year in the player index
season_experienceintegerListed NBA seasons of experience
birth_datestringPlayer birth date
ageintegerPlayer age in the NBA player index

Games

GET /entities/games

Returns NBA and Las Vegas Summer League game schedule and result metadata.

Game status and scores are refreshed periodically from NBA schedule data and may lag live game action by several minutes.

ParameterRequiredTypeDescription
game_id_nbaNostringFilter to a specific NBA game ID
league_idNostring, repeatableExact league ID. Defaults to 00
seasonNointegerFilter to a season start year, e.g. 2025 for 2025-26
season_typeNostringFilter to an NBA season type such as Regular Season or Playoffs
team_id_nbaNostringFilter to games involving an NBA team ID
completedNobooleanFilter by completed game status
from_dateNostringInclusive lower bound for game_date
to_dateNostringInclusive upper bound for game_date
limitNointegerMaximum number of rows to return. Default: 1000, max: 5000
bash
curl --request GET \
  --url 'https://api.cleaningtheglass.com/pro/entities/games?season=2025&completed=true&limit=100' \
  --header 'X-API-KEY: YOUR_API_KEY'
json
{
  "data": [
    {
      "game_id_nba": "0022500001",
      "game_date": "2025-10-21",
      "league_id": "00",
      "season": 2025,
      "season_str": "2025-26",
      "season_type": "Regular Season",
      "home_team_id_nba": 1610612743,
      "away_team_id_nba": 1610612744,
      "home_score": 109,
      "away_score": 111,
      "game_status": 3,
      "game_status_text": "Final",
      "completed": true
    }
  ]
}

Response Fields

FieldTypeDescription
game_id_nbastringNBA game ID
game_datestringGame date
league_idstringExact league ID: 00 for NBA or 15 for Las Vegas Summer League
seasonintegerSeason start year
season_strstringSeason label, such as 2025-26
season_typestringNBA season type, such as Regular Season or Playoffs
home_team_id_nbaintegerNBA team ID for the home team
away_team_id_nbaintegerNBA team ID for the away team
home_scoreintegerHome team score when available
away_scoreintegerAway team score when available
periodsintegerNumber of scheduled or completed game periods
game_codestringNBA game code
game_statusintegerNBA game status code
game_status_textstringNBA game status text
playoff_roundintegerPlayoff round when applicable
playoff_round_gameintegerGame number within the playoff round when applicable
completedbooleanWhether the game is final according to NBA schedule data
game_sequenceintegerNBA schedule sequence number for the game date
game_date_eststringGame date in Eastern time
game_time_eststringScheduled game time in Eastern time
game_date_time_eststringScheduled game datetime in Eastern time
game_date_utcstringGame date in UTC
game_time_utcstringScheduled game time in UTC
game_date_time_utcstringScheduled game datetime in UTC
if_necessarybooleanWhether a playoff game is listed as if necessary
series_game_numberintegerGame number within a playoff series when applicable
game_labelstringNBA game label when available
game_sub_labelstringNBA game sub-label when available
series_textstringNBA series text when available
arena_namestringArena name
arena_statestringArena state
arena_citystringArena city
postponed_statusstringPostponement status when available
actual_start_time_utcstringActual game start time in UTC when available
actual_end_time_utcstringActual game end time in UTC when available
game_duration_secondsintegerGame duration in seconds when available
series_conferencestringPlayoff series conference when applicable
game_subtypestringNBA game subtype when available

Game Players

GET /entities/game_players

Returns boxscore roster and participation data for a specific NBA game.

ParameterRequiredTypeDescription
game_id_nbaYesstringNBA game ID
bash
curl --request GET \
  --url 'https://api.cleaningtheglass.com/pro/entities/game_players?game_id_nba=0022500001' \
  --header 'X-API-KEY: YOUR_API_KEY'
json
{
  "data": [
    {
      "game_id_nba": "0022500001",
      "team_type": "home",
      "team_id_nba": 1610612743,
      "team_name": "Denver Nuggets",
      "player_id_nba": 203999,
      "player_name": "Nikola Jokic",
      "position": "C",
      "jersey_num": "15",
      "is_starter": true,
      "did_play": true,
      "status": "ACTIVE",
      "not_playing_reason": null,
      "not_playing_description": null
    }
  ]
}

Response Fields

FieldTypeDescription
game_id_nbastringNBA game ID
team_typestringWhether the player's team was home or away
team_id_nbaintegerNBA team ID
team_namestringTeam name for that game
player_id_nbaintegerNBA player ID
player_namestringPlayer name used in the boxscore
positionstringListed position for the game
jersey_numstringJersey number for the game
is_starterbooleanWhether the player started the game
did_playbooleanWhether the player appeared in the game
statusstringNBA boxscore participation status
not_playing_reasonstringReason the player did not play when available
not_playing_descriptionstringAdditional not-playing description when available

Game Status Endpoint

GET /game_status

Retrieve the processing status of games in the CTG system. Use this to discover which games have data available, their current processing state, and whether games have recently been processed.

An important parameter here is the stream_type: if you don't submit a stream_type, the system defaults to returning the data for the processed stream. This is the highest quality postgame stream. If you would like to see the status of live, in-game processing, you would use the delayed stream.

NOTE

This only includes games that have been processed already or games that are currently being processed. Games that will happen in the future are not available at this endpoint.

Parameters

ParameterRequiredTypeDescription
game_id_nbaNostringFilter to a specific game (e.g., 0022500241)
nba_game_idNostringdeprecated Use game_id_nba instead
stream_typeNostringdelayed (i.e. live) or processed. Default: processed
only_in_progressNobooleanIf true, only return games currently being processed
seasonNostringFour-digit season year. NBA uses the season start year; Las Vegas Summer League uses the calendar year.
league_idNostring, repeatableExact league ID. Defaults to 00

Example Request

bash
curl --request GET \
  --url 'https://api.cleaningtheglass.com/pro/game_status?stream_type=processed&season=2025' \
  --header 'X-API-KEY: YOUR_API_KEY'
python
import requests

response = requests.get(
    "https://api.cleaningtheglass.com/pro/game_status",
    headers={"X-API-KEY": "YOUR_API_KEY"},
    params={"stream_type": "processed", "season": "2025"}
)

games = response.json()["games"]
javascript
const response = await fetch(
  "https://api.cleaningtheglass.com/pro/game_status?stream_type=processed&season=2025",
  { headers: { "X-API-KEY": "YOUR_API_KEY" } }
);

const { games } = await response.json();

Example Response

json
{
  "games": [
    {
      "game_id_nba": "0022500241",
      "nba_game_id": "0022500241",
      "league_id": "00",
      "game_status": "completed",
      "tracking_stream": "processed.pose.clean",
      "ctg_last_updated": "2025-11-15T04:23:15.123456+00:00",
      "data_quality_status": "complete",
      "issues": []
    },
    {
      "game_id_nba": "0022500242",
      "nba_game_id": "0022500242",
      "league_id": "00",
      "game_status": "completed",
      "tracking_stream": "processed.pose.clean",
      "ctg_last_updated": "2025-11-15T18:12:44.882013+00:00",
      "data_quality_status": "degraded",
      "issues": [
        {
          "source": "hawkeye",
          "affected_data": ["tracking"],
          "period": 2,
          "start_clock": "07:31",
          "end_clock": "07:12",
          "summary": "No tracking for 19 seconds in period 2 (07:31 to 07:12)",
          "updated_at": "2025-11-15T21:04:52.118392+00:00"
        }
      ]
    },
    {
      "game_id_nba": "0022500243",
      "nba_game_id": "0022500243",
      "league_id": "00",
      "game_status": "in_progress",
      "tracking_stream": "delayed.pose.clean",
      "ctg_last_updated": "2025-11-15T20:48:01.326940+00:00",
      "data_quality_status": "complete",
      "issues": []
    }
  ]
}

Response Fields

game_id_nba

Type: string

The NBA game ID (e.g., "0022500241").


nba_game_id deprecated

Type: string

The NBA game ID. Use game_id_nba instead.

league_id

Type: string

The exact league ID: 00 for NBA or 15 for Las Vegas Summer League.

game_status

Type: string

The CTG processing status of this game:

StatusDescription
in_progressGame is currently being live-processed by CTG
partialGame was processed, but some data is missing
completedThe complete game was processed

tracking_stream

Type: string

The tracking stream used when generating the CTG markings:

ValueDescription
delayed.pose.cleanLive/in-progress data stream
processed.pose.cleanPostgame processed data stream

ctg_last_updated

Type: string (ISO 8601 timestamp)

The last time this game's data was updated by CTG (e.g., "2025-11-15T04:23:15.123456+00:00").

NOTE

We recommend that you monitor for updates to our data by polling the /game_status endpoint regularly to check for new games that have been processed, using this ctg_last_updated field. You can do so by hitting the endpoint without a game_id_nba parameter to get all games, and then check to see if any games have been updated since your last poll. The season parameter can be used to filter to a specific season to reduce the number of games you need to check.

data_quality_status

Type: string

What CTG knows about the quality of this game's data:

StatusDescription
completeCTG has not recorded any problems with this game's data
degradedThe data is delivered, but part of the game is affected. Every known problem is listed in issues
unavailableReserved for games CTG could not fully deliver. Writes for this status ship in a following release

CTG evaluates data quality only for games processed after this feature shipped. Games processed earlier report the default complete status, which does not mean CTG evaluated and cleared them.

game_status and data_quality_status are independent fields. game_status describes the processing and delivery lifecycle (in_progress, partial, completed). data_quality_status describes the quality of the delivered data, as evaluated postgame. A game can be completed and still degraded, and a partial live game carries no quality verdict on the delayed stream.

A degraded game still returns markings from /markings. Read issues to see which part of the game to treat with care.

NOTE

CTG evaluates data quality on the postgame processed stream. The quality writer only ever updates the processed row, so games on the delayed (live) stream always report the default complete status with an empty issues list — that value does not change for the delayed stream. Read the processed stream for a game's quality verdict.

issues

Type: array of object

The known problems behind a degraded status, in the order you would meet them watching the game: by period, then by game time. The list is empty when data_quality_status is complete.

Each entry has these fields:

FieldTypeDescription
sourcestringWhere the problem comes from: hawkeye (the tracking provider), nba (NBA data such as play-by-play), ctg (CTG's own processing), or unknown
affected_dataarray of stringWhich families of data this affects, such as tracking or events
periodinteger, nullableThe period the problem is in. null when the problem is not tied to one period
start_clockstring, nullableGame clock at the start of the affected span, as MM:SS remaining in the period (e.g., "07:31"). null when the problem is not tied to a game clock
end_clockstring, nullableGame clock at the end of the affected span, as MM:SS remaining in the period. null when the problem is not tied to a game clock
summarystringOne plain sentence describing the problem
updated_atstring (ISO 8601 timestamp)When CTG last evaluated this problem

A game with many problems returns at most 50 entries. When there are more, the last entry summarizes the rest: it has the same fields, a source of ctg, a null period and clocks, and a summary that gives the true total.

Example
json
{
  "game_id_nba": "0022500242",
  "nba_game_id": "0022500242",
  "league_id": "00",
  "game_status": "completed",
  "tracking_stream": "processed.pose.clean",
  "ctg_last_updated": "2025-11-15T18:12:44.882013+00:00",
  "data_quality_status": "degraded",
  "issues": [
    {
      "source": "hawkeye",
      "affected_data": ["tracking"],
      "period": 2,
      "start_clock": "07:31",
      "end_clock": "07:12",
      "summary": "No tracking for 19 seconds in period 2 (07:31 to 07:12)",
      "updated_at": "2025-11-15T21:04:52.118392+00:00"
    },
    {
      "source": "hawkeye",
      "affected_data": ["events"],
      "period": 4,
      "start_clock": "02:14",
      "end_clock": "02:14",
      "summary": "NBA foul event 512 has no HawkEye event in period 4 at 02:14",
      "updated_at": "2025-11-15T21:04:52.118392+00:00"
    }
  ]
}

IMPORTANT

ctg_last_updated does not change when only the quality verdict changes. It tells you when the markings themselves changed. If CTG re-evaluates a game and finds a new problem, or clears one, the markings are the same and ctg_last_updated stays where it was.

To react to quality updates without re-downloading markings, poll /game_status and compare issues[].updated_at against what you stored last time. Keep using ctg_last_updated to decide when to re-download markings.

Markings Endpoint

GET /markings

Retrieve the markings data for a specific game.

Generally you will want to use a stream_type of processed, which will provide our highest quality, postgame markings. (This is the default if that parameter is not provided.) For pulling live, in-game markings, you need to specify a stream_type of delayed. Markings from the processed feed are backfilled as we improve our markings over time. The markings from the delayed feed remain a point-in-time snapshot of what the markings delivery looked like when we last processed that data during the game and are not backfilled.

Parameters

ParameterRequiredTypeDescription
game_id_nbaYesstringThe NBA game ID (e.g., 0022500241)
nba_game_idYesstringdeprecated Use game_id_nba instead
stream_typeNostringdelayed or processed. Default: processed
marking_typesNostringComma-separated list of marking types to return. If not specified, all available types are returned. A list of available marking types is provided below.

TIP

We include the marking_types parameter as an option so that you can fetch a specific marking type that you are interested in without having to download the entire set of markings for a given game, since the size of this data can be quite large.

Example — Filtered Markings

bash
curl --request GET \
  --url 'https://api.cleaningtheglass.com/pro/markings?game_id_nba=0022500241&stream_type=processed&marking_types=shots,jump_shots,passes' \
  --header 'Accept-Encoding: gzip,deflate' \
  --header 'X-API-KEY: YOUR_API_KEY'
python
import requests

response = requests.get(
    "https://api.cleaningtheglass.com/pro/markings",
    headers={"X-API-KEY": "YOUR_API_KEY"},
    params={
        "game_id_nba": "0022500241",
        "stream_type": "processed",
        "marking_types": "shots,jump_shots,passes"
    }
)

markings = response.json()["markings"]
javascript
const params = new URLSearchParams({
  game_id_nba: "0022500241",
  stream_type: "processed",
  marking_types: "shots,jump_shots,passes"
});

const response = await fetch(
  `https://api.cleaningtheglass.com/pro/markings?${params}`,
  { headers: { "X-API-KEY": "YOUR_API_KEY" } }
);

const { markings } = await response.json();

NOTE

In the example above, we include the Accept-Encoding: gzip,deflate header on the request to reduce the response size significantly. We strongly recommend that as a best practice since the volume of this data can get to be quite large!

Stream Types

ValueInternal StreamDescription
delayeddelayed.pose.cleanLive/in-progress game data
processedprocessed.pose.cleanPostgame processed data

Request Errors

ScenarioResponseHTTP Status
Missing game_id_nba"game_id_nba is required"400
Invalid stream_type"Invalid stream_type 'invalid'. Valid options: delayed, processed"400
Invalid marking_types"Invalid marking types for delayed stream: closeouts, drives..."400
Game not found"No markings found for game_id_nba='0022500999'..."404

Response Structure

The /markings endpoint returns a JSON object with metadata and a markings object containing arrays for each marking type:

json
{
  "game_id_nba": "0022500241",
  "nba_game_id": "0022500241",
  "league_id": "00",
  "stream_type": "processed",
  "markings": {
    "shots": [...],
    "jump_shots": [...],
    "interior_shots": [...],
    "jump_shot_contests": [...],
    "interior_shot_contests": [...],
    [...]
  }
}

WARNING

We often update the data by adding new fields or new markings. We do not want to break your ingestion pipelines when we deploy new data, so please design your ingestion system to be resilient to the addition of new fields.

We will not remove or change fields without significant advanced notice.

Quick Start

Here's a minimal example to retrieve markings for a game:

bash
curl --request GET \
  --url 'https://api.cleaningtheglass.com/pro/markings?game_id_nba=0022500241&stream_type=processed' \
  --header 'Accept-Encoding: gzip,deflate' \
  --header 'X-API-KEY: YOUR_API_KEY'
python
import requests

response = requests.get(
    "https://api.cleaningtheglass.com/pro/markings",
    headers={"X-API-KEY": "YOUR_API_KEY"},
    params={
        "game_id_nba": "0022500241",
        "stream_type": "processed"
    }
)

data = response.json()

# Access different marking types
shots = data["markings"]["shots"]
jump_shots = data["markings"]["jump_shots"]
passes = data["markings"]["passes"]
javascript
const response = await fetch(
  "https://api.cleaningtheglass.com/pro/markings?game_id_nba=0022500241&stream_type=processed",
  {
    headers: { "X-API-KEY": "YOUR_API_KEY" }
  }
);

const data = await response.json();

// Access different marking types
const shots = data.markings.shots;
const jumpShots = data.markings.jump_shots;
const passes = data.markings.passes;

Verifying It Worked

A successful response will return a JSON object containing the game metadata and a markings object with arrays for each marking type:

json
{
  "game_id_nba": "0022500241",
  "nba_game_id": "0022500241",
  "stream_type": "processed",
  "markings": {
    "shots": [...],
    "jump_shots": [...],
    "passes": [...],
    ...
  }
}

If you see this structure, you're all set! Each array contains individual events from the game.

Next Steps

  • Explore the data: Check out the Data Sets section for detailed field definitions
  • Understand key concepts: Read Key Concepts to learn about coordinate systems, timestamps, and entity IDs
  • Filter your requests: Use the marking_types parameter to fetch only the data you need

LLM & Tooling Support

For teams using LLMs, we expose a few machine-readable helper files alongside this documentation:

  • /fields.json: A machine-readable catalog of data-set fields (by marking type), including type, units, and descriptions. This is the recommended starting point for code generation or schema validation.
  • /llms.txt: A short, high-level guide that explains the CTG Pro Markings API, key endpoints, and where the rest of the docs live.
  • /llms-full.txt: A single large text file that concatenates the main documentation pages and appends the full field catalog. Useful if your tooling prefers ingesting one big document.

These files are regenerated automatically from these docs so they should always stay in sync with the documentation.