Appearance
Getting the Data
API Host & Endpoints
API requests should be made to:
https://api.cleaningtheglass.com/pro/The API provides two endpoints:
| Endpoint | Description |
|---|---|
GET /game_status | Check the processing status of games |
GET /markings | Retrieve the markings 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
| 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." | 403 |
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.
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
| 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: delayed |
only_in_progress | No | boolean | If true, only return games currently being processed |
season | No | string | Filter to a specific NBA season, with the format YYYY for the year in which the season started. For example, 2025 returns games from the 2025-26 NBA season. |
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",
"game_status": "completed",
"tracking_stream": "processed.pose.clean",
"ctg_last_updated": "2025-11-15T04:23:15.123456+00:00"
},
{
"game_id_nba": "0022500242",
"nba_game_id": "0022500242",
"game_status": "in_progress",
"tracking_stream": "delayed.pose.clean",
"ctg_last_updated": "2025-11-15T20:48:01.326940+00:00"
}
]
}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.
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.
Markings Endpoint
GET /markingsRetrieve the markings data for a specific game.
Parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
game_id_nba | Yes | string | The NBA game ID (e.g., 0022500241) |
nba_game_id | Yes | string | deprecated Use game_id_nba instead |
stream_type | No | string | delayed or processed. Default: delayed |
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 |
processed | processed.pose.clean | Postgame processed data |
Request 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 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",
"stream_type": "processed",
"markings": {
"shots": [...],
"jump_shots": [...],
"interior_shots": [...],
"jump_shot_contests": [...],
"interior_shot_contests": [...],
"free_throws": [...],
"passes": [...],
"ball_screens": [...],
"dribbles": [...],
"jumps": [...],
"rebounds": [...],
"deflections": [...],
"after_shot_positioning": [...],
"closeouts": [...],
"drives": [...],
"falls": [...],
"fouls": [...],
"turnovers": [...],
"chances": [...],
"possessions": [...],
"possession_touches": [...],
"contested_rebound_touches": [...],
"anthro_measurements": [...],
"advantage_creation_1v1": [...]
}
}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.
Marking Types by Stream
All marking types you see here and in the Data Sets section are available in the postgame (processed) data. Live (delayed) data contains only a subset of these marking types (temporarily).
shotsjump_shotsinterior_shotsfree_throwsjump_shot_contestsinterior_shot_contestspassesball_screensdribblesjumpsfallsdeflectionsreboundscontested_rebound_toucheschancespossessionsafter_shot_positioningturnoversfoulsanthro_measurementscloseoutsdrivespossession_touchesadvantage_creation_1v1
Only the following marking types are currently available in the live (delayed) stream:
anthro_measurementschancescontested_rebound_touchesdeflectionsdribblesfallsfoulsfree_throwsinterior_shot_contestsinterior_shotsjump_shot_contestsjump_shotsjumpspassespossessionsreboundsshotsturnovers
Full descriptions and field definitions for each of these marking types are available in the Data Sets section.
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.
