Submit videos for processing and receive results via webhook
This guide walks through how to submit a video for processing using the SplitStep API. You submit a job and receive results via a webhook when the job completes or fails.
You will need:
Run the script from your terminal. Your API key can be passed via the SPLITSTEP_API_KEY
environment variable (recommended) or directly with the --api-key flag:
# Using the SPLITSTEP_API_KEY environment variable (recommended) SPLITSTEP_API_KEY=your_key python send_client.py path/to/job_request.json # Or passing the key directly python send_client.py path/to/job_request.json --api-key your_key
The script will print the immediate queuing response as JSON, for example:
{
"job_id": "a1b2c3d4-...",
"video_id": "your_match_id",
"status": "queued",
"message": "Job queued successfully"
}
If a required field is missing or invalid, the API will reject the request immediately with an error, for example:
{
"detail": "Webhook URL is required"
}
The job request is a JSON file with the following fields.
| Field | Type | Description |
|---|---|---|
| MatchID | string | A unique identifier for this video. |
| VideoUrl | string (URL) | A publicly accessible URL to the video file (e.g. an Azure Blob SAS URL). |
| WebhookUrl | string (URL) | The URL that will receive a POST request when the job completes or fails. See Webhook Responses below. |
| InitialTopPlayer | string | Name of the player starting at the top of the court at the beginning of the video. |
| InitialBottomPlayer | string | Name of the player starting at the bottom of the court at the beginning of the video. |
| StartTime | float | Time in seconds from the start of the video to begin processing. |
| EndTime | float | Time in seconds from the start of the video to end processing. |
| SetGameScores | array of [number, number] | The game scores for each set, from the perspective of the top and bottom player respectively. Each entry is a two-element array [top_player_games, bottom_player_games]. For example, a match won 6–4, 6–1 by the top player would be [[6, 4], [6, 1]]. |
| FixedCamera | boolean | Whether the camera is stationary (e.g. on a tripod or fence mount) throughout the match. |
| Ad | boolean | Whether advantage scoring is used. If true, a player must win two consecutive points after deuce to win the game. |
{
"MatchID": "my_match_001",
"VideoUrl": "https://example.blob.core.windows.net/videos/match.mp4?...",
"WebhookUrl": "https://your-server.com/webhook/splitstep",
"InitialTopPlayer": "Smith",
"InitialBottomPlayer": "Jones",
"StartTime": 120.0,
"EndTime": 3600.0,
"SetGameScores": [[6, 3], [7, 5]],
"FixedCamera": true,
"Ad": false
}
| Specification | Requirement |
|---|---|
| Resolution | 1080p (1920×1080) or higher |
| Frame rate | 30 fps minimum, 60 fps recommended |
| Format | MP4 (H.264) preferred |
| File size | Less than 5 GB |
| Length | Adjust StartTime and EndTime to cover complete games, consistent with the set game scores provided in SetGameScores |
| Mode | Singles only — doubles matches are not supported at this time |
You will receive two webhook notifications per job: one when the job is first queued, and one when processing completes or fails.
Sent immediately after a successful submission:
{
"job_id": "a1b2c3d4-...",
"video_id": "my_match_001",
"status": "queued",
"message": "Job queued successfully"
}
Sent when processing finishes successfully:
{
"job_id": "a1b2c3d4-...",
"video_id": "my_match_001",
"status": "job_completed",
"message": "Job completed successfully",
"sas_url": "https://...",
"trimmed_video_url": "https://..."
}
| Field | Description |
|---|---|
| sas_url | Azure Blob SAS URL to a JSON file containing the stroke-by-stroke analysis results, valid for 7 days. |
| trimmed_video_url | Azure Blob SAS URL to the trimmed and re-encoded video used for processing, valid for 7 days. |
Sent if an error occurs at any stage of processing:
{
"job_id": "a1b2c3d4-...",
"video_id": "my_match_001",
"status": "job_failed",
"message": "Failed to download video: <error details>"
}
The message field identifies which processing step failed and includes the underlying
error message.
#!/usr/bin/env python3
import json
import click
import requests
@click.command()
@click.argument("job_request_path", type=click.Path(exists=True))
@click.option("--api-key", envvar="SPLITSTEP_API_KEY", required=True)
def send(job_request_path, api_key):
"""Send a job request to the SplitStep API.
Parameters
----------
job_request_path : str
Path to a JSON file containing the job request payload.
api_key : str
API key for authenticating with the API. Falls back to the
SPLITSTEP_API_KEY environment variable.
"""
with open(job_request_path, "r") as f:
data = json.load(f)
response = requests.post(
"https://api.example.com/jobs", # dummy endpoint — replace with your assigned URL
headers={"X-Api-Key": api_key, "Content-Type": "application/json"},
json=data,
)
click.echo(json.dumps(response.json(), indent=2))
if __name__ == "__main__":
send()