Appearance
Getting the Data
API Host & Endpoints
API requests should be made to:
https://api.cleaningtheglass.com/pro/The API provides the following endpoints:
| Endpoint | Description |
|---|---|
GET /game_status | Check the processing status of games |
GET /markings | Retrieve the markings data for a specific game |
GET /entities/teams | Retrieve NBA, Las Vegas Summer League, and G League team reference data |
GET /entities/leagues | Discover available league groups and exact league IDs |
GET /entities/players | Retrieve NBA, Las Vegas Summer League, and G League player reference data |
GET /entities/games | Retrieve NBA, Las Vegas Summer League, and G League game metadata |
GET /entities/game_players | Retrieve 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
Every error response is JSON with the message under an error key. Authorization errors also carry the same message under a result key, which is kept for existing clients, for example {"error": "Authorization Error: invalid API key.", "result": "Authorization Error: invalid API key."}. See also Request Errors.
| Scenario | Response | HTTP 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." (or delayed data. for live data) | 403 |
Evaluation Keys
An evaluation key gives access to a fixed set of games instead of the full season. If your key is an evaluation key:
GET /game_statusreturns only the games in your set. Use it to list the games you can download.GET /markingsreturns the full processed data for a game in your set. A game outside your set returns403.- Live data (
stream_type=delayed) is not included. Requests for it return403. - The entity endpoints (teams, leagues, players, games, game players) are not restricted.
| Scenario | Response | HTTP Status |
|---|---|---|
| Game outside your set | "Authorization Error: game 0022500999 is not in this key's game set. This evaluation key has access to 50 games. Call /game_status to list them." | 403 |
| Live data requested | "Authorization Error: evaluation keys have access to processed (postgame) data only. This evaluation key has access to 50 games. Call /game_status to list them." | 403 |
NBA-Family Entity Endpoints
Leagues
GET /entities/leaguesReturns the currently available league groups and seasons. NBA uses exact ID 00; Las Vegas Summer League uses exact ID 15; G League uses exact ID 20. Other Summer League tournaments are not currently exposed.
League-aware endpoints accept repeatable exact filters, for example ?league_id=00&league_id=15&league_id=20. Omitting the parameter defaults to NBA (00); unknown and unavailable IDs return 400.
The entity endpoints return reference data for NBA, Las Vegas Summer League, and G League games, players, and teams.
G League games can have partial tracking coverage, so a G League game is more likely to report complete_with_issues or degraded in data_quality_status. Check issues on /game_status before relying on a game.
Teams
GET /entities/teamsReturns NBA, Las Vegas Summer League, and G League team identifiers, league IDs, names, and abbreviations. League 00 also includes non-NBA clubs that play NBA preseason games.
| Parameter | Required | Type | Description |
|---|---|---|---|
league_id | No | string, repeatable | Exact 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
| Field | Type | Description |
|---|---|---|
team_id_nba | integer | NBA team ID |
league_id | string | Exact league ID: 00 for NBA, 15 for Las Vegas Summer League, or 20 for G League |
name | string | Full team name |
abbreviation | string | Three-letter team abbreviation |
Players
GET /entities/playersReturns NBA, Las Vegas Summer League, and G 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.
| Parameter | Required | Type | Description |
|---|---|---|---|
league_id | No | string, repeatable | Exact league ID. Defaults to NBA (00) |
active_only | No | boolean | If true, only return currently active roster players |
season | No | integer | Return players whose NBA career span includes this season start year |
limit | No | integer | Maximum 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
| Field | Type | Description |
|---|---|---|
player_id_nba | integer | NBA player ID |
league_id | string | Exact league ID for this player row |
first_name | string | Player first name |
last_name | string | Player last name |
player_slug | string | NBA slug for the player |
position | string | Listed player position |
height | string | Listed player height |
weight | string | Listed player weight |
jersey_num | string | Listed jersey number |
last_affiliation | string | Player's listed prior affiliation |
last_affiliation_type | string | Type of prior affiliation, such as college or international |
country | string | Player country |
draft_year | integer | NBA draft year |
draft_round | integer | NBA draft round |
draft_number | integer | Overall draft pick number |
roster_status | boolean | Whether the player is currently listed as active |
from_year | integer | First NBA season start year in the player index |
to_year | integer | Last NBA season start year in the player index |
season_experience | integer | Listed NBA seasons of experience |
birth_date | string | Player birth date |
age | integer | Player age in the NBA player index |
Games
GET /entities/gamesReturns NBA, Las Vegas Summer League, and G 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.
| Parameter | Required | Type | Description |
|---|---|---|---|
game_id_nba | No | string | Filter to a specific NBA game ID |
league_id | No | string, repeatable | Exact league ID. Defaults to 00 |
season | No | integer | Filter to a season start year, e.g. 2025 for 2025-26 |
season_type | No | string | Filter to an NBA season type such as Regular Season or Playoffs |
team_id_nba | No | string | Filter to games involving an NBA team ID |
completed | No | boolean | Filter by completed game status |
from_date | No | string | Inclusive lower bound for game_date, as YYYY-MM-DD. Any other format returns 400 |
to_date | No | string | Inclusive upper bound for game_date, as YYYY-MM-DD. Any other format returns 400 |
limit | No | integer | Maximum 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
| Field | Type | Description |
|---|---|---|
game_id_nba | string | NBA game ID |
game_date | string | Game date |
league_id | string | Exact league ID: 00 for NBA, 15 for Las Vegas Summer League, or 20 for G League |
season | integer | Season start year |
season_str | string | Season label, such as 2025-26 |
season_type | string | NBA season type, such as Regular Season or Playoffs |
home_team_id_nba | integer | NBA team ID for the home team |
away_team_id_nba | integer | NBA team ID for the away team |
home_score | integer | Home team score when available |
away_score | integer | Away team score when available |
periods | integer | Number of scheduled or completed game periods |
game_code | string | NBA game code |
game_status | integer | NBA game status code |
game_status_text | string | NBA game status text |
playoff_round | integer | Playoff round when applicable |
playoff_round_game | integer | Game number within the playoff round when applicable |
completed | boolean | Whether the game is final according to NBA schedule data |
game_sequence | integer | NBA schedule sequence number for the game date |
game_date_est | string | Game date in Eastern time |
game_time_est | string | Scheduled game time in Eastern time |
game_date_time_est | string | Scheduled game datetime in Eastern time |
game_date_utc | string | Game date in UTC |
game_time_utc | string | Scheduled game time in UTC |
game_date_time_utc | string | Scheduled game datetime in UTC |
if_necessary | boolean | Whether a playoff game is listed as if necessary |
series_game_number | integer | Game number within a playoff series when applicable |
game_label | string | NBA game label when available |
game_sub_label | string | NBA game sub-label when available |
series_text | string | NBA series text when available |
arena_name | string | Arena name |
arena_state | string | Arena state |
arena_city | string | Arena city |
postponed_status | string | Postponement status when available |
actual_start_time_utc | string | Actual game start time in UTC when available |
actual_end_time_utc | string | Actual game end time in UTC when available |
game_duration_seconds | integer | Game duration in seconds when available |
series_conference | string | Playoff series conference when applicable |
game_subtype | string | NBA game subtype when available |
Game Players
GET /entities/game_playersReturns boxscore roster and participation data for a specific NBA game.
| Parameter | Required | Type | Description |
|---|---|---|---|
game_id_nba | Yes | string | NBA 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
| Field | Type | Description |
|---|---|---|
game_id_nba | string | NBA game ID |
team_type | string | Whether the player's team was home or away |
team_id_nba | integer | NBA team ID |
team_name | string | Team name for that game |
player_id_nba | integer | NBA player ID |
player_name | string | Player name used in the boxscore |
position | string | Listed position for the game |
jersey_num | string | Jersey number for the game |
is_starter | boolean | Whether the player started the game |
did_play | boolean | Whether the player appeared in the game |
status | string | NBA boxscore participation status |
not_playing_reason | string | Reason the player did not play when available |
not_playing_description | string | Additional not-playing description when available |
Game Status Endpoint
GET /game_statusRetrieve 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. During a game, only some marking types have data on the delayed stream; see Live Data for how live data changes over the life of a game.
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.
EVALUATION KEYS
If your key is an evaluation key, this endpoint returns only the games in your set. It is the complete list of games you can download.
Parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
game_id_nba | No | string | Filter to a specific game (e.g., 0022500241) |
nba_game_id | No | string | deprecated Use game_id_nba instead |
stream_type | No | string | delayed (i.e. live) or processed. Default: processed |
only_in_progress | No | boolean | If true, only return games currently being processed |
season | No | string | Four-digit season year. NBA and G League use the season start year; Las Vegas Summer League uses the calendar year. |
league_id | No | string, repeatable | Exact 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",
"events_source": "postgame",
"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",
"events_source": "live",
"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)",
"impact": "degrading",
"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",
"events_source": "live",
"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, 15 for Las Vegas Summer League, or 20 for G League.
game_status
Type: string
The CTG processing status of this game:
| Status | Description |
|---|---|
in_progress | Game is currently being live-processed by CTG |
partial | Game was processed, but some data is missing |
completed | The complete game was processed |
tracking_stream
Type: string
The tracking stream used when generating the CTG markings:
| Value | Description |
|---|---|
delayed.pose.clean | Live/in-progress data stream |
processed.pose.clean | Postgame 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.
events_source
Type: string
Which events feed the game's markings were built with:
| Value | Description |
|---|---|
live | Markings built with the live events feed: every delayed stream row, and interim processed stream markings |
postgame | Final markings, built with the official postgame events feed |
A game can be published twice on the processed stream. CTG publishes interim markings with the live events feed as soon as postgame tracking is ready, then publishes the final markings when the official postgame events feed becomes available. The second publication changes ctg_last_updated and sets events_source to postgame. Re-pull the game's markings when ctg_last_updated changes, as described above, to replace the interim set with the final set.
data_quality_status
Type: string
What CTG knows about the quality of this game's data:
| Status | Description |
|---|---|
complete | CTG has not recorded any problems with this game's data |
complete_with_issues | The data is delivered and usable as a full game. CTG recorded only minor problems, such as gaps in tracking that add up to less than five minutes of the game, or fewer than 10 events missing from the HawkEye feed. Each one is listed in issues |
degraded | The data is delivered, but part of the game is affected. Every known problem is listed in issues |
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 complete_with_issues or 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.
A failed reprocess does not change a game's data_quality_status or issues: the game keeps the verdict from its last successful run.
A reprocessing guard keeps a game that is complete or complete_with_issues from being republished when the updated data would make it degraded. In that case, CTG keeps the game's current markings, data_quality_status, issues, and ctg_last_updated, and reviews the newer data manually before publishing it.
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 complete_with_issues or 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:
| Field | Type | Description |
|---|---|---|
source | string | Where the problem comes from: hawkeye (the tracking provider), nba (NBA data such as play-by-play), ctg (CTG's own processing), or unknown |
affected_data | array of string | Which families of data this affects, such as tracking or events |
period | integer, nullable | The period the problem is in. null when the problem is not tied to one period |
start_clock | string, nullable | Game 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_clock | string, nullable | Game 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 |
summary | string | One plain sentence describing the problem |
impact | string | minor when the problem leaves the game usable as a full game, or degrading when part of the game is affected. A game is degraded when any issue is degrading, and complete_with_issues when every issue is minor |
updated_at | string (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, a summary that gives the true total, and an impact of degrading if any of the summarized problems is degrading.
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",
"events_source": "postgame",
"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)",
"impact": "degrading",
"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",
"impact": "minor",
"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 /markingsRetrieve 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. During the game, each live update replaces the previous data set. After the game ends, we run an end of game update which contains the full marking set based on the delayed feed. See Live Data for details.
Note that markings from the processed feed are backfilled as we improve our markings over time, but the markings from the delayed feed are not backfilled.
Parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
game_id_nba | Yes | string | The NBA game ID (e.g., 0022500241) |
nba_game_id | No | string | deprecated Use game_id_nba instead |
stream_type | No | string | delayed or processed. Default: processed |
marking_types | No | string | Comma-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
| Value | Internal Stream | Description |
|---|---|---|
delayed | delayed.pose.clean | Live/in-progress game data. See Live Data |
processed | processed.pose.clean | Postgame processed data |
Request Errors
Request errors return the message under an error key, for example {"error": "game_id_nba is required"}. Authorization errors use the same error key and also repeat the message under result (see Authentication Errors).
| Scenario | Response | HTTP 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 processed stream: shot. Valid options: ..." (the message lists every valid marking type) | 400 |
| No markings for this game and stream | "No markings found for game_id_nba='0022500999' with stream_type=processed" | 404 |
A 404 also means the data is not published yet, for example during the first minutes of a game on the delayed stream or before postgame processing finishes on the processed stream.
A URL under /pro/ that matches no endpoint returns 404, and a method other than GET returns 405 with an Allow header. A server error returns 500 with {"error": "Internal error. Please try again later."}.
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",
"available_marking_types": ["advantage_creation_1v1", "after_shot_positioning", ...],
"markings": {
"shots": [...],
"jump_shots": [...],
"interior_shots": [...],
"jump_shot_contests": [...],
"interior_shot_contests": [...],
[...]
}
}| Field | Type | Description |
|---|---|---|
game_id_nba | string | NBA game ID |
nba_game_id | string | deprecated Use game_id_nba instead |
league_id | string | Exact league ID: 00 for NBA, 15 for Las Vegas Summer League, or 20 for G League |
stream_type | string | The stream you requested: delayed or processed |
available_marking_types | array of string | Sorted list of the marking types that this snapshot contains. It describes the whole snapshot and does not depend on marking_types |
markings | object | One array per requested marking type. A requested type that is not in the snapshot returns [] |
Use available_marking_types to read an empty list in markings:
- A type in
available_marking_typeswith[]inmarkingswas produced, and nothing occurred. - A type not in
available_marking_typeswas not produced in this snapshot. During a live game, this means it is not produced live yet. On older postgame games, it means CTG processed the game before that marking type existed.
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_typesparameter 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.
