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:
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), notMatch.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_testmatches; subscribe withsession=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):
Example (one-shot — no session):
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=0means 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}/resetrestarts withcatch_up_sec=0, so the producer paces again from the archive start (orstart_atslice), 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:
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:
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:
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_eventdelays - 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:
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:
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:
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:
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:
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: Same filters asstart_at— event ID (UUID), NHL/NFL period/clock (e.g."1:10:00"), MLB half-inning (e.g."1:B"), streamts, or array indexduration_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:
- Send heartbeat events during the delay period (stream injection only)
- 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:
MLB half-inning delay:
Multiple delays at different events:
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/0andtrue/falsevalues - All timing parameters use milliseconds unless otherwise specified
- The
game_delay_at_eventparameter 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_eventidentifiers fail silently (full stream / skipped delay). Do not use NHL/NFLperiod:mm:sson MLB recordings; useinning: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>ownMatch.status(start →inprogress, delays, completion →closed); one-shot streams do not.GET /delaysreads Postgres.