MLB Advanced Insights - Milestones v1

Frequently Asked Questions
API API Version
MLB Advanced Insights - Milestones v1
Note: Authentication is required for all API calls.
## Milestone Thresholds ```ruby require 'uri' require 'net/http' require 'openssl' url = URI("https://api.sportradar.com/milestones/mlb/trial/v1/en/thresholds?api_key={your_api_key}") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Get.new(url) response = http.request(request) puts response.read_body ``` ```python import http.client conn = http.client.HTTPSConnection("api.sportradar.us") conn.request("GET", "/milestones/mlb/trial/v1/en/thresholds?api_key={your_api_key}") res = conn.getresponse() data = res.read() print(data.decode("utf-8")) ``` ```shell curl -L "https://api.sportradar.com/milestones/mlb/trial/v1/en/thresholds?api_key={your_api_key}" ``` > The above command returns json structured like this. This endpoint retrieves Milestone Thresholds. https://api.sportradar.com/milestones/mlb/`{access_level}`/`{version}`/thresholds?api_key=`{your_api_key}` Replace placeholders with the following query parameters: | Parameter | Description | | --------- | ----------- | | `access_level` | Defines the access level of your API key as Trial (trial) or Development (development). | | `version` | Version number of the API you are accessing (Current Version: v1). | | `your_api_key` | Your API key. | ## Milestones by Game ```ruby require 'uri' require 'net/http' require 'openssl' url = URI("https://api.sportradar.com/milestones/mlb/trial/v1/en/game/dd6edd68-1d29-4494-a6f5-d11c6eb94b27?api_key={your_api_key}") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Get.new(url) response = http.request(request) puts response.read_body ``` ```python import http.client conn = http.client.HTTPSConnection("api.sportradar.us") conn.request("GET", "/milestones/mlb/trial/v1/en/game/dd6edd68-1d29-4494-a6f5-d11c6eb94b27?api_key={your_api_key}") res = conn.getresponse() data = res.read() print(data.decode("utf-8")) ``` ```shell curl -L "https://api.sportradar.com/milestones/mlb/trial/v1/en/game/dd6edd68-1d29-4494-a6f5-d11c6eb94b27?api_key={your_api_key}" ``` > The above command returns json structured like this. This endpoint retrieves Milestones by Game. https://api.sportradar.com/milestones/mlb/`{access_level}`/`{version}`/game/`{game_id}`?api_key=`{your_api_key}` Replace placeholders with the following query parameters: | Parameter | Description | | --------- | ----------- | | `access_level` | Defines the access level of your API key as Trial (trial) or Development (development). | | `version` | Version number of the API you are accessing (Current Version: v1). | | `game_id` | Id of a given game. | | `your_api_key` | Your API key. | ## Milestones by Player ```ruby require 'uri' require 'net/http' require 'openssl' url = URI("https://api.sportradar.com/milestones/mlb/trial/v1/en/player/49812b41-643c-4356-b6eb-ffd29df4f653?api_key={your_api_key}") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Get.new(url) response = http.request(request) puts response.read_body ``` ```python import http.client conn = http.client.HTTPSConnection("api.sportradar.us") conn.request("GET", "/milestones/mlb/trial/v1/en/player/49812b41-643c-4356-b6eb-ffd29df4f653?api_key={your_api_key}") res = conn.getresponse() data = res.read() print(data.decode("utf-8")) ``` ```shell curl -L "https://api.sportradar.com/milestones/mlb/trial/v1/en/player/49812b41-643c-4356-b6eb-ffd29df4f653?api_key={your_api_key}" ``` > The above command returns json structured like this. This endpoint retrieves Milestones by Player. https://api.sportradar.com/milestones/mlb/`{access_level}`/`{version}`/player/`{player_id}`?api_key=`{your_api_key}` Replace placeholders with the following query parameters: | Parameter | Description | | --------- | ----------- | | `access_level` | Defines the access level of your API key as Trial (trial) or Development (development). | | `version` | Version number of the API you are accessing (Current Version: v1). | | `player_id` | Id of a given player. | | `your_api_key` | Your API key. | ## Milestones by Projected Game ```ruby require 'uri' require 'net/http' require 'openssl' url = URI("https://api.sportradar.com/milestones/mlb/trial/v1/en/game/projected/dd6edd68-1d29-4494-a6f5-d11c6eb94b27?api_key={your_api_key}") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Get.new(url) response = http.request(request) puts response.read_body ``` ```python import http.client conn = http.client.HTTPSConnection("api.sportradar.us") conn.request("GET", "/milestones/mlb/trial/v1/en/game/projected/dd6edd68-1d29-4494-a6f5-d11c6eb94b27?api_key={your_api_key}") res = conn.getresponse() data = res.read() print(data.decode("utf-8")) ``` ```shell curl -L "https://api.sportradar.com/milestones/mlb/trial/v1/en/game/projected/dd6edd68-1d29-4494-a6f5-d11c6eb94b27?api_key={your_api_key}" ``` > The above command returns json structured like this. This endpoint retrieves Milestones by Projected Game. https://api.sportradar.com/milestones/mlb/`{access_level}`/`{version}`/game/projected/`{game_id}`?api_key=`{your_api_key}` Replace placeholders with the following query parameters: | Parameter | Description | | --------- | ----------- | | `access_level` | Defines the access level of your API key as Trial (trial) or Development (development). | | `version` | Version number of the API you are accessing (Current Version: v1). | | `game_id` | Id of a given game. | | `your_api_key` | Your API key. | ## Milestones by Team ```ruby require 'uri' require 'net/http' require 'openssl' url = URI("https://api.sportradar.com/milestones/mlb/trial/v1/en/team/4f735188-37c8-473d-ae32-1f7e34ccf892?api_key={your_api_key}") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Get.new(url) response = http.request(request) puts response.read_body ``` ```python import http.client conn = http.client.HTTPSConnection("api.sportradar.us") conn.request("GET", "/milestones/mlb/trial/v1/en/team/4f735188-37c8-473d-ae32-1f7e34ccf892?api_key={your_api_key}") res = conn.getresponse() data = res.read() print(data.decode("utf-8")) ``` ```shell curl -L "https://api.sportradar.com/milestones/mlb/trial/v1/en/team/4f735188-37c8-473d-ae32-1f7e34ccf892?api_key={your_api_key}" ``` > The above command returns json structured like this. This endpoint retrieves Milestones by Team. https://api.sportradar.com/milestones/mlb/`{access_level}`/`{version}`/team/`{team_id}`?api_key=`{your_api_key}` Replace placeholders with the following query parameters: | Parameter | Description | | --------- | ----------- | | `access_level` | Defines the access level of your API key as Trial (trial) or Development (development). | | `version` | Version number of the API you are accessing (Current Version: v1). | | `team_id` | Id of a given team. | | `your_api_key` | Your API key. | ## Push Feeds >To best utilize Push feeds, we have included code samples in Ruby and Java which provides an example of a way you can consume the feeds. Using these samples will output the feeds content to STDOUT.
For Java, we have also provided a Stream Client to assist your integration.

Note: In the provided Java sample, replace "URL GOES HERE" with the desired Push feed URL. ```ruby require 'httpclient' module Sportradar module HTTP module Stream class Client attr_reader :url, :logger def initialize(url, publisher, logger) @url = url @logger = logger @publisher = publisher @client = ::HTTPClient.new(:agent_name => 'SportsData/1.0') end def start @thread ||= Thread.new do logger.debug "Starting loop" @client.get_content(url, :follow_redirect => true) do |chunk| @publisher.publish(::JSON.parse(chunk)) if @publisher end logger.debug "finished loop" end end def stop @thread.terminate if @thread end end end end end ``` ```java package com.sportradar.http.stream.client; import org.junit.After; import org.junit.Before; import org.junit.Test; public class StreamClientTest { private StreamClient client; private static String SERVICE_URL = ""; @Before public void setup() { client = new StreamClient(); } @After public void cleanup() { client.terminate(); } @Test public void testStream() throws Exception { Handler handler = new ConsoleHandler(); client.stream(SERVICE_URL, handler); System.out.println("Connecting...."); Thread.sleep(1 * 60 * 1000); System.out.println("Disconnecting...."); } } ``` Some of our APIs include Push feeds that allow you to get updates as soon as they are available. Push API feeds automatically send JSON and XML payloads to you via a push service, and can dramatically reduce the number of calls you need to make to our RESTful API feeds. The structure of the Push feeds are similar to the structure of the corresponding RESTful API feed (i.e. Push Milestones). The push service ensures reliable and efficient delivery of the most up to date information. Our Push services are based on a HTTP publish/subscribe model. When making a call to the Push APIs, you "subscribe" to various data feeds provided by our service; whenever new content is available on one of those feeds, the server pushes that information out to your client. When no new information is available on the feed, a heartbeat message is sent every 5 seconds to keep the connection active. If you want to filter the results of the feeds, there are several optional query string parameters that can be applied to the API call. If left unfiltered, all data for the feed is displayed (i.e. all milestones). For your applications to accept data from our Push feeds, ensure that your application can: * Can follow a HTTP redirect or use the location provided in the feeds header within one minute of your initial request. * Can accept HTTP data transfer encoded as chunked. Our Push service does not provide a "stateful session", there is no memory of what data has been sent previously. If you are disconnected from the Push session, you can use the RESTful API to catch up or recover from the disconnection. Syntax for using our Push feeds and examples of the JSON and XML payloads can be found below. ## Push - Milestones ```ruby require 'uri' require 'net/http' require 'openssl' url = URI("http://api.sportradar.com/milestones/mlb/trial/stream/en/events/subscribe?api_key={your_api_key}") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Get.new(url) response = http.request(request) puts response.read_body ``` ```python import http.client conn = http.client.HTTPSConnection("api.sportradar.us") conn.request("GET", "/milestones/mlb/trial/stream/en/events/subscribe?api_key={your_api_key}") res = conn.getresponse() data = res.read() print(data.decode("utf-8")) ``` ```shell curl -L "GET api.sportradar.com/milestones/mlb/trial/stream/en/events/subscribe?api_key={your_api_key}" ``` This endpoint retrieves the Milestone information via Push. http://api.sportradar.us/milestones/mlb/`{access_level}`/stream/en/events/subscribe?api_key=`{your_api_key}` Replace placeholders with the following query parameters: | Parameter | Description | | --------- | ----------- | | `access_level` | Defines the access level of your API key as Production (production) or Trial (trial). | | `your_api_key` | Your API key. | ### Optional Query String Parameters >Example including optional query string parameters: ```ruby require 'uri' require 'net/http' require 'openssl' url = URI("http://api.sportradar.com/milestones/mlb/trial/stream/en/events/subscribe?api_key={your_api_key}&format=json&sport_event_id=52b87a30-aec2-45c6-851e-8218ac1d7b64") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Get.new(url) response = http.request(request) puts response.read_body ``` ```python import http.client conn = http.client.HTTPSConnection("api.sportradar.us") conn.request("GET", "/milestones/mlb/trial/stream/en/events/subscribe?api_key={your_api_key}&format=json&sport_event_id=52b87a30-aec2-45c6-851e-8218ac1d7b64") res = conn.getresponse() data = res.read() print(data.decode("utf-8")) ``` ```shell curl -L GET 'https://api.sportradar.com/milestones/mlb/trial/stream/en/events/subscribe?api_key={your_api_key}&format=json&sport_event_id=52b87a30-aec2-45c6-851e-8218ac1d7b64' ``` In addition to the URL parameters listed above, you can filter the Milestone information with one or more of the following optional query string parameters.
Note: Optional query string parameters must be added after your API key with an ampersand (&). If you are filtering for more than one result, separate the results with a comma (,) and no spaces.
Replace placeholders with the following query parameters: | URL Parameters | Description | | --------- | ----------- | | `channel` | Channel type expressed as: {channel_type}.
Example: channel=snooker | | `competition_id` | Competition type expressed as: {competition_id}.
Example: competition_id=sr:competition:20508 | | `event_id` | Event id expressed as: {event_id}.
Example: event_id=535536474 | | `format` | Format type expressed as: {format}.
Example: format=json | | `season_id` | Season id expressed as: {season_id}.
Example: season_id=sr:season:63867 | | `sport_event_id` | Sport event id expressed as: {sport_event_id}.
Example: sport_event_id=sr:sport_event:17738118 | | `sport_id` | Sport id expressed as: {sport_id}.
Example: sport_id=sr:sport:19 | ## Frequently Asked Questions

Q: What is the Date format?

A: When we present date only values we present these in the ISO 8601 standard format.
ex: 2013-04-03
We use these for attributes that have date and no time (such as birthdate). For more information: https://en.wikipedia.org/wiki/ISO_8601

Q: What time zone are the date time fields presented in?

A: All of our Date/Time attributes are in UTC, presented in the ISO 8601 standard format.
ex: 2013-04-03T18:15:00+00:00
For more information: https://en.wikipedia.org/wiki/ISO_8601

Q: What types of milestones can I expect and what thresholds are they generated at?

A: There are three different types of milestones: Season, Career, and Playoffs. There are three different kinds of milestones within those three types: Players competing against themselves, Players climbing their franchise's leaderboard, and Players climbing the league leaderboard

  • All milestones have set thresholds. Those thresholds can be found in the Milestone Threshold feed.
  • Across all milestone types, there are several different statistics with available insights. Those can be found in the Milestone Threshold feed.
    • The infinite value within that feed represents the number added to the end of the last threshold. For example, if the last single-season threshold for HRs is 73, and the infinite is 1, then we'll create an insight if a player is approaching 74, per 75, 76, etc
  • For the Player vs. franchise and Player vs. league, we are looking at various Top # leaderboards, being represented in the Franchise and League fields on the endpoint. For example, we may look at the top 100 in League history for regular season hits, but only the top 50 in League history for regular season hit by pitches.

Q: When are milestones generated and when are they updated?

A: Every morning our processes produce and update upcoming milestones. For baseball, the data updates daily, as long as a player played the previous day. MLB: Runs at 6am (TBD)

There are five different triggers for creating a milestone insight. All in-game insights are generated with approximately a minute latency between the event occurring and the insight being created.
Some insight triggers are exclusively created in-game: Reaching, Tying, and Passing. Approaching, Closing In, and One Away can be triggered in-game, but they are also placed in the Milestones by Projected Game endpoint.

Here is an example:

In game, Aaron Judge has a hit to bring him to 95 on the season. Assuming his last three seasons average for hits is 1 hit per game, he is now 5 games away from reaching 100 hits on the season. In-game, we'll send out an insight that says Judge is approaching 100 hits on the season and is 5 games away. The next morning, our milestones are updated and the Milestones by Projected game feed displays that Judge is still 5 games away from 100 hits.

Trigger Types:

  1. Approaching (Available on pre-game & in-game endpoints):
    1. Approaching gets generated in-game, as soon as a player is "5 games away"
      1. To determine how far “away” that player is, we take the average of that stat over the last 3 regular seasons. For example, if the milestone is Mike Trout reaching 100 RBI on the season, and his average RBI the last 3 regular seasons is 1 per game, when he reaches 95 RBI on the season, an insight is generated.
    1. Approaching then gets updated each morning when a player is 4, 3, or 2 games away
      1. When it is updated the insight id remains the same, and a new insight isn't generated. The data within that insight updates the next morning
      2. There is a field in the payload that communicates when the insight is updated
  2. Closing In (Available on pre-game & in-game endpoints):
    1. Closing In gets generated in-game, as soon as a player is "one game away"
      1. The determination for one game away is the same as approaching
      2. This is one game away from reaching or tying, not passing
  3. One Away (Available on pre-game & in-game endpoints):
    1. One Away gets generated in-game, as soon as a player is "one of that stat category" away
      1. "One of that stat category" is always 1 (1 HR, 1 Run, etc), except for stats that can be accumulated by more than 1 in a single event. For example, RBI, where a player can get up to 4 in a single at-bat
      2. For leaderboards, it's one away from tying, not one away from passing
  4. Reaching/Tying (Available on in-game endpoints only):
    1. Reaching or Tying gets generated in-game, as soon as a player reaches a milestone, or ties another player in a leaderboard
  5. Passing (Available on in-game endpoints only. For leaderboard insights only):
    1. Passing gets generated in-game, as soon as a player who was previously tied on a leaderboard passes that player on a leaderboard

Q: Can I control what the thresholds and trigger types are?

A: Currently, milestone thresholds are controlled by Sportradar. Eventually, we’ll open up that configuration to customers; in the meantime, you can filter out the thresholds you aren’t interested in. If there are thresholds that are missing that you think should be added, please reach out to lj.rader@sportradar.com

Q: Where does the relevancy information come from?

A: We have a team of experts at Sportradar who compile the information seen in the relevancy section. This information is not intended to be shown to your end-users, but instead should be used as a way to filter down the insights. For example, you can decide to only show insights related to tier 1 & 2 players, and filter out tiers 3, 4, and 5.

Return to top

Docs Navigation