How To: Create a Requested Analysis via the Reboot Motion API

This tutorial uses code samples written in Python; however, if your organization uses a different language, you can still use the tutorials as a reference point — you will just need to translate the examples to the language of your choosing.

If you need help with getting set up to use the Reboot Motion API, you can check out our Getting Set Up tutorial here.

Welcome! This tutorial walks you through the process of creating a Requested Analysis via the Reboot Motion API. For more information about the endpoints included in this tutorial, or any other endpoint, you can check out our API documentation.

Note: You will need an API Key to interact with the API endpoints mentioned in this tutorial. API Keys are available to all active Reboot Motion customers. If you do not already have an API Key from Reboot Motion, you can generate one from your Reboot Motion Dashboard.

What exactly is a Requested Analysis? A Requested Analysis is simply a custom report that Reboot Motion can create for an organization using specific data that the organization provides.

For this tutorial, we will be analyzing a fictional example pitcher’s fastballs vs their curveballs. We will be using the Reboot Motion API to create a Requested Analysis that compares the example pitcher’s fastballs to their curveballs.

Step 0: Understanding the Endpoints

First, let’s take a look at the Reboot Motion API documentation for Analyses. You'll notice there are seven different endpoints :

EndpointDescription
POST /player_group_segmentsCreate Player Group Segments
PATCH /player_group_segments/{player_group_segment_id}Update Player Group Segments
GET /requested_analysesList Requested Analyses
POST /requested_analysesCreate Requested Analyses
GET /requested_analyses/{requested_analysis_id}Get Requested Analyses
PATCH /requested_analyses/{requested_analysis_id}Update Requested Analyses
PATCH /requested_analyses/{requested_analysis_id}/submitSet Requested Analyses Status To Requested

For this tutorial, we will use two of the endpoints listed above. First, we create the primary and comparison segments using the POST /player_group_segments endpoint (which returns the newly created segments' IDs). We then use the POST /requested_analyses endpoint, which takes those segment IDs and submits the Requested Analysis for processing.

The first endpoint we will look at is the POST /requested_analyses endpoint. You will notice that this endpoint requires the following parameters:

{
  "name": "Player A comparing May 2022 to April 2022",
  "primary_analysis_segment_id": 1
  "comparison_analysis_segment_id": 2,
  "population_analysis_segment_id": 3,
}

There are some Reboot Motion-specific terms in here, like name and primary/comparison/population analysis segment — let’s define those:

TermDefinition
nameWhatever you want to name your generated report to make it easier for you to find either via the Reboot Motion API or the Dashboard. You can make this as specific or generic as you like; we suggest erring on the side of more specific to make it easier to find.
player_group_segmentThe underlying grouping of movements that will be analyzed in the Requested Analysis. The primary, comparison, and population segments are subsets of the larger player_group_segment.

Again, in our example, our player_group_segment is a specific player’s pitch types.

  • Our primary segment will be the pitcher’s Fastballs, as that is the first pitch type we are going to be analyzing.
  • The comparison segment will be the pitcher's Curveballs, as we are comparing the pitcher's Curveballs to their Fastballs in this Requested Analysis.
  • The population segment is a bit more complicated than just choosing one pitch type for a player — this one will need to be defined within your organization and can change based on your use case. The population segment is the total dataset for whatever you decide you want to look at. For the tutorial example, it could be all the example pitcher’s pitches in a certain game, all the pitcher’s pitches thus far in the season; all the pitcher’s Fastballs for the season, or all the pitcher’s Curveballs for the season. The population segment is used to provide a larger dataset for which to compare your primary dataset and should be tailored to the data your organization is most interested in seeing.

If these segments are a bit confusing, don't worry — we will be walking through getting each necessary segment in the tutorial below with examples.

Before we start trying to figure out how to get our primary_segment_id and comparison_segment_id, we want to set up our main.py file properly, so make sure you have the following import statements and constants at the top of your file — we are going to use the os.getenv() function to get our API Key from wherever it is currently stored:

import os

import requests 

API_KEY = "API_KEY_FROM_REBOOT"

If you're not sure what any of these import statements or constants are doing, hop over to our Getting Set Up tutorial, which walks you through each of those.

Note that "API_KEY_FROM_REBOOT" would be replaced with your actual API Key, given to you by Reboot Motion, as detailed in the Getting Set Up tutorial. In our example, we are hard-coding the API key for ease of understanding, but in practice it's wise to read the API key from an environment variable leveraging a library like python-dotenv. As mentioned in the tutorial, please be incredibly careful not to commit your API Key to a public repository.

As a reminder: all the values used in this tutorial are example values. You cannot plug and play with the example values as they currently are; you will need to put in the correct values for your organization/player/etc. The example values used in this tutorial are for a fictional example player.

Step 1: Getting the List of Movement IDs to Compare

After looking at the API documentation, you'll notice that we need a list of Movement IDs in order to work with this endpoint.

You can get the list of Movement IDs in a couple different ways, depending on how your organization stores the data. If you're looking to compare a list of Movement IDs from a game (for example, a specific, league-provided ID), you can simply input the Movement IDs as arrays. If your organization has a larger dataset, you may retrieve that dataset directly from a database or stored in a CSV file. In the case of a CSV, a tool like Pandas can simplify the process of reading and filtering the data.

Getting the List of Movement IDs via CSV File:

Let's look at getting the list of Movement IDs via a CSV file, using Pandas. If you need a refresher on why we are using Pandas, you can look at the Pandas section in the Getting Set Up tutorial.

In this scenario, we are getting the data to be compared from a CSV file, so will need the path to that file. Note that we do not provide this CSV file for you — it must come from your organization and you can save it wherever you would like within your codebase, but you’ll need to get the path to that file starting at the root folder to use in this step.

League-Provided IDPitchType
aaeae660-70d8-443c-ad95-8824771e6251Fastball
dae947c0-85b4-469e-ad27-72324add9b42Fastball
9f0a5ca1-d4ff-45af-aac6-1c1d90afd2c5Fastball
fbcfe483-b462-4135-b249-6c588c688851Curveball
eb306285-c145-414a-93c5-5361d4c9915cCurveball
6dc0e92b-b0b5-4d1a-b6dd-1a34adfee63cCurveball

Our CSV file replicated above has two columns: one labeled League-Provided ID and one labeled PitchType. If you look at the PitchType column, you’ll see it includes only Fastball and Curveball, which are the two Pitch Types we are comparing in this example; your data may have more values and can be filtered based on the values you want, or you may create a CSV file that includes only the values you're looking at, as we've done in this example.

When using Pandas, reading the data is easy — using the Pandas read_csv function, we are able to easily read the file and create DataFrames from our CSV file, which looks like this:

import pandas as pd

def main():
    csv_df = pd.read_csv(PATH_TO_CSV_FILE)

if __name__ == "__main__":
    main()

Again, the PATH_TO_CSV_FILE would be replaced with the file path where the CSV file lives within your organization's repository.

The next step is to figure out what data we want from the file so we can start to make and filter our DataFrames — our original desire was to get the values of an example pitcher’s fastballs vs their curveballs, so our primary segment will be the one that contains that pitcher’s fastballs.

We will be making a copy of the csv_df DataFrame and inserting that into a new DataFrame that we will call fastball_movements_df. This dataframe will relate to the primary segment that we are looking at: in this case, the example pitcher’s fastballs.

From there, we need to take that primary DataFrame and filter it on the pitch type of Fastball, as that's the pitch type we want to use to compare the rest of the data to. Since we are looking at both the pitcher's fastballs and curveballs, you will want to create a second DataFrame for the pitcher's curveballs as well, using the Curveball pitch type.

fastball_movements_df = csv_df[csv_df["PitchType"] == "Fastball"]
curveball_movements_df = csv_df[csv_df["PitchType"] == "Curveball"]

You now have a DataFrame of both the fastball and curveball movements that include the league-provided ID for the lines of the CSV file that correlate to either fastballs or curveballs. You now have a DataFrame of both the fastball and curveball movements that include the league-provided ID for the lines of the CSV file that correlate to either fastballs or curveballs.

The last step is to turn these DataFrames into lists of Movement IDs using the league-provided ID column and the `.tolist() function:

fastball_movements = fastball_movements_df["MLBPlayId"].tolist()
curveball_movements = curveball_movements_df["MLBPlayId"].tolist()

This will give you two lists of Movement IDs that you can use to create the Primary and Comparison Segments:

fastball_movements = ["aaeae660-70d8-443c-ad95-8824771e6251", "dae947c0-85b4-469e-ad27-72324add9b42", "9f0a5ca1-d4ff-45af-aac6-1c1d90afd2c5"]
curveball_movements = ["fbcfe483-b462-4135-b249-6c588c688851", "eb306285-c145-414a-93c5-5361d4c9915c", "6dc0e92b-b0b5-4d1a-b6dd-1a34adfee63c"]

Regardless of the method you choose to get your list of Movement IDs, you will now have one list of fastball movements and one list of curveball movements that we will use as we progress through this tutorial.

Step 2: Creating the Primary Segment

From the API documentation, the first thing we need to create for our Requested Analysis is the Primary Segment ID.

The Primary Segment ID is the ID of a Player Group Segment that we can use to request the analysis. However, we don't have a Player Group Segment yet, let alone the ID of a Player Group Segment; we just have our lists of Movement IDs.

To create a Player Group Segment for our Primary Segment (aka Player Group Segment #1, aka the example pitcher's Fastballs) and get the ID needed to create the Requested Analysis, we will need to reference the Reboot Motion API documentation again, this time looking at the Create Player Group Segments endpoint.

This POST /player_group_segments request will provide us with the Player Group Segment that we can use to move forward. We will be taking all the data we need for that primary segment and making a dictionary of primary_segment_criteria.

In the documentation, you will see that movement_type_id and dom_hand are required fields. In our example, we will also be adding in external_context_ids to further clarify what data we want. The External Context ID corresponds to the MLB Play ID for a movement you have uploaded to Reboot Motion, and is included in our CSV file as a column.

fastball_movements = ["aaeae660-70d8-443c-ad95-8824771e6251", "dae947c0-85b4-469e-ad27-72324add9b42", "9f0a5ca1-d4ff-45af-aac6-1c1d90afd2c5"]

primary_segment_criteria = {
    "external_context_ids": fastball_movements,
    "movement_type_id": 2,
        "dom_hand": "RHA"
}

Let’s walk through exactly what each of those dictionary elements means:

Dictionary ElementDefinition
external_context_idsThe list of specific, league-provided IDs that we want to analyze, which we get from the "League-Provided ID" column of our CSV file or from the array of individual league-provided IDs.
movement_type_idThe type of movement we want to analyze. For our example case, we are looking at baseball pitching movements, so we are using a movement_type_id of 2. For the names and IDs of other movement types, you can query the API via the List Movement Types endpoint.
dom_handThe dominant hand for the movements we want to analyze — in our case, our example pitcher is right handed, so we use RHA (if we were analyzing left—handed movements, you would use LHA). We use dom_hand to make this variable more flexible — it can be used for multiple sports and in many applications (i.e. in baseball it can be used for pitching and hitting, in basketball for shooting, and in football for throwing, to name a few).

The next step is to send the API POST /player_group_segments request to create the Primary Segment we just defined the criteria for. Since we’re using the requests library, passing the primary_segment_criteria dictionary to the json= parameter will automatically convert the dictionary to JSON and use it as the body of the request.

We authenticate with the API using the x-api-key header as detailed in the documentation:

create_primary_segment = requests.post(
    "https://api.rebootmotion.com/player_group_segments",
    headers={'x-api-key': API_KEY},
    json=primary_segment_criteria
)

Now we have the create_primary_segment JSON object, but we still need to get the analysis_segment_id from it. Since this is a JSON object, we can’t just tack ["analysis_segment_id"] straight onto the end of the response; we need to first convert it back to a dictionary and then we can retrieve the analysis_segment_id parameter.

Since we are going to be reusing the same general code structure for Step 2, we are going to create some additional constants from our segment criteria dictionary since you must use the same values for movement_type_id and dom_hand for the primary, comparison, and population segments. Since we will also be using the same header and API KEY requests, we can turn that into a constant for easy reuse throughout the code.

API_HEADER = {'x-api-key': API_KEY}
DOM_HAND = "RHA"
MOVEMENT_TYPE_ID = 2

fastball_movements = ["aaeae660-70d8-443c-ad95-8824771e6251", "dae947c0-85b4-469e-ad27-72324add9b42", "9f0a5ca1-d4ff-45af-aac6-1c1d90afd2c5"]

primary_segment_criteria = {
    "external_context_ids": fastball_movements,
    "movement_type_id": MOVEMENT_TYPE_ID,
    "dom_hand": DOM_HAND
}

create_primary_segment = requests.post(
    "https://api.rebootmotion.com/player_group_segments",
    headers=API_HEADER,
    json=primary_segment_criteria
)

primary_segment_id = create_primary_segment.json()["analysis_segment_id"]

create_primary_segment should return a response object that includes multiple keys and values; one of which is the analysis_segment_id. If you are not getting a response object back, double check to make sure you have entered all fields correctly before proceeding. The Reboot Motion API Documentation has more information on the response object you should be getting back.

Now let’s move on to Step 3, which is creating the Comparison Segment in the same way we just created the Primary Segment.

Step 3: Creating the Comparison Segment

Creating the Comparison Segment ID repeats the above steps but uses comparison_segment instead of primary_segment; curveball_movements instead of fastball_movements; and "Curveball" instead of "Fastball". The new block of code will therefore look like this:

curveball_movements = ["fbcfe483-b462-4135-b249-6c588c688851", "eb306285-c145-414a-93c5-5361d4c9915c", "6dc0e92b-b0b5-4d1a-b6dd-1a34adfee63c"]

comparison_segment_criteria = {
    "external_context_ids": curveball_movements,
    "movement_type_id": MOVEMENT_TYPE_ID,
    "dom_hand": DOM_HAND
}

create_comparison_segment = requests.post(
    "https://api.rebootmotion.com/player_group_segments",
    headers=API_HEADER,
    json=comparison_segment_criteria
)

comparison_segment_id = create_comparison_segment.json()["analysis_segment_id"]

Again, create_comparison_segment should return a response object with multiple keys and values; one of which is the analysis_segment_id. If you are not getting a response object back, double check to make sure you have entered all fields correctly before proceeding. The Reboot Motion API Documentation has more information on the response object you should be getting back.

Now we have both the Primary (fastball) and Comparison (curveball) Analysis Segment IDs that we can use in the last part of our code, which is actually creating the Requested Analysis.

Step 4: Creating the Requested Analysis

The last step in this tutorial is to write the POST /requested_analyses request, creating the Requested Analysis itself. The documentation for this can be accessed in the Reboot Motion API documentation.

Since we now have both the primary_analysis_segment_id and comparison_analysis_segment_id, we can go back to our initial POST /requested_analyses endpoint and fill the request body with the Segment IDs from Steps 2 and 3.

You will need to create a requested_analysis_criteria dictionary and to make the POST request:

requested_analysis_criteria = {
    "name": "Example Pitcher Fastballs vs Curveballs",
    "primary_analysis_segment_id": int(primary_segment_id),
    "comparison_analysis_segment_id": int(comparison_segment_id),
    "status": "requested"
}

create_requested_analyses = requests.post(
    "https://api.rebootmotion.com/requested_analyses",
    headers=API_HEADER,
    json=requested_analysis_criteria
)

Let’s walk through what each of the lines of the above code is doing.

We'll start with the requested_analysis_criteria dictionary first.

Dictionary ElementDefinition
nameAs mentioned earlier in this tutorial, this is simply the name you would like to give your report — this can be whatever you would like, and as descriptive as you would like; we recommend erring on the side of a more descriptive name so your reports are easy to locate in the future via the API or Dashboard.
primary_analysis_segment_idThe integer value of the primary_segment_id we got in Step 2 — this allows us to get the data for that primary segment you are looking to compare; in this case it’s the example pitcher’s fastballs. You’ll notice that we convert the primary_segment_id we got earlier into an integer using int().
comparison_analysis_segment_idAlso the integer value of the comparison_segment_id we got in Step 3, and allows us to get the data for the segment you are looking to compare the primary segment to. In this example, that would be the example pitcher’s curveballs. Again, the comparison_segment_id is converted to an integer using .int().
statusThe status of the requested analysis. If you do not include this field, it will default to "draft". The status should always be requested when creating a new analysis; it will be updated as the analysis is processed on Reboot Motion’s end.

Now that we have the dictionary with the criteria created, we can make the create_requested_analyses POST request.

The headers for the POST request remain the same as they were for getting the Primary and Comparison Segment IDs, but the URL and criteria we are providing the endpoint are different: the URL is now "https://api.rebootmotion.com/requested_analyses" and the required requested_analysis_criteria dictionary from the API documentation has been included as a JSON object.

If your create_requested_analyses is not returning a full response object, double check to make sure you have entered all fields correctly before proceeding. The Reboot Motion API Documentation has more information on the response object you should be getting back.

In the documentation, comparison_analysis_segment_id and population_analysis_segment_id are not required. Why is that?

Reboot Motion allows you to create a Requested Analysis for just one segment if you would like. This means you would only have a primary_analysis_segment_id, and would not include a comparison_analysis_segment_id or a population_analysis_segment_id, giving you a Requested Analysis for just the one segment you have put in as your primary segment.

This tutorial has not provided an example of a population_analysis_segment_id, but we do want to touch on what exactly that means. The population can be whatever you would like it to be: if you want to see a specific pitcher’s pitches for all games, the population segment can be that pitcher’s pitches for all their games (this season, last season, since they joined the organization, however you want to break it up); if you want to see all the shots from the entire organization, the population segment can be shots from your entire organization. This allows you to have the power to compare whatever segments you would like to compare with ease. That being said, the way to get the Population Analysis Segment ID is the exact same way as we used to get the Primary and Comparison Analysis Segment IDs: you’ll create a Player Group Segment with whatever you want the population to be. This can be used in conjunction with either just a Primary Analysis Segment or both a Primary and Comparison Analysis Segment.

The last part is to simply print the JSON response of the requested analysis from the API, and run the file. Putting all the previous parts together, our main.py file should now look like the below, and you should be able to create a Requested Analysis (keep in mind that if you used Pandas for getting the Movement IDs, you will have a bit more code to get the fastball and curveball movements).

import os

import requests 

API_KEY = "API_KEY_FROM_REBOOT"
API_HEADER = {'x-api-key': API_KEY}
DOM_HAND = "RHA"
MOVEMENT_TYPE_ID = 2

def main():
    fastball_movements = ["aaeae660-70d8-443c-ad95-8824771e6251", "dae947c0-85b4-469e-ad27-72324add9b42", "9f0a5ca1-d4ff-45af-aac6-1c1d90afd2c5"]
    
    primary_segment_criteria = {
        "external_context_ids": fastball_movements,
        "movement_type_id": MOVEMENT_TYPE_ID,
        "dom_hand": DOM_HAND
    }

    create_primary_segment = requests.post(
        "https://api.rebootmotion.com/player_group_segments",
        headers=API_HEADER,
        json=primary_segment_criteria
    )

    primary_segment_id = create_primary_segment.json()["analysis_segment_id"]


    curveball_movements = ["fbcfe483-b462-4135-b249-6c588c688851", "eb306285-c145-414a-93c5-5361d4c9915c", "6dc0e92b-b0b5-4d1a-b6dd-1a34adfee63c"]
        
    comparison_segment_criteria = {
        "external_context_ids": curveball_movements,
        "movement_type_id": MOVEMENT_TYPE_ID,
        "dom_hand": DOM_HAND
    }

    create_comparison_segment = requests.post(
        "https://api.rebootmotion.com/player_group_segments",
        headers=API_HEADER,
        json=comparison_segment_criteria
    )

    comparison_segment_id = create_comparison_segment.json()["analysis_segment_id"]

    requested_analysis_criteria = {
        "name": "Example Pitcher Fastballs vs Curveballs",
        "primary_analysis_segment_id": int(primary_segment_id),
        "comparison_analysis_segment_id": int(comparison_segment_id),
        "status": "requested"
    }
    create_requested_analyses = requests.post(
        "https://api.rebootmotion.com/requested_analyses",
        headers=API_HEADER,
        json=requested_analysis_criteria
    )

    print(create_requested_analyses.json())

if __name__ == "__main__":
main()

Running this file will allow you to create a Requested Analysis, and will print out the JSON values of the response to your terminal.

Common Errors

Ideally, you wouldn't run into any errors while going through this tutorial, but there's a lot of information here and sometimes errors happen. That being said, let's go through some of the more common errors and the first steps to take to troubleshoot those errors to save you some time.

You can always access a full list of errors in the Reboot Motion documentation, but we will walk you through some more specific error messages you may encounter while trying to create a Requested Analysis.

ModuleNotFoundError: No module named '<module_name>'

This error comes from the module in question not being installed — you will need to install the module in order to use it. You can do this by running pip install requests in your terminal. If you are using a different package manager, you will need to use the appropriate command for that package manager.

response.json()[‘analysis_segment_id’] throws an exception

This exception is likely being thrown because of a key error, coming from response.json()['analysis_segment_id']. This error means the JSON coming back doesn't have an ['analysis_segment_id'], which it should.

It likely means you have entered something incorrectly in your request; we recommend you double check the spelling of all the provided fields, as this is a frequent cause of this error. You may have also provided data in an incorrect form — double check with the documentation that everything matches up.

HTTP Exception 401: Unauthorized

You need to include a proper API Key — if you don't know how to get this, take a look at the Getting Set Up tutorial.

HTTP Exception 500: Internal Server Error

This means something is wrong on the Reboot Motion server's end - please reach out to the team at [email protected].

If you need to retry the API call after a failure, check that you have everything above correct, restart your server, and make the call again. If you continue to get an error message and can't figure out why, feel free to reach out to the Reboot Motion team.

Please feel free to reach out to the team with any additional questions you may have, or if you run into any issues that weren't addressed above!