Skip to content

SportRadar Simulator Query Parameters

This document describes all query string parameters that can be used with the SportRadar simulator endpoints to control data flow and streaming behavior.

Endpoints

The simulator provides the following endpoints that accept query parameters:

  • /data/{access_level}/{language_code} - Direct streaming endpoint
  • /mlb/{access_level}/stream/{language_code}/events/subscribe - MLB streaming endpoint (redirects to /data)
  • /nhl/{access_level}/stream/{language_code}/events/subscribe - NHL streaming endpoint (redirects to /data)
  • /nfl/official/{access_level}/stream/{language_code}/events/subscribe - NFL streaming endpoint (redirects to /data)

Required Parameters

match

Type: string
Required: Yes
Format: sd:match:{game_id}

The match identifier in SportRadar format. The simulator extracts the Sportradar match id (UUID after sd:match:) from this parameter — the same value as Match.sr_id, not the internal match id (Match.id).

Example:

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec

Continuous sessions

Cloned test matches can use a continuous session: an in-process producer in srsim that advances the archive on wall clock from Match.scheduled, using the clone’s StreamManager params (playback_speed, delays, start_at, etc.), whether or not a listener is connected.

  • Session key = internal match id (Match.id), not Match.sr_id (clones share Sportradar ids).
  • Requires uvicorn --workers 1 (compose default). In-memory registry is not shared across workers.
  • Control plane: GET /sessions, GET /sessions/{id}, POST /sessions/{id}/stop, POST /sessions/{id}/reset.
  • A lifespan watcher polls Postgres for due is_test matches; subscribe with session= can also eager-start a due session.

session

Type: string (UUID)
Required: No
Format: Internal match id (Match.id)

When present and a live continuous session exists (or can be started for that test match), the response joins that session and only receives events from that point forward. Clone-and-listen injects session={Match.id} into listener_sr_request_append when Wait for listener is off (default) — Sportradar-like continuous playback from Match.scheduled.

When session is omitted (or unknown / not live): srsim uses the legacy one-shot path — a new per-request StreamManager for that HTTP connection only. The archive plays from the beginning (or from start_at). Disconnecting and reconnecting restarts from the beginning again; it does not join a continuous session. Clone Wait for listener (Speed through preset) omits session= on purpose so an instant feed cannot race ahead of the listener. Also useful for ad-hoc curl / debug.

Example (continuous):

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&session=a1b2c3d4-e5f6-7890-abcd-ef1234567890

Example (one-shot — no session):

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&playback_speed=2

Catch-up (late start / srsim restart)

If the session should have started at Match.scheduled but srsim starts it later (watcher delay, process restart, first subscribe after kickoff), the producer fast-forwards instead of replaying from event 0.

Budget: catch_up_sec = max(0, now − Match.scheduled).

How: the same StreamManager pacing as live play (playback_speed, inter-event delays, game_delay_at_event, …), except wall sleeps are skipped until that budget is spent. Events during catch-up are not emitted — a listener that joins afterward only gets events from that point forward (it missed the skipped portion).

Example A — normal speed

  • Kickoff was 30 seconds ago
  • Events are ~10s apart, playback_speed=1
  • Catch-up skips ~30s of waiting (roughly the first few events) without emitting them, then resumes sleeping/emitting normally from there

Example B — playback_speed=0 (Speed through)

  • playback_speed=0 means no wait between events — the whole archive finishes in essentially zero wall time at kickoff
  • If kickoff was 30 seconds ago, that instant replay already finished at scheduled
  • A listener that connects now gets no further events (the simulated game is already over). Catch-up does not dump the full recording again

Example C — reset

  • POST /sessions/{id}/reset restarts with catch_up_sec=0, so the producer paces again from the archive start (or start_at slice), not from “now”

Continuous sessions: what-if scenarios

Scenario Behavior
No listener connected Producer still advances from Match.scheduled; publish does not wait for subscribe
Listener cancel / replace Listener process exits as today; new subscribe with the same session joins the live tip (no rewind to archive start)
Two listeners, same session Fanout from one producer / one clock; both see the same live tip
Two listeners, different session ids Independent producers (or one-shot fallback if that session was never started). Different clones of the same sr_id are different sessions by design
session omitted Legacy one-shot: new per-request replay from archive start (or start_at); reconnect restarts from the beginning; does not join a continuous session
Same clone, wrong/unknown session Unknown/non-live session → same one-shot fallback as omitting it (debug path), not the live producer
srsim crash / restart / --reload In-memory registry lost; watcher recreates session + catch-up from scheduled + params; reconnect joins new live tip; events during outage are missed (not replayed)
uvicorn --workers > 1 Unsupported for continuous sessions — each worker has its own registry; duplicate clocks / wrong join. Keep --workers 1
Stop listener vs reset session Stop listener does not stop or rewind the sim clock; POST /sessions/{id}/reset (or /stop) is required to rewind/halt the producer
Clone form fields scheduled_at = continuous-session kickoff when Wait for listener is off; start_at/speed/delays configure playback; Wait for listener off → auto-inject session= (default); on → one-shot (no session=)
How closely this mimics Sportradar Mimics reconnect/join-live and “feed continues without a client”; still paced archive replay with clone knobs — not a live Sportradar game feed
Process model Same srsim process; lifespan watcher + in-process producer thread per session; not a separate OS process or Celery job

Event Filtering Parameters

start_at

Type: string
Required: No
Default: Start from the beginning of the game

Filters events to start at a specific event. The filter string can be: - A stream timestamp: bare float (e.g. "1661558839.352656") or prefixed ("ts:1661558839.352656"). Use the ts: prefix for integer unix times so they are not treated as array indices. - An event ID (UUID) - A period/clock time for NHL/NFL (e.g., "1:10:00" for period 1, 10 minutes, 0 seconds remaining) - An MLB half-inning (e.g., "1:T" / "1:B" for top/bottom of the 1st; aliases top / bottom are accepted). Matches the first event with that payload.event.inning and inning_half. - An array index (e.g., "0" for the first event)

The event matching the filter string will be the first event in the stream (inclusive).

If no event matches, the filter is silently ignored (no HTTP error): the full recording streams for start_at / end_at, and that entry is skipped for game_delay_at_event. Common case: NHL/NFL clock forms like 1:00 or 1:10:00 on an MLB feed — MLB has no period.sequence / countdown clock, so use 1:T / 1:B instead. The admin Clone Past Match form does not validate league-specific syntax; it passes the value through to srsim.

Listener shortcode recordings under {FILESYSTEM_CONTAINER_DATA_DIR}/listener/ store enriched MatchListenerEvent dumps (gid / ts / eid / data / corrective). srsim flattens those to Sportradar push wire shape (payload / heartbeat at the top level) when loading and streaming so filters and clients see the live feed layout. On-disk archives stay enriched.

Examples:

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&start_at=1:10:00
?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&start_at=1:T
?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&start_at=1661558839.352656
?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&start_at=ts:1661558839

end_at

Type: string
Required: No
Default: Stream until the end of the game

Filters events to end at a specific event. The filter string format is the same as start_at. The event matching the filter string will be the last event in the stream (inclusive).

Examples:

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&end_at=2:05:00
?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&end_at=2:B
?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&end_at=ts:1661559000.0

Stream Control Parameters

playback_speed

Type: integer
Required: No
Default: 1
Range: 0 or greater

Playback speed multiplier for event timing: - 0 = No delay between events (stream as fast as possible) - 1 = Normal speed (uses original event timestamps) - 2 = 2x speed (half the delay between events) - 3 = 3x speed, etc.

Example:

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&playback_speed=2

default_event_delay_ms

Type: integer
Required: No
Default: 500
Range: 0 or greater

Default delay in milliseconds between events when event timestamps are not available or invalid. This is used as a fallback when the simulator cannot determine the actual time difference between consecutive events.

Example:

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&default_event_delay_ms=1000

max_ms_between_events

Type: integer
Required: No
Default: 60000 (60 seconds)
Range: 0 or greater

Maximum milliseconds allowed between events. If the calculated delay between two events exceeds this value, it will be capped at this maximum. This prevents extremely long delays in the stream.

Example:

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&max_ms_between_events=30000

Heartbeat Control Parameters

skip_heartbeats

Type: boolean or integer
Required: No
Default: false (0)

When enabled, heartbeat events are not sent in the stream. This includes:

  • Heartbeats already present in the recorded match JSON (top-level "heartbeat" key)
  • Heartbeats injected during game_delay_at_event delays
  • Heartbeats from end_with_infinite_heartbeats (that mode produces no output when skip is on)

Timing between remaining events is still applied (playback_speed, default_event_delay_ms, etc.). Accepts 1/true or 0/false.

Example:

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&skip_heartbeats=1

heartbeat_ms_override

Type: integer
Required: No
Default: -1 (disabled)

Override the heartbeat interval in milliseconds. When set to a value greater than -1, heartbeat events will use this interval instead of the default 5 seconds. Set to -1 to disable the override and use the default interval.

Example:

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&heartbeat_ms_override=10000

end_with_infinite_heartbeats

Type: boolean or integer
Required: No
Default: false (0)

When enabled, the stream will continue sending heartbeat events indefinitely after all game events have been streamed. Accepts 1/true or 0/false.

Example:

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&end_with_infinite_heartbeats=1

Event Processing Parameters

skip_corrective_events

Type: boolean or integer
Required: No
Default: false (0)

When enabled, events that have already been published to the stream (identified by duplicate event IDs) are skipped. This is useful for handling corrective events that may appear later in the event sequence. Accepts 1/true or 0/false.

Example:

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&skip_corrective_events=1

rewrite_ts_strategy

Type: integer
Required: No
Default: 0 (NO_REWRITE)

How each event’s stream ts is set while srsim plays the recording. This matters when the listener uses LISTENER_TIMING_SOURCE=ts (min-interval and correction windows compare stream ts deltas).

Value Name Behavior
0 NO_REWRITE Keep original recorded ts (real game clock from the archive). Prefer for accelerated playback when you still want large in-game gaps for ts timing gates. Clone Past Match default.
1 CURRENT_TIME Set ts = time.time() at emit. Gaps follow real-time sleep during playback (playback_speed / max_ms_between_events shrink them).
2 RUNNING_TIME Start a synthetic clock at stream open (time.time()). After each event, advance it by the simulator’s inter-event delay (archive gap after max_ms_between_events / default-delay caps). That stamped gap is added in full; playback_speed only shortens the real-time sleep, so stamped ts can run ahead of real time when speed > 1. Discards absolute archive timestamps; does not re-read real time at each emit.

Example:

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&rewrite_ts_strategy=1

Game Delay Parameters

game_delay_at_event

Type: string
Required: No
Default: No delays

Configures game delays at specific events. The format is a comma-separated list of delay specifications, where each specification is:

event_identifier;duration_seconds
  • event_identifier: Same filters as start_at — event ID (UUID), NHL/NFL period/clock (e.g. "1:10:00"), MLB half-inning (e.g. "1:B"), stream ts, or array index
  • duration_seconds: Duration of the delay in seconds (optional, defaults to 900 seconds if omitted)

When a delay is triggered at the specified event, the simulator will:

  1. Send heartbeat events during the delay period (stream injection only)
  2. Resume normal event streaming after the delay duration

Match status (observers): Redis delay tracking is gone. For continuous is_test sessions, srsim owns Match.status as a provider-side stand-in for Sportradar schedule refresh: inprogress when the session producer starts, delayed / inprogress around game_delay_at_event or archive synthetic delay markers (heartbeats continue on the stream), postponed on synthetic.type=game_postponed, and closed when the stream completes normally. Live non-test rows still come from Sportradar Beat refresh. The MatchListener does not write status. srsim GET /delays reads delayed Match rows (today’s UTC calendar day, plus any delayed test clone).

Archive synthetic markers (auto delay / postpone)

Live listeners append non-Sportradar markers to the event recording when they observe Match.status transitions (from Beat refresh), under a top-level synthetic object:

synthetic.type Meaning
game_delay_start Status became delayed
game_delay_end Status left delayed (e.g. back to inprogress)
game_postponed Status became postponed

On replay, srsim honors these: sleeps for the ts delta between start and end (default 900s if end is missing), skips intermediate archive events in that window, flips test-session status, and ends the stream on postpone. Manual game_delay_at_event still works alongside markers. Markers are not written for is_test clones (srsim already owns their status).

Live listeners reset the consecutive-heartbeat counter on each status check that still sees Match.status=delayed, so rain-delay silence does not reach listener_max_consecutive_heartbeats and tear down the process mid-delay.

Examples:

Single delay at a specific event:

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&game_delay_at_event=1:10:00;600

MLB half-inning delay:

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&game_delay_at_event=1:B;600

Multiple delays at different events:

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&game_delay_at_event=1:10:00;600,2:05:00;300

Delay using event ID:

?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&game_delay_at_event=cd161ae3-9e6c-41ee-811e-9711a1d9aa2a;900

Complete Example

Here's an example combining multiple parameters:

/mlb/trial/stream/en/events/subscribe?match=sd:match:673751e5-3f53-4643-9a3c-668f0e5c66ec&start_at=1:T&end_at=2:B&playback_speed=2&skip_heartbeats=0&heartbeat_ms_override=10000&game_delay_at_event=1:B;600

This example: - Streams MLB game events from the top of the 1st through the bottom of the 2nd - Plays events at 2x speed - Sends heartbeats every 10 seconds - Delays the game for 600 seconds (10 minutes) at the start of the bottom of the 1st

Notes

  • Boolean parameters accept both 1/0 and true/false values
  • All timing parameters use milliseconds unless otherwise specified
  • The game_delay_at_event parameter requires the game events to be loaded to parse event identifiers, so it's processed after the events are loaded
  • Unmatched start_at / end_at / game_delay_at_event identifiers fail silently (full stream / skipped delay). Do not use NHL/NFL period:mm:ss on MLB recordings; use inning:half (1:T, 1:B).
  • When using end_with_infinite_heartbeats, the stream will never terminate unless the connection is closed
  • Continuous sessions with session=<internal match id> own Match.status (start → inprogress, delays, completion → closed); one-shot streams do not. GET /delays reads Postgres.