Push Feeds
With RESTful endpoints you make a request each time you want new data. Push feeds instead open a connection with a single call and deliver continuous live updates: no pull frequency to manage, just listen for match updates as they happen.
AccessTennis Push feeds are available for Sportradar Realtime customers and are not part of the self-issued trial in your account. Reach out to a sales representative for trial access.
Push and RESTful Together
Each Push update is a payload that mirrors the structure of a similar RESTful feed. Payloads are delivered for changes to events and statistics, not for match status updates.
| Push feed | RESTful counterparts |
|---|---|
| Push Events | Live Timelines, Sport Event Timeline |
| Push Statistics | Live Summaries, Sport Event Summary |
Push complements the RESTful API rather than replacing it. Push has no stateful session: there is no memory of or access to previously sent data. After a disconnection, use the corresponding RESTful feed to recover anything missed (for Push Events, catch up from Live Timelines or Sport Event Timeline). Push feeds also do not carry every data point the RESTful API serves, so a complete integration uses both.
Making a Request
Each Push feed starts with a URL request, like any other endpoint:
curl -L -X GET 'https://api.sportradar.com/tennis/{access_level}/{version}/stream/events/subscribe' \
-H 'x-api-key: {your_api_key}'The call opens an HTTP redirect connection that returns all Push data for the requested feed. There are no restrictions on the number of open connections: filter requests to individual matches and close connections as matches complete, or keep a single unfiltered connection open indefinitely.
Filtering
By default a Push feed delivers everything: an unfiltered Push Events connection streams every tennis match in progress. Add query strings to narrow the stream, for example to one match:
curl -L -X GET 'https://api.sportradar.com/tennis/trial/v3/stream/events/subscribe?&format=json&sport_event_id=sr:sport_event:13468929' \
-H 'x-api-key: {your_api_key}'See the endpoint pages for the full query string syntax.
Technical Requirements
To accept data from Push feeds, ensure your application can:
- Follow an HTTP redirect, or use the location provided in the feed's header within one minute of your initial request.
- Accept HTTP data transfer encoded as chunked.
Payloads
Push is delivered by HTTP streaming with chunked encoding: a long HTTP response whose chunks you act on as they arrive. When no new information is available, a heartbeat message is sent every 5 seconds to keep the connection active. Messages are delivered in JSON format only.
A stream interleaves heartbeats with payloads. Here is an excerpt showing a heartbeat, a period_score payload with its metadata, and further heartbeats:
}{
"heartbeat":{
"from":1738689527,
"interval":5,
"to":1738689532,
"type":"events",
"package":"tennis-v3"
}
}{
"payload":{
"sport_event_status":{
"status":"live",
"match_status":"3rd_set",
"home_score":1,
"away_score":1,
"period_scores":[
{
"home_score":4,
"away_score":6,
"type":"set",
"number":1
},
{
"home_score":6,
"away_score":1,
"type":"set",
"number":2
},
{
"home_score":5,
"away_score":2,
"type":"set",
"number":3
}
],
"game_state":{
"home_score":0,
"away_score":0,
"serving":"away",
"last_point_result":"receiver_winner",
"tie_break":false
}
},
"event":{
"id":485308,
"type":"period_score",
"time":"2025-02-04T17:18:50+00:00",
"period":"3",
"competitor":"home",
"home_score":5,
"away_score":2,
"server":"home",
"result":"server_won"
}
},
"metadata":{
"format":"json",
"sport_event_id":"sr:sport_event_id:57798949",
"event_id":"period_score",
"channel":"tennis",
"competition_id":"sr:competition:35428",
"sport_id":"sr:sport:5",
"season_id":"sr:season:126111"
}
}{
"heartbeat":{
"from":1738689532,
"interval":5,
"to":1738689537,
"type":"events",
"package":"tennis-v3"
}
}{
"heartbeat":{
"from":1738689537,
"interval":5,
"to":1738689542,
"type":"events",
"package":"tennis-v3"
}
}{
"heartbeat":{
"from":1738689542,
"interval":5,
"to":1738689547,
"type":"events",
"package":"tennis-v3"
}Disconnections
If heartbeats stop arriving, or you are disconnected for any reason, reconnect using your same initial request, then backfill from the RESTful counterparts.
Metadata
Each payload carries a metadata object identifying the payload type and its match, competition, sport, and season. Use it to filter and route messages without parsing the full payload:
{
"metadata": {
"format": "json",
"sport_event_id": "sr:sport_event_id:57756307",
"event_id": "point",
"channel": "tennis",
"competition_id": "sr:competition:34320",
"sport_id": "sr:sport:5",
"season_id": "sr:season:124107"
}
}{
"metadata": {
"format": "json",
"sport_event_id": "sr:sport_event_id:57756307",
"event_id": "period_score",
"channel": "tennis",
"competition_id": "sr:competition:34320",
"sport_id": "sr:sport:5",
"season_id": "sr:season:124107"
}
}ID Updates
Events in the Push Events stream carry an updated flag set to true when a message creates or revises a previously delivered event. When you receive an event with the same ID as one already consumed, replace the earlier data with the most recent message:
{
"payload": {
"sport_event_status": {
"status": "live",
"match_status": "2nd_set",
"home_score": 0,
"away_score": 1,
"period_scores": [
{
"home_score": 2,
"away_score": 6,
"type": "set",
"number": 1
},
{
"home_score": 2,
"away_score": 5,
"type": "set",
"number": 2
}
],
"game_state": {
"home_score": 15,
"away_score": 40,
"serving": "away",
"last_point_result": "ace",
"tie_break": false,
"point_type": "match"
}
},
"event": {
"id": 1961571099,
"type": "point",
"time": "2025-02-04T17:23:26+00:00",
"competitor": "away",
"updated": true,
"updated_time": "2025-02-04T17:23:33+00:00",
"home_score": 15,
"away_score": 40,
"server": "away",
"result": "ace"
}
}
}Code and Data Samples
Sample consumers in Ruby and Java are below; both print the stream to STDOUT. For Java, a Stream Client is also available. In the Java sample, replace "URL GOES HERE" with the desired Push feed URL.
require 'httpclient'
module Sportradar
module HTTP
module Stream
class Client
attr_reader :url, :logger
def initialize(url, api_key, logger)
@url = url
@logger = logger
@api_key = api_key
@client = ::HTTPClient.new(agent_name: 'SportsData/1.0')
end
def start
@thread ||= Thread.new do
logger.debug "Starting loop"
headers = {
'x-api-key' => @api_key
}
@client.get_content(url, header: headers, 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
endpackage com.sportradar.http.stream.client;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class StreamClient {
private Thread streamThread;
private volatile boolean running = false;
private String apiKey;
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public void stream(String serviceUrl, Handler handler) {
running = true;
streamThread = new Thread(() -> {
try {
URL url = new URL(serviceUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("User-Agent", "SportsData/1.0");
if (apiKey != null && !apiKey.isEmpty()) {
connection.setRequestProperty("x-api-key", apiKey);
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
String line;
while (running && (line = reader.readLine()) != null) {
if (!line.trim().isEmpty()) {
handler.handle(line);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
});
streamThread.start();
}
public void terminate() {
running = false;
if (streamThread != null) {
streamThread.interrupt();
}
}
}Complete data samples of a full match are available for Push Events and Push Statistics.
Endpoint Docs
Visit the links below for syntax structure, data samples, and data dictionaries:
- Push Events: detailed, real-time information on every live match event.
- Push Statistics: detailed, real-time match stats for all live matches.
Updated 9 days ago
