ShotTracker Broadcast API Overview

Use Cases

The broadcast game day service is used to enhance the live viewing of games with in broadcast stats and high sample rate location data. Past integrations have been:

  • In venue graphics for display and video boards

  • Enhanced 3D broadcast video with location tracking; stats, distance, clocks, etc…

  • Enhanced 2D broadcast graphics with stats, shot charts, zone maps, etc…

Authentication

An API key is required on all game data service endpoints. The API key identifies the calling stats data consumer and is passed either on the URL

?apikey=your api key

or as a HTTP header:

apikey: your api key

Please contact ShotTracker to obtain an API key.

Environment Connections

Production ShotTracker Cloud Service API

In-venue UDP Multicast

  • ip address: 239.251.101.6

  • port: 8668

Data Plotting Concepts

Locations XY Orientation

fullcourtxydirections

Zone Map Locations

Shots are assigned a zone number 1 - 14 that represents the specific location around the hoop the shot occurred. The map below shows the shot zones.

zonemap

Advanced Zone Map Locations

Shots are assigned an advanced zone number 1 - 23 that represents the specific location around the hoop the shot occurred. The map below shows the shot advanced zone.

advzonemap

Shot Chart Plotting

Shot data contains a hoop_player_x and hoop_player_y that represents the xy location of the shot from the hoop. Representing a shot from the hoop assumes that the positive y runs from the hoop to the center of the court and positive x runs from the hoop to the right.

halfcourtxydirections

Data Overview

In-venue UDP Multicast CSV Data

The broadcast data collection is tailored to work with specific consumers needing access to very high sample rate sensor locations and full stats. The data is provided in 2 locations, sensor xy’s come from the ShotTracker local server installed at the facility and full stats from the ShotTracker cloud. Below represents the consumers connection diagram:

game_data

  1. The consumer resides on the same network as the ShotTracker local server where location data is emitted UDP via multicast. This data represents the exact location in xy of each ball and player sensor at the defined sample rate. See the Locations CSV Format section for a complete definition of each field.

  2. Full game stats is delivered from the ShotTracker cloud. This is delivered as a JSON file each time a stat occurs, half or quarter change, or a player sensor assignment is changed. See the Full Game Stats JSON Format for a complete description of each field.

Important Note The consumer must pull the players sensor assignments, either from the Attributes Endpoint or receive them directly from the Stats Endpoint, to know which sensor number in the CSV is what player.

Ping

The ShotTracker server will always send a ping event which is used to inidicate the connection is alive. Ping messages will be sent every minute.

(CSV Data)
event_timestamp,event_structure_version,ping

(Data Description)
event_timestamp = the time the event occurred in UTC ms
event_structure_version = the version of this event structure; will be 2
ping = the name of the event; will always be ping

When a game is active, the ShotTracker server will also send the player and ball locations with the following format. The version that will be sent is the most recent (greatest) version number unless pre-configured otherwise to support legacy consumers.

Player / Ball Locations v2

(CSV Data)
event_timestamp,event_structure_version,event_type,game_clock,shot_clock,stop_flag,tag_serial_number,X,Y,Z

(Data Description)
event_timestamp = the time the event occurred in UTC ms
event_structure_version = the version of the event structure; v2
event_type = player or ball location data
game_clock = MM:SS.T formatted clock data, MM = minute, SS = second, T = subsecond (depending on time subsecond might be missing)
shot_clock = SS.T formatted clock data, SS = second, T = subsecond (depending on time subsecond might be missing)
stop_flag = 0 if clock is running; 1 if clock is stopped
tag_serial_number = the unique serial number of the device
X, Y, Z = mm location of the tag relative to the court coordinate system where the center of the court is 0,0

Sample:
1611805439518,2,player,19:59.0,30.0,1,105645,-6113,-23444,1763
1611805439518,2,ball,19:59.0,30.0,0,2147583169,-1004,-23,455

Note: if game/shot clock is not available these fields will be empty

Click here to download a full game example of the v2 player/ball locations.

Player / Ball Locations v3

(player CSV Data)
event_timestamp,event_structure_version,player,game_clock,shot_clock,stop_flag,tag_serial_number,player_id,team_id,X,Y,Z,distance,Vx,Vy,V
(ball CSV Data)
event_timestamp,event_structure_version,ball,game_clock,shot_clock,stop_flag,tag_serial_number,X,Y,Z,distance,Vx,Vy,V

(Data Description)
event_timestamp = the time the event occurred in UTC ms
event_structure_version = the version of the event structure; v2
player or ball = the given name of the event
game_clock = MM:SS.T formatted clock data, MM = minute, SS = second, T = subsecond (depending on time subsecond might be missing)
shot_clock = SS.T formatted clock data, SS = second, T = subsecond (depending on time subsecond might be missing)
stop_flag = 0 if clock is running; 1 if clock is stopped
tag_serial_number = the unique serial number of the device
player_id = the DDSports id representing the player; only provided for player
team_id = the DDSports id representing the team; only provided for player
X, Y, Z = mm location of the tag relative to the court coordinate system where the center of the court is 0,0
distance = distance the object has traveled since in the network, a running total in km
Vx, Vy = instantaneous velocities in the x and y directions in m/s
V = speed in m/s

Sample:
1611805439518,3,player,19:59.0,30.0,1,105645,18672,461,-6113,-23444,1763,0,0,0,0
1611805439518,3,ball,19:59.0,30.0,0,2147583169,-1004,-23,455,0,0,0,0

Note: if game/shot clock is not available these fields will be empty

Player Ball Possessions

The possession events indicate at an exact moment in time which player tag is possessing which ball. The events are broken into 2 separate events, got possession (or when the player got possession of the ball) and lost possesion (or when the player lost possession of the ball).

Got Possession v2

(CSV Data)
event_timestamp,event_structure_version,event_type,game_clock,shot_clock,stop_flag,player_tag_serial_number,X,Y,Z,ball_tag_serial_number

(Data Description)
event_timestamp = the time the event occurred in UTC ms
event_structure_version = the version of the event structure; v2
event_type = gotpossession
game_clock = MM:SS.T formatted clock data, MM = minute, SS = second, T = subsecond (depending on time subsecond might be missing)
shot_clock = SS.T formatted clock data, SS = second, T = subsecond (depending on time subsecond might be missing)
stop_flag = 0 if clock is running; 1 if clock is stopped
player_tag_serial_number = the serial number of the players tag
X, Y, Z = mm location of the tag relative to the court coordinate system where the center of the court is 0,0
ball_tag_serial_number = the serial number of the ball the player tag is possessing

Sample:
1611805439518,2,gotpossession,19:59.0,30.0,1,105645,-6113,-23444,1763,2147583169

Got Possession v4

(CSV Data)
event_timestamp,event_structure_version,event_type,game_clock,shot_clock,stop_flag,player_tag_serial_number,player_id,team_id,X,Y,Z,ball_tag_serial_number

(Data Description)
event_timestamp = the time the event occurred in UTC ms
event_structure_version = the version of the event structure; v4
event_type = gotpossession
game_clock = MM:SS.T formatted clock data, MM = minute, SS = second, T = subsecond (depending on time subsecond might be missing)
shot_clock = SS.T formatted clock data, SS = second, T = subsecond (depending on time subsecond might be missing)
stop_flag = 0 if clock is running; 1 if clock is stopped
player_tag_serial_number = the serial number of the players tag
player_id = the DDSports id representing the player; only provided for player
team_id = the DDSports id representing the team; only provided for player
X, Y, Z = mm location of the tag relative to the court coordinate system where the center of the court is 0,0
ball_tag_serial_number = the serial number of the ball the player tag is possessing

Sample:
1611805439518,4,gotpossession,19:59.0,30.0,1,105645,1,2,-6113,-23444,1763,2147583169

Lost Possession v2

(CSV Data)
event_timestamp,event_structure_version,event_type,game_clock,shot_clock,stop_flag,player_tag_serial_number,X,Y,Z,ball_tag_serial_number,num_bounces

(Data Description)
event_timestamp = the time the event occurred in UTC ms
event_structure_version = the version of the event structure; v2
event_type = lostpossession
game_clock = MM:SS.T formatted clock data, MM = minute, SS = second, T = subsecond (depending on time subsecond might be missing)
shot_clock = SS.T formatted clock data, SS = second, T = subsecond (depending on time subsecond might be missing)
stop_flag = 0 if clock is running; 1 if clock is stopped
player_tag_serial_number = the serial number of the players tag
X, Y, Z = mm location of the tag relative to the court coordinate system where the center of the court is 0,0
ball_tag_serial_number = the serial number of the ball the player tag is possessing
num_bounces = # of bounces counted while the player had possession

Sample:
1611805439518,2,lostpossession,19:59.0,30.0,1,105645,-6113,-23444,1763,2147583169,8

Lost Possession v4

(CSV Data)
event_timestamp,event_structure_version,event_type,game_clock,shot_clock,stop_flag,player_tag_serial_number,player_id,team_id,X,Y,Z,ball_tag_serial_number,num_bounces

(Data Description)
event_timestamp = the time the event occurred in UTC ms
event_structure_version = the version of the event structure; v4
event_type = lostpossession
game_clock = MM:SS.T formatted clock data, MM = minute, SS = second, T = subsecond (depending on time subsecond might be missing)
shot_clock = SS.T formatted clock data, SS = second, T = subsecond (depending on time subsecond might be missing)
stop_flag = 0 if clock is running; 1 if clock is stopped
player_tag_serial_number = the serial number of the players tag
player_id = the DDSports id representing the player; only provided for player
team_id = the DDSports id representing the team; only provided for player
X, Y, Z = mm location of the tag relative to the court coordinate system where the center of the court is 0,0
ball_tag_serial_number = the serial number of the ball the player tag is possessing
num_bounces = # of bounces counted while the player had possession

Sample:
1611805439518,4,lostpossession,19:59.0,30.0,1,105645,1,2,-6113,-23444,1763,2147583169,8

Cloud Service(s) Stats JSON Data

The json file contains stats at the following levels:
- Full game stats (game_stats object)
- First half stats (half_1_stats object)
- Second half stats (half_2_stats object)
- First quarter stats (quarter_1_stats object)
- Second quarter stats (quarter_2_stats object)
- Third quarter stats (quarter_3_stats object)
- Fourth quarter stats (quarter_4_stats object)
- Overtime stats (ot_1_stats object)

The quarter_n_stats objects are only included when the game is ran as quarters. All games, regardless if ran as quarters or halves, include the game_stats and half_n_stats objects.

at (number) - epoch timestamp of file
at_formatted (string) - human readable timestamp represent by the at field
period (string) - the current or last period of the active game (PRE, H1, H2, Q1, Q2, Q3, Q4, HT, OT, END); completed games will have COMPLETED and scheduled games with test pattern with have TP

Each game, half and quarter stats object has the same format and contains the following fields:

reference (string) - the internal value to represent the ShotTracker internal tracking id
home (object) - all team and player stats for the home team
away (object) - all team and player stats for the away team

Each home and away objects contains the same fields; those are:

team (object) - contains all team level stats
team,team_id (number) - the ShotTracker internal team id
team,consumer_code (string) - the calling consumers defined code for the team or the ShotTracker team_id
team,team_name (string) - the name of the team defined in ShotTracker
team,TWO_POINT_PCT_DISPLAY (string) - (DEPRECATED) the percent of only 2pt field goals
team,FG (number) - the number of made field goals
team,FGA (number) - the number of attempted field goals
team,FG_FRACTION (string) - the fractional display of field goals
team,FG_PCT_DISPLAY (string) - the percent of field goals
team,FG2 (number) - the number of made 2pt field goals
team,FGA2 (number) - the number of attempted 2pt field goals
team,FG2_FRACTION (string) - the fractional display of 2pt field goals
team,FG2_PCT_DISPLAY (string) - the percent of 2pt field goals
team,FG3 (number) - the number of made 3pt field goals
team,FGA3 (number) - the number of attempted 3pt field goals
team,FG3_FRACTION (string) - the fractional display of 3pt field goals
team,FG3_PCT_DISPLAY (string) - the percent of 3pt field goals
team,FT (number) - the number of made free throws
team,FTA (number) - the number of attempted free throws
team,FT_FRACTION (string) - the fractional display of free throws
team,FT_PCT_DISPLAY (string) - the percent of free throws
team,PTS (number) - number of team points
team,REB (number) - number of team rebounds
team,OFFENSIVE_REB (number) - number of team offensive rebounds
team,DEFENSIVE_REB (number) - number of team defensive rebounds
team,AST (number) - number of team assists
team,STL (number) - number of team steals
team,TO (number) - number of team turnovers
team,LBTO (number) - number of team live ball turnovers
team,DBTO (number) - number of team dead ball turnovers
team,DIST (number) - total team distance in cm
team,DIST_MILES (number) - total team distance in miles
team,BLK (number) - number of team blocks
team,FL (number) - number of team fouls
team,FLDN (number) - number of team fouls drawn
team,PPTS (number) - number of points in the paint
team,AST_TO_RATE (number) - the rate of assist to turnovers
team,SECOND_CHANCE_POINTS (number) - number of points scored after an offensive rebound
team,POINTS_OFF_TURNOVER (number) - number of points scored after a turnover

team,shots (object array) - total team shots locations per ShotTrackers 14 zone map
team,shots,zone# (object) - specific ShotTracker zone
team,shots,zone#,DISPLAY (string) - the fractional display of zone shots
team,shots,zone#,PCT_DISPLAY (string) - the percent of the zone shots
team,shots,zone#,R (number) - red color value in RGB
team,shots,zone#,G (number) - green color value in RGB
team,shots,zone#,B (number) - blue color value in RGB

team,shot_locations,make (array) - array of xy made shot locations in millimeters (0,0 starts at the hoop where positive y runs from the hoop out to center court and positive x runs from the hoop to the right of the positive y), peak ball height, entry angle, depth, xy ball locations in millimeters and velocity; see Shot Chart Plotting for this visual
team,shot_locations,miss (array) - array of xy missed shot locations in millimeters (0,0 starts at the hoop where positive y runs from the hoop out to center court and positive x runs from the hoop to the right of the positive y), peak ball height, entry angle, depth, xy ball locations in millimeters and velocity; see Shot Chart Plotting for this visual

team,cas_shots (object array) - total team catch and shoot shots locations per ShotTrackers 14 zone map
team,cas_shots,zone# (object) - specific ShotTracker zone
team,cas_shots,zone#,DISPLAY (string) - the fractional display of zone shots
team,cas_shots,zone#,PCT_DISPLAY (string) - the percent of the zone shots
team,cas_shots,zone#,R (number) - red color value in RGB
team,cas_shots,zone#,G (number) - green color value in RGB
team,cas_shots,zone#,B (number) - blue color value in RGB

team,otd_shots (object array) - total team off the dribble shots locations per ShotTrackers 14 zone map
team,otd_shots,zone# (object) - specific ShotTracker zone
team,otd_shots,zone#,DISPLAY (string) - the fractional display of zone shots
team,otd_shots,zone#,PCT_DISPLAY (string) - the percent of the zone shots
team,otd_shots,zone#,R (number) - red color value in RGB
team,otd_shots,zone#,G (number) - green color value in RGB
team,otd_shots,zone#,B (number) - blue color value in RGB

The team section also contains the following possession type stats. All of the possession types below are a subset of the OVERALL type with the exception of TRANSITION. Paint Touch (PT) occurs when a player possesses the basketball and their location is in the paint. A Ball Reversal (BR) occurs when the ball travels from one wing to the other. This can happen in 1 pass, a player dribbling the ball from one side to the other, or a series of passes.

Below are the possession type prefixes:

TRANSITION - a possession that remains in live ball, either after a turnover, a made shot, or a defensive rebound, that is either turned over or a shot is taken within 10 seconds
OVERALL - all half court possessions
PT0_BR0 - a possession with no paint touch or ball reversal
PT1_BR0 - a possession that only has at least one paint touch
PT0_BR1 - a possession that only has one ball reversal
PT0_BR2 - a possession that only has two or more ball reversals
PT1_BR1 - a possession that has at least one paint touch combined with only one ball reversal
PT1_BR2 - a possession that has a least one paint touch combined with two or more ball reversals
PASS0_2 - a possession with zero passes, one pass or two passes in the possession
PASS3_5 - a possession with 3 passes, four passes or five passes in the possession
PASS6 - a possession that has 6 or more passes in the possession
BS0 - a possession with no ball screens
BS1 - a possession with only 1 ball screen
BS2 - a possession with only 2 ball screens
BS3 - a possession with 3 or more ball screens
BS_ALL - a sum of BS1 + BS2 + BS3
BS_LW - ball screen possessions on the left wing
BS_MW - ball screen possessions on the middle wing
BS_RW - ball screen possessions on the right wing
BS_PNP - pick and pop ball screen possessions
BS_PNR - pick and roll ball screen possessions
BS_SS - screened shot ball screen possessions
BS_HANDOFF - handoff ball screen possessions
BS_DRAG - drag ball screen possessions
BS_SLIP - slip ball screen possessions
BS_SHORT_ROLL - short roll ball screen possessions
BS_REJECT - reject ball screen possessions
BS_RE_SCREEN - re-screen ball screen possessions
BS_STAY - stay ball screen possessions
BS_STEP_UP - step-up ball screen possessions
BS_SNAKE - snake ball screen possessions
BS_SPLIT - split ball screen possessions
BS_OTHER - other ball screen possessions

team,*possession type prefix*_FG_VALUE (number) - total field goals
team,*possession type prefix*_FG (string) - total field goals percent
team,*possession type prefix*_FG_FRACTION (string) - total field goals fraction
team,*possession type prefix*_POSS (number) - number of possessions
team,*possession type prefix*_PTS (number) - number of points in possession type
team,*possession type prefix*_2PTM (number) - 2pt makes
team,*possession type prefix*_2PTA(number) - 2pt attempts
team,*possession type prefix*_3PTM (number) - 3pt makes
team,*possession type prefix*_3PTA (number) - 3pt attempts
team,*possession type prefix*_TO (number) - turnovers
team,*possession type prefix*_PPP (number) - number of points per possession
team,*possession type prefix*_FG_VALUE_ARROW - indicates which field goal value is higher when compared between home and away teams

team,lineup_stats (object array) - the top 2 lineups for each team
team,lineup_stats,#,player_ids (array) - the 5 player ids for the given lineup stats
team,lineup_stats,#,PLUS_MINUS (number) - the lineup's plus/minus
team,lineup_stats,#,TOTAL_POINTS_SCORED (number) - the lineups total points scored
team,lineup_stats,#,TOTAL_POINTS_ALLOWED (number) - the lineups total points allowed

players (object array) - all team and player stats; team stats will be identified by a player_id of 0
players,#,player_id (number) - the ShotTracker internal player id or will be 0 if team
players,#,consumer_code (string) - the calling consumers defined code for the player or the ShotTracker player_id
players,#,jersey_number (number) - player team jersey number or -1 if team
players,#,first_name (string) - players first name or null if team
players,#,last_name (string) - players last name or null if team
players,#,position_abbr (string) - player position abbreviation, C center, G guard, F forward or null if team
players,#,sensor (number) - current player assigned sensor or 0 if team
players,#,on_the_floor (boolean) - true if currently on the court in lineup
players,#,TWO_POINT_PCT_DISPLAY (string) - (DEPRECATED) the percent of only 2pt field goals
players,#,FG (number) - the number of made field goals
players,#,FGA (number) - the number of attempted field goals
players,#,FG_FRACTION (string) - the fractional display of field goals
players,#,FG_PCT_DISPLAY (string) - the percent of field goals
players,#,FG2 (number) - the number of made 2pt field goals
players,#,FGA2 (number) - the number of attempted 2pt field goals
players,#,FG2_FRACTION (string) - the fractional display of 2pt field goals
players,#,FG2_PCT_DISPLAY (string) - the percent of 2pt field goals
players,#,FG3 (number) - the number of made 3pt field goals
players,#,FGA3 (number) - the number of attempted 3pt field goals
players,#,FG3_FRACTION (string) - the fractional display of 3pt field goals
players,#,FG3_PCT_DISPLAY (string) - the percent of 3pt field goals
players,#,FT (number) - the number of made free throws
players,#,FTA (number) - the number of attempted free throws
players,#,FT_FRACTION (string) - the fractional display of free throws
players,#,FT_PCT_DISPLAY (string) - the percent of free throws
players,#,PLUS_MINUS (number) - the player's plus/minus
players,#,PTS (number) - number of player points
players,#,REB (number) - number of player rebounds
players,#,OFFENSIVE_REB (number) - number of player offensive rebounds
players,#,DEFENSIVE_REB (number) - number of player defensive rebounds
players,#,AST (number) - number of player assists
players,#,STL (number) - number of player steals
players,#,TO (number) - number of player turnovers
players,#,LBTO (number) - number of player live ball turnovers
players,#,DBTO (number) - number of player dead ball turnovers
players,#,DIST (number) - total player distance in cm
players,#,DIST_MILES (number) - total player distance in miles
players,#,BLK (number) - number of player blocks
players,#,FL (number) - number of player fouls
players,#,FLDN (number) - number of player fouls drawn
players,#,PPTS (number) - number of points in the paint
players,#,AST_TO_RATE (number) - the rate of assists to turnovers

players,#,shots (object array) - total player shots locations per ShotTrackers 14 zone map
players,#,shots,zone# (object) - specific ShotTracker zone
players,#,shots,zone#,DISPLAY (string) - the fractional display of zone shots
players,#,shots,zone#,PCT_DISPLAY (string) - the percent of the zone shots
players,#,shots,zone#,R (number) - red color value in RGB
players,#,shots,zone#,G (number) - green color value in RGB
players,#,shots,zone#,B (number) - blue color value in RGB

players,#,shot_locations,make (array) - array of xy made shot locations in millimeters (0,0 starts at the hoop where positive y runs from the hoop out to center court and positive x runs from the hoop to the right of the positive y), peak ball height, entry angle, depth, xy ball locations in millimeters and velocity; see Shot Chart Plotting for this visual
players,#,shot_locations,miss (array) - array of xy missed shot locations in millimeters (0,0 starts at the hoop where positive y runs from the hoop out to center court and positive x runs from the hoop to the right of the positive y), peak ball height, entry angle, depth, xy ball locations in millimeters and velocity; see Shot Chart Plotting for this visual

players,#,cas_shots (object array) - total player catch and shoot shots locations per ShotTrackers 14 zone map
players,#,cas_shots,zone# (object) - specific ShotTracker zone
players,#,cas_shots,zone#,DISPLAY (string) - the fractional display of zone shots
players,#,cas_shots,zone#,PCT_DISPLAY (string) - the percent of the zone shots
players,#,cas_shots,zone#,R (number) - red color value in RGB
players,#,cas_shots,zone#,G (number) - green color value in RGB
players,#,cas_shots,zone#,B (number) - blue color value in RGB

players,#,otd_shots (object array) - total player off the dribble shots locations per ShotTrackers 14 zone map
players,#,otd_shots,zone# (object) - specific ShotTracker zone
players,#,otd_shots,zone#,DISPLAY (string) - the fractional display of zone shots
players,#,otd_shots,zone#,PCT_DISPLAY (string) - the percent of the zone shots
players,#,otd_shots,zone#,R (number) - red color value in RGB
players,#,otd_shots,zone#,G (number) - green color value in RGB
players,#,otd_shots,zone#,B (number) - blue color value in RGB

players,#,season_stats (object) - season stats are available on all stats endpoints response with the include_player_season query parameter; the season_stats node will only appear under the game_stats node
players,#,season_stats,FT (number) - the number of made free throws for the season
players,#,season_stats,FTA (number) - the number of attempted free throws for the season
players,#,season_stats,FT_FRACTION (string) - the fractional display of free throws for the season
players,#,season_stats,FT_PCT_DISPLAY (string) - the percent of free throws for the season

Games

Schedule

Schedule
GET/broadcast/v1/games/schedule{?from,to,apikey}

Requests the ShotTracker game schedule. If from and to are not provided it will return all games at the time of the request to all into the future. If from and to are provided will return only the games during the timeframe. The intention of a from/to search would be in the future as the broadcast service is live and upcoming scheduled games.

Example URI

GET /broadcast/v1/games/schedule?from=&to=&apikey=
URI Parameters
HideShow
from
number (optional) 

The starting epoch timestamp (in milliseconds); in UTC

to
number (optional) 

The ending epoch timestamp (in milliseconds); in UTC

apikey
string (required) 

The authentication key

Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "games": [
    {
      "schedule_id": "1a4118d4-2e50-11e6-b4a4-deecc6e6f111",
      "event_id": "1a4118d4-2e50-11e6-b4a4-deecc6e6f111",
      "location": "Test Location",
      "tournament": "N/A",
      "tipoff_at": 1549587600000,
      "expected_duration_ms": 7200000,
      "name": "TestTeam at BWB",
      "gender": "MEN",
      "status": "SCHEDULED",
      "home_team_id": 461,
      "away_team_id": 493,
      "officials_team_id": 0,
      "_link": "/broadcast/display?schedule_id=1a4118d4-2e50-11e6-b4a4-deecc6e6f111",
      "_home_team_link": "/broadcast/v1/games/teams/461?testing=true",
      "_home_team_images": "/broadcast/v1/games/teams/461/images?testing=true",
      "_away_team_link": "/broadcast/v1/games/teams/493?testing=true",
      "_away_team_images": "/broadcast/v1/games/teams/493/images?testing=true",
      "_sse_stats_link": "/broadcast/v1/stats/event-stream?schedule_id=1a4118d4-2e50-11e6-b4a4-deecc6e6f111",
      "_stats_link": "/broadcast/v1/stats?schedule_id=1a4118d4-2e50-11e6-b4a4-deecc6e6f111",
      "udp_multicast_ip": "127.0.0.1",
      "udp_multicast_port": 8765
    }
  ]
}

Active Game Colors

Active Game Colors
GET/broadcast/v1/games/active/{schedule_id}/colors{?apikey}

Returns the team colors for the active game. This endpoint only works with games in an ACTIVE status. It is possible to subscribe to a game before it is active which means once a game marker message is received this endpoint could be called to get the current colors set by ShotTracker game success group. The base team color (color_rgb) is returned under the teams endpoint and can be used to represent the team color however this endpoint represents the exact jersey color each team is wearing at the time of the active game.

Example URI

GET /broadcast/v1/games/active/schedule_id/colors?apikey=
URI Parameters
HideShow
schedule_id
string (required) 

ID of the scheduled game

apikey
string (required) 

The authentication key

Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "teams": [
    {
      "id": 469,
      "color": "00FF80"
    },
    {
      "id": 470,
      "color": "0080FF"
    }
  ]
}

Teams

List Teams

List Teams
GET/broadcast/v1/games/teams{?apikey}

Returns all ShotTracker teams.

Example URI

GET /broadcast/v1/games/teams?apikey=
URI Parameters
HideShow
apikey
string (required) 

The authentication key

Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "teams": [
    {
      "id": 461,
      "name": "TestTeam"
    },
    {
      "id": 493,
      "name": "BWB"
    },
    {
      "id": 481,
      "name": "ShotTrackerW"
    }
  ]
}

Team Roster

Team Roster
GET/broadcast/v1/games/teams/{team_id}{?apikey,game_event_id}

The current active players on the team. The endpoint also returns the players current assigned sensor which can change during a game. The game_event_id parameter can be used to look up all of the players on the team at the time of a game. With this query parameter an additional field is return ‘sensor_assignments_history’ which indicates the sensor assignments during the game. This field is the same response from the Event API Sensor Assignments History Players who are no longer on the team will have an ‘is_active’ false. The special_services field returns items for specific special events; possible type values are MIC, VIDEO.

Basketball Player Positions

Abbreviation Description
G GUARD
F FORWARD
C CENTER

Example URI

GET /broadcast/v1/games/teams/team_id?apikey=&game_event_id=
URI Parameters
HideShow
team_id
number (required) 

ID of the team

game_event_id
string (optional) 

ID of the game

apikey
string (required) 

The authentication key

Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "id": 493,
  "name": "BWB",
  "abbr": "BB",
  "city": "Kansas City",
  "state": "MO",
  "color_rgb": "0066CC",
  "players": [
    {
      "id": 3531,
      "first_name": "Shelden",
      "last_name": "Williams",
      "jersey_number": 4,
      "jersey_number_str": "4",
      "position_abbr": "C",
      "sensor": 100630,
      "special_services": []
    },
    {
      "id": 3541,
      "first_name": "Casey",
      "last_name": "Jacobsen",
      "jersey_number": 3,
      "jersey_number_str": "3",
      "position_abbr": "F",
      "sensor": 100520,
      "special_services": [
        {
          "type": "MIC",
          "value": "mic6"
        }
      ]
    },
    {
      "id": 3548,
      "first_name": "Mateen",
      "last_name": "Cleaves",
      "jersey_number": 2,
      "jersey_number_str": "2",
      "position_abbr": "G",
      "sensor": 100539,
      "special_services": []
    },
    {
      "id": 3532,
      "first_name": "Alando",
      "last_name": "Tucker",
      "jersey_number": 6,
      "jersey_number_str": "6",
      "position_abbr": "F",
      "sensor": null,
      "special_services": []
    }
  ]
}

Team/Player ID CSV Conference Report

Team/Player ID CSV Conference Report
GET/broadcast/v1/games/teams/csv/{conference_name}

Returns a CSV file containing each team and player ids in the given conference name.

Example URI

GET /broadcast/v1/games/teams/csv/conference_name
URI Parameters
HideShow
conference_name
string (required) 

Conference name; BIG12, BIG10, SEC, ACC, PAC12

Response  200
HideShow
Headers
Content-Type: application/csv

Officials Teams

Officials Teams
GET/broadcast/v1/games/officials/teams{?apikey}

Returns all officials teams.

Example URI

GET /broadcast/v1/games/officials/teams?apikey=
URI Parameters
HideShow
apikey
string (required) 

The authentication key

Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "teams": [
    {
      "id": 91,
      "name": "Officials Team 1"
    }
  ]
}

Officials Team Roster

Officials Team Roster
GET/broadcast/v1/games/officials/teams/{team_id}{?apikey}

The special_services field returns items for specific special events; possible type values are MIC, VIDEO.

Example URI

GET /broadcast/v1/games/officials/teams/team_id?apikey=
URI Parameters
HideShow
team_id
number (required) 

ID of the team

apikey
string (required) 

The authentication key

Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "id": 91,
  "name": "Officials Team 1",
  "abbr": "OT",
  "members": [
    {
      "id": 3531,
      "first_name": "Doug",
      "last_name": "Williams",
      "jersey_number": 0,
      "jersey_number_str": "00",
      "position_abbr": "C",
      "sensor": 100699,
      "special_services": []
    }
  ]
}

Team And Player Images

Team And Player Images
GET/broadcast/v1/games/teams/{team_id}/images{?apikey}

Returns the team and player image links.

Example URI

GET /broadcast/v1/games/teams/team_id/images?apikey=
URI Parameters
HideShow
team_id
number (required) 

ID of the team

apikey
string (required) 

The authentication key

Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "team_image_url": "https://shottracker.com/pimg/bc1b6e06-3a44-11e6-857c-06a15c73f3c3",
  "players": [
    {
      "id": 2907,
      "image_url": "https://shottracker.com/pimg/bc1b6e06-3a44-11e6-857c-06a15c73f3c3"
    },
    {
      "id": 2908,
      "image_url": "https://shottracker.com/pimg/bc1b6e06-3a44-11e6-857c-06a15c73f3c3"
    },
    {
      "id": 2909,
      "image_url": "https://shottracker.com/pimg/bc1b6e06-3a44-11e6-857c-06a15c73f3c3"
    },
    {
      "id": 2910,
      "image_url": "https://shottracker.com/pimg/bc1b6e06-3a44-11e6-857c-06a15c73f3c3"
    },
    {
      "id": 2911,
      "image_url": "https://shottracker.com/pimg/bc1b6e06-3a44-11e6-857c-06a15c73f3c3"
    }
  ]
}

Stats

Test Pattern Game Stats

Test Pattern Game Stats
GET/broadcast/v1/stats/testpattern{?schedule_id,format,apikey}

This endpoint returns the a zero’ed out stats file for any scheduled, live or ended game. As a test pattern in broadcast, this file is intended to be used as a calibration test of the stats file. Actual stats for live or ended games are not available on this endpoint; the Full Game Stats or Full Game Stats SSE endpoints should be used.

Example URI

GET /broadcast/v1/stats/testpattern?schedule_id=&format=&apikey=
URI Parameters
HideShow
schedule_id
string (required) 

ID of the scheduled game

format
string (optional) 

indicates the response format; values are json or xml; if no value is given the default format is json

apikey
string (required) 

The authentication key

Response  200
HideShow
Headers
Content-Type: application/json
Body
See "Game Stats JSON Format"

Live Game Stats SSE

Live Game Stats SSE
GET/broadcast/v1/stats/event-stream{?schedule_id,format,include_player_season,test_pattern,stats_level,apikey}

Opens a Server Sent Events (SSE) connection that will remain open as long as the connection persists. This endpoint will push updated live game stats to the consumer as they occur. The schedule_id from the Schedule endpoint is required. If the connection drops during the game, after reconnecting, the latest game stats file will be pushed. See the Full Game Stats JSON Format for a complete description of each field.

Example connecting to the SSE endpoint using javascript:

var EventSource = require("eventsource");
var fs = require('fs');

const SCHEDULE_ID = '<schedule id>';
const API_KEY = '<your api key>';

var es = new EventSource(`https://api-shottracker.ddsports.com/broadcast/v1/stats/event-stream?schedule_id=${SCHEDULE_ID}&apikey=${API_KEY}`);

var listener = function (event) {
    var type = event.type;
    if (type === 'message') {
        var data = event.data;
        console.log(data);

        fs.writeFile("./sse_data.json", data, function(err) {
            if(err) {
                return console.log(err);
            }

            console.log("The file was saved!");
        });
    }
};

es.addEventListener('open', listener);
es.addEventListener('message', listener);
es.addEventListener('error', listener);

Example connection to the SSE endpoint using golang (download tool):

package main

import (
  "bufio"
  "fmt"
  "io"
  "net/http"
  "os"
  "strings"
  "time"
)

const CONNECTED_STATUS = "CONNECTED"
const DISCONNECTED_STATUS = "DISCONNECTED"

var timer *time.Timer

func main() {
  reader := bufio.NewReader(os.Stdin)
  fmt.Println("ShotTracker SSE Download Utility")
  fmt.Println("--------------------------------")
  fmt.Println("Enter Event Stream URL")
  fmt.Print("> ")
  url, _ := reader.ReadString('\n')
  fmt.Println("Enter Output File Name")
  fmt.Print("> ")
  fileName, _ := reader.ReadString('\n')
  fmt.Println("================================")

  run(strings.TrimSpace(url), strings.TrimSpace(fileName))
}

func run(url string, fileName string) {
  for {
    response, _ := getResponse(nil, url)

    if response == nil {
      time.Sleep(5000 * time.Millisecond)
      continue
    }

    logToConsole(CONNECTED_STATUS, "waiting for data ...")
    read(response, fileName)

    response.Body.Close()
  }
}

func getResponse(body io.Reader, url string) (*http.Response, error) {
  request, requestErr := http.NewRequest(http.MethodGet, url, body)
  if requestErr != nil {
    panic(fmt.Sprintf("Error occurred creating new request: %s", requestErr))
  }
  request.Header.Add("Accept", "text/event-stream")

  httpClient := http.Client{}

  response, err := httpClient.Do(request)
  if err != nil {
    logToConsole(DISCONNECTED_STATUS, fmt.Sprintf("error occurred connecting to %s: %s", url, err))
    return nil, err
  }
  if response.StatusCode != http.StatusOK {
    panic(fmt.Sprintf("Expected a %d status code; got a %d", http.StatusOK, response.StatusCode))
  }
  return response, err
}

func read(response *http.Response, fileName string) {
  handleHeartbeat(response)

  dataChannel := make(chan string)
  cancelChannel := make(chan struct{})
  go func() {
    for {
      select {
      case data := <-dataChannel:
        {
          dataHandler(fileName, data, response)
        }
      case <-cancelChannel:
        return
      }
    }
  }()

  defer close(cancelChannel)

  reader := bufio.NewReader(response.Body)
  for {
    data, err := reader.ReadString('\n')
    if err != nil && err != io.EOF {
      fmt.Fprintf(os.Stderr, "Error reading response: %s\n", err)
      break
    }

    dataChannel <- data
  }
}

func dataHandler(fileName string, data string, response *http.Response) {
  if data == "\n" {
    return
  }

  if data == ":\n" {
    logToConsole(CONNECTED_STATUS, "server heartbeat received")
    handleHeartbeat(response)
  }

  if strings.HasPrefix(data, "data:") {
    logToConsole(CONNECTED_STATUS, "data received, updating "+fileName)
    writeToFile(fileName, strings.TrimSpace(data[6:]))
  }
}

func handleHeartbeat(response *http.Response) {
  if timer != nil {
    timer.Stop()
  }
  timer = time.NewTimer(30 * time.Second)
  go func() {
    <-timer.C
    logToConsole(DISCONNECTED_STATUS, "no heartbeat received in 30 seconds; reconnecting...")
    response.Body.Close()
  }()
  return
}

func writeToFile(filename string, data string) {
  file, err := os.Create(filename)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Error creating file: %s\n", err)
  }

  defer file.Close()

  _, err = io.WriteString(file, data)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Error writing to file: %s\n", err)
  }

  file.Sync()
}

func logToConsole(status string, value string) {
  dateTime := time.Now().Format("2006.01.02 15:04:05")

  fmt.Printf("\r%s [%s] %s", status, dateTime, value)
}

Example URI

GET /broadcast/v1/stats/event-stream?schedule_id=&format=&include_player_season=&test_pattern=&stats_level=&apikey=
URI Parameters
HideShow
schedule_id
string (required) 

ID of the scheduled game

format
string (optional) 

indicates the response format; values are json or xml; if no value is given the default format is json

include_player_season
string (optional) 

indicates to include the season_stats node for each player; example usage include_player_season=2021-22

test_pattern
boolean (optional) 

when set to true will return a zero’ed stats file as done in the test pattern endpoint for games that have not yet started (SCHEDULED); once the game starts the file will be replaced with the actual live game; defaults to false

stats_level
string (optional) 

when set will return only the specific stats level; possible values are game_stats, half_1_stats, half_2_stats, quarter_1_stats, quarter_2_stats, quarter_3_stats, quarter_4_stats, ot_1_stats; example stats_level=game_stats to return only the game totaled stats

apikey
string (required) 

The authentication key

Response  200
HideShow
Headers
Content-Type: text/event-stream
Body
See "Game Stats JSON Format"

Game Stats

Game Stats
GET/broadcast/v1/stats{?schedule_id,format,include_player_season,test_pattern,stats_level,apikey}

This endpoint returns the latest updated stats for an active or completed game. To receive realtime stats, as they happen, consumers should use the Full Game Stats SSE. See the Full Game Stats JSON Format for a complete description of each field.

Example URI

GET /broadcast/v1/stats?schedule_id=&format=&include_player_season=&test_pattern=&stats_level=&apikey=
URI Parameters
HideShow
schedule_id
string (required) 

ID of the scheduled game

format
string (optional) 

indicates the response format; values are json or xml; if no value is given the default format is json

include_player_season
string (optional) 

indicates to include the season_stats node for each player; example usage include_player_season=2021-22

test_pattern
boolean (optional) 

when set to true will return a zero’ed stats file as done in the test pattern endpoint for games that have not yet started (SCHEDULED); this parameter has no effect for active or completed games; defaults to false

stats_level
string (optional) 

when set will return only the specific stats level; possible values are game_stats, half_1_stats, half_2_stats, quarter_1_stats, quarter_2_stats, quarter_3_stats, quarter_4_stats, ot_1_stats; example stats_level=game_stats to return only the game totaled stats

apikey
string (required) 

The authentication key

Response  200
HideShow
Headers
Content-Type: application/json
Body
See "Game Stats JSON Format"

Player Season Stats

Player Season Stats
GET/broadcast/v1/seasons/{season}/stats/teams/{team_id}/players{?format,apikey}

Returns the completed games season stats for all players for the given team id.

Example URI

GET /broadcast/v1/seasons/season/stats/teams/team_id/players?format=&apikey=
URI Parameters
HideShow
season
string (required) 

season identifier; examples 2020-21, 2021-22

team_id
number (required) 

ID of the team

format
string (optional) 

indicates the response format; values are json or xml; if no value is given the default format is json

apikey
string (required) 

The authentication key

Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "players": [
    {
      "player_id": 101808,
      "season_stats": {
        "FT": 38,
        "FTA": 49
      }
    },
    {
      "player_id": 103871,
      "season_stats": {
        "FT": 0,
        "FTA": 1
      }
    }
  ]
}

Locomotion

Metrics

Metrics
GET/broadcast/v1/locomotion{?schedule_id,team_id,apikey}

This endpoint returns player locomotion metrics for the game and the given team id.

Example URI

GET /broadcast/v1/locomotion?schedule_id=&team_id=&apikey=
URI Parameters
HideShow
schedule_id
string (required) 

ID of the scheduled game

team_id
number (required) 

ID of the team

apikey
string (required) 

The authentication key

Response  200
HideShow
Headers
Content-Type: application/json
Body
{
  "metrics": [
    {
      "pid": "1",
      "tid": "461",
      "gid": "860e825e-38c2-11ea-9d3b-02422f8cbade",
      "metrics": {
        "DIST_TOTAL": 167.5,
        "DIST_SPRINT": 56.9,
        "DIST_JOG": 80.4,
        "DIST_WALK": 30.2,
        "DIST_SPRINT_COUNT": 3,
        "DIST_JOG_COUNT": 5,
        "DIST_WALK_COUNT": 8,
        "ACCEL_HIGH_COUNT": 3,
        "ACCEL_MED_COUNT": 2,
        "ACCEL_LOW_COUNT": 1,
        "DECEL_HIGH_COUNT": 3,
        "DECEL_MED_COUNT": 2,
        "DECEL_LOW_COUNT": 1,
        "VELOCITY_CURR_AVG": 10.2,
        "VELOCITY_TOP": 12.6
      }
    }
  ]
}

Live Locomotion Metrics SSE

Live Locomotion Metrics SSE
GET/broadcast/v1/locomotion/metric-stream{?schedule_id,apikey}

Opens a Server Sent Events (SSE) connection that will remain open as long as the connection persists. This endpoint will push updated live locomotion metrics to the consumer as they occur. The schedule_id is required. If the connection drops during the game, after reconnecting, the latest locomotion metrics file will be pushed.

Example connecting to the SSE endpoint using javascript:

var EventSource = require("eventsource");
var fs = require('fs');

const SCHEDULE_ID = '<schedule id>';
const API_KEY = '<your api key>';

var es = new EventSource(`https://api-shottracker.ddsports.com/broadcast/v1/locomotion/metric-stream?schedule_id=${SCHEDULE_ID}&apikey=${API_KEY}`);

var listener = function (event) {
    var type = event.type;
    if (type === 'message') {
        var data = event.data;
        console.log(data);

        fs.writeFile("./sse_data.json", data, function(err) {
            if(err) {
                return console.log(err);
            }

            console.log("The file was saved!");
        });
    }
};

es.addEventListener('open', listener);
es.addEventListener('message', listener);
es.addEventListener('error', listener);

Example connection to the SSE endpoint using golang:

package main

import (
  "bufio"
  "fmt"
  "io"
  "net/http"
  "os"
  "strings"
  "time"
)

const CONNECTED_STATUS = "CONNECTED"
const DISCONNECTED_STATUS = "DISCONNECTED"

var timer *time.Timer

func main() {
  reader := bufio.NewReader(os.Stdin)
  fmt.Println("ShotTracker SSE Download Utility")
  fmt.Println("--------------------------------")
  fmt.Println("Enter Event Stream URL")
  fmt.Print("> ")
  url, _ := reader.ReadString('\n')
  fmt.Println("Enter Output File Name")
  fmt.Print("> ")
  fileName, _ := reader.ReadString('\n')
  fmt.Println("================================")

  run(strings.TrimSpace(url), strings.TrimSpace(fileName))
}

func run(url string, fileName string) {
  for {
    response, _ := getResponse(nil, url)

    if response == nil {
      time.Sleep(5000 * time.Millisecond)
      continue
    }

    logToConsole(CONNECTED_STATUS, "waiting for data ...")
    read(response, fileName)

    response.Body.Close()
  }
}

func getResponse(body io.Reader, url string) (*http.Response, error) {
  request, requestErr := http.NewRequest(http.MethodGet, url, body)
  if requestErr != nil {
    panic(fmt.Sprintf("Error occurred creating new request: %s", requestErr))
  }
  request.Header.Add("Accept", "text/event-stream")

  httpClient := http.Client{}

  response, err := httpClient.Do(request)
  if err != nil {
    logToConsole(DISCONNECTED_STATUS, fmt.Sprintf("Error occurred connecting to %s: %s", url, err))
    return nil, err
  }
  if response.StatusCode != http.StatusOK {
    panic(fmt.Sprintf("Expected a %d status code; got a %d", http.StatusOK, response.StatusCode))
  }
  return response, err
}

func read(response *http.Response, fileName string) {
  handleHeartbeat(response)

  dataChannel := make(chan string)
  cancelChannel := make(chan struct{})
  go func() {
    for {
      select {
      case data := <-dataChannel:
        {
          dataHandler(fileName, data, response)
        }
      case <-cancelChannel:
        return
      }
    }
  }()

  defer close(cancelChannel)

  reader := bufio.NewReader(response.Body)
  for {
    data, err := reader.ReadString('\n')
    if err != nil && err != io.EOF {
      fmt.Fprintf(os.Stderr, "Error reading response: %s\n", err)
      break
    }

    dataChannel <- data
  }
}

func dataHandler(fileName string, data string, response *http.Response) {
  if data == "\n" {
    return
  }

  if data == ":\n" {
    logToConsole(CONNECTED_STATUS, "server heartbeat received")
    handleHeartbeat(response)
  }

  if strings.HasPrefix(data, "data:") {
    logToConsole(CONNECTED_STATUS, "data received, updating "+fileName)
    writeToFile(fileName, strings.TrimSpace(data[6:]))
  }
}

func handleHeartbeat(response *http.Response) {
  if timer != nil {
    timer.Stop()
  }
  timer = time.NewTimer(30 * time.Second)
  go func() {
    <-timer.C
    logToConsole(DISCONNECTED_STATUS, "no heartbeat received in 30 seconds; reconnecting...")
    response.Body.Close()
  }()
  return
}

func writeToFile(filename string, data string) {
  file, err := os.Create(filename)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Error creating file: %s\n", err)
  }

  defer file.Close()

  _, err = io.WriteString(file, data)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Error writing to file: %s\n", err)
  }

  file.Sync()
}

func logToConsole(status string, value string) {
  dateTime := time.Now().Format("2006.01.02 15:04:05")

  fmt.Printf("\r%s [%s] %s", status, dateTime, value)
}

Example URI

GET /broadcast/v1/locomotion/metric-stream?schedule_id=&apikey=
URI Parameters
HideShow
schedule_id
string (required) 

ID of the scheduled game

apikey
string (required) 

The authentication key

Response  200
HideShow
Headers
Content-Type: text/event-stream
Body
{
  "type": "data",
  "source": "locomotion",
  "data": {
    "t": 1663773345277,
    "sid": "4c298764-39bf-11ed-bbae-0242e9e2912e",
    "st": "FOOTBALL_GAME_QUARTER",
    "pid": 123,
    "tid": 515,
    "gid": "4bb6ef73-39bf-11ed-bbae-0242e9e2912e",
    "metrics": {
      "DIST_TOTAL": 167.5,
      "DIST_SPRINT": 56.9,
      "DIST_JOG": 80.4,
      "DIST_WALK": 30.2,
      "ACCEL_CURR_AVG": 2,
      "ACCEL_HIGH": 3,
      "ACCEL_MED": 2,
      "ACCEL_LOW": 1,
      "DECEL_HIGH": 3,
      "DECEL_MED": 2,
      "DECEL_LOW": 1,
      "VELOCITY_CURR_AVG": 10.2,
      "VELOCITY_TOP": 12.6
    }
  }
}

Fan Experience

Live Fan Experience SSE

Live Fan Experience SSE
GET/broadcast/v1/fan-experience/item-stream{?schedule_id,apikey}

Opens a Server Sent Events (SSE) connection that will remain open as long as the connection persists. This endpoint will push live fan experience items onsumer as they occur. The schedule_id is required. If the connection drops during the game, after reconnecting, only the next live items will be received.

Example connecting to the SSE endpoint using javascript:

var EventSource = require("eventsource");
var fs = require('fs');

const SCHEDULE_ID = '<schedule id>';
const API_KEY = '<your api key>';

var es = new EventSource(`https://api-shottracker.ddsports.com/broadcast/v1/fan-experience/item-stream?schedule_id=${SCHEDULE_ID}&apikey=${API_KEY}`);

var listener = function (event) {
    var type = event.type;
    if (type === 'message') {
        var data = event.data;
        console.log(data);

        fs.writeFile("./sse_data.json", data, function(err) {
            if(err) {
                return console.log(err);
            }

            console.log("The file was saved!");
        });
    }
};

es.addEventListener('open', listener);
es.addEventListener('message', listener);
es.addEventListener('error', listener);

Example connection to the SSE endpoint using golang:

package main

import (
  "bufio"
  "fmt"
  "io"
  "net/http"
  "os"
  "strings"
  "time"
)

const CONNECTED_STATUS = "CONNECTED"
const DISCONNECTED_STATUS = "DISCONNECTED"

var timer *time.Timer

func main() {
  reader := bufio.NewReader(os.Stdin)
  fmt.Println("ShotTracker SSE Download Utility")
  fmt.Println("--------------------------------")
  fmt.Println("Enter Event Stream URL")
  fmt.Print("> ")
  url, _ := reader.ReadString('\n')
  fmt.Println("Enter Output File Name")
  fmt.Print("> ")
  fileName, _ := reader.ReadString('\n')
  fmt.Println("================================")

  run(strings.TrimSpace(url), strings.TrimSpace(fileName))
}

func run(url string, fileName string) {
  for {
    response, _ := getResponse(nil, url)

    if response == nil {
      time.Sleep(5000 * time.Millisecond)
      continue
    }

    logToConsole(CONNECTED_STATUS, "waiting for data ...")
    read(response, fileName)

    response.Body.Close()
  }
}

func getResponse(body io.Reader, url string) (*http.Response, error) {
  request, requestErr := http.NewRequest(http.MethodGet, url, body)
  if requestErr != nil {
    panic(fmt.Sprintf("Error occurred creating new request: %s", requestErr))
  }
  request.Header.Add("Accept", "text/event-stream")

  httpClient := http.Client{}

  response, err := httpClient.Do(request)
  if err != nil {
    logToConsole(DISCONNECTED_STATUS, fmt.Sprintf("Error occurred connecting to %s: %s", url, err))
    return nil, err
  }
  if response.StatusCode != http.StatusOK {
    panic(fmt.Sprintf("Expected a %d status code; got a %d", http.StatusOK, response.StatusCode))
  }
  return response, err
}

func read(response *http.Response, fileName string) {
  handleHeartbeat(response)

  dataChannel := make(chan string)
  cancelChannel := make(chan struct{})
  go func() {
    for {
      select {
      case data := <-dataChannel:
        {
          dataHandler(fileName, data, response)
        }
      case <-cancelChannel:
        return
      }
    }
  }()

  defer close(cancelChannel)

  reader := bufio.NewReader(response.Body)
  for {
    data, err := reader.ReadString('\n')
    if err != nil && err != io.EOF {
      fmt.Fprintf(os.Stderr, "Error reading response: %s\n", err)
      break
    }

    dataChannel <- data
  }
}

func dataHandler(fileName string, data string, response *http.Response) {
  if data == "\n" {
    return
  }

  if data == ":\n" {
    logToConsole(CONNECTED_STATUS, "server heartbeat received")
    handleHeartbeat(response)
  }

  if strings.HasPrefix(data, "data:") {
    logToConsole(CONNECTED_STATUS, "data received, updating "+fileName)
    writeToFile(fileName, strings.TrimSpace(data[6:]))
  }
}

func handleHeartbeat(response *http.Response) {
  if timer != nil {
    timer.Stop()
  }
  timer = time.NewTimer(30 * time.Second)
  go func() {
    <-timer.C
    logToConsole(DISCONNECTED_STATUS, "no heartbeat received in 30 seconds; reconnecting...")
    response.Body.Close()
  }()
  return
}

func writeToFile(filename string, data string) {
  file, err := os.Create(filename)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Error creating file: %s\n", err)
  }

  defer file.Close()

  _, err = io.WriteString(file, data)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Error writing to file: %s\n", err)
  }

  file.Sync()
}

func logToConsole(status string, value string) {
  dateTime := time.Now().Format("2006.01.02 15:04:05")

  fmt.Printf("\r%s [%s] %s", status, dateTime, value)
}
JSON Field Name Description
status The board items are ADDED or DELETED (from corrections).
type The type of board items being received; BOARD_EVENT is when a single item on any board for the active game is triggered; BOARD_WIN is when an number of fan players win with their boards.
data.boards.board_name TIC_TAC_TOE for tic-tac-toe square locations or wins, or BINGO for bingo square items or wins.
data.boards.items.value The value will be either a number (between 1-9) for TIC_TAC_TOE or a string value of the BINGO square.

Tic-Tac-Toe is represented as a 3x3 grid with the following layout:

123
456
789

Example URI

GET /broadcast/v1/fan-experience/item-stream?schedule_id=&apikey=
URI Parameters
HideShow
schedule_id
string (required) 

ID of the scheduled game

apikey
string (required) 

The authentication key

Response  200
HideShow
Headers
Content-Type: text/event-stream
Body
{
  "type": "data",
  "source": "fanexperience",
  "data": {
    "gameId": "abc-123",
    "status": "ADDED || DELETED",
    "type": "BOARD_EVENT || BOARD_WIN",
    "data": {
      "boards": [
        {
          "board_name": "TIC_TAC_TOE",
          "items": [
            {
              "timestamp": 12345,
              "team": "Team1",
              "value": 3
            }
          ],
          "winners": [
            "username1"
          ]
        },
        {
          "board_name": "BINGO",
          "items": [
            {
              "timestamp": 12345,
              "team": "Team1",
              "value": "Player 2pt Make"
            }
          ],
          "winners": []
        }
      ]
    }
  }
}

Utilities

Graphic metrics

Graphic metrics
POST/broadcast/v1/graphics/metrics{?apikey}

This endpoint accepts the graphic metrics in usage statistics purposes.

Example URI

POST /broadcast/v1/graphics/metrics?apikey=
URI Parameters
HideShow
apikey
string (required) 

The authentication key

Request
HideShow
Headers
Content-Type: application/json
Body
{
  "consumer_id": "4c298764-39bf-11ed-bbae-0242e9e2912e",
  "graphic_name": "Shot Chart",
  "team_id": "515",
  "stats": {
    "FG2": 3,
    "FGA2": 6,
    "FG2_RATE": 50,
    "FG3": 2,
    "FGA3": 5,
    "FG3_RATE": 40
  }
}
Response  204