Integration GuidesReference Docs
Coverage MatrixDocumentationChange LogLog InContact Us
Integration Guides

Push Feeds

The feeds elsewhere in this guide are RESTful pull feeds: you request them on a schedule you control. The UFL API also offers two Push feeds, Push Events and Push Statistics, which hold a connection open and stream game updates to you as they happen. This page covers opening and filtering a connection, reading the stream, and recovering when a connection drops.



The Push Feeds

Each Push message is a JSON payload that mirrors the structure of a RESTful counterpart, so the parsing you build for the pull feeds carries over:

Push feedRESTful counterpartWhat streams
Push EventsGame Play-by-PlayEvery play and event as it is entered, with situations, per-play statistics, and details
Push StatisticsGame StatisticsTeam and player box statistics, updated as plays resolve

Push complements the pull feeds rather than replacing them. A Push session is not stateful: there is no way to request data the stream already sent, so pair Push with the RESTful game feeds for preloads, catch-up, and the validated final described in Game Status Workflow.

Push Connection LifecycleSubscribe once, then listen; recover from the RESTful side
SubscribeGET subscribefollow redirectwithin one minute of the request
Listenchunked JSON streamheartbeat every 5 seconds when quiet
Applypayload messagesreplace stored events by id; operation is update or delete
Recoverreconnectsame subscribe request; close the gap from the RESTful game feeds
An unfiltered connection streams every game in progress; the sections below cover each step.

🔐

Push is a Realtime add-on

The Push Events and Push Statistics feeds are part of Sportradar's Realtime offering and are not included in every package. Contact your Sportradar representative to add Push to your package.



Opening a Connection

A Push connection starts as an ordinary GET with your API key. The response is an HTTP redirect to the stream, which then delivers chunked JSON indefinitely:

GET https://api.sportradar.com/ufl/{access_level}/stream/{language_code}/events/subscribe
x-api-key: YOUR_API_KEY
GET https://api.sportradar.com/ufl/{access_level}/stream/{language_code}/statistics/subscribe
x-api-key: YOUR_API_KEY

For your application to accept the stream, ensure that it can:

  • Follow an HTTP redirect (or use the Location header from the initial response) within one minute of the request
  • Accept HTTP data transfer encoded as chunked


Filtering the Stream

An unfiltered connection streams every game in progress. Query string parameters narrow the stream, and each parameter is added with a preceding ampersand:

ParameterValuesUse
matchmatch=sd:match:{game_guid}One game
teamteam=sd:team:{team_guid}One team's games
statusinprogress, createdGames in a given status
event_typesetup, timeout, tv_timeout, two_minute_warning, comment, period_end, game_overSpecific event types
event_categoryredzone, two_minute, scoring_play, big_play, turnoverHigh-interest situations
GET https://api.sportradar.com/ufl/trial/stream/en/events/subscribe?&status=inprogress&match=sd:match:c5cce400-a716-49d0-bbbe-1a84fb200fa3
x-api-key: YOUR_API_KEY

The sd: prefix wraps the same GUID the RESTful paths use; ID Handling covers the ID families.



Reading the Stream

Messages arrive one JSON document at a time. When no game data is flowing, a heartbeat arrives every 5 seconds to keep the connection alive; anything else is a payload message:

{
  "heartbeat": {
    "interval": 5000
  }
}

A Push Events payload pairs a game envelope (score, clock, quarter) with the event that just changed. The opening kickoff of a week 1 game shows the shape; the full message carries the same period, drive, situation, statistics, and details nodes as the RESTful Play-by-Play, trimmed here to the envelope:

{
  "payload": {
    "game": {
      "id": "c5cce400-a716-49d0-bbbe-1a84fb200fa3",
      "status": "inprogress",
      "coverage": "full",
      "game_type": "regular",
      "scheduled": "2026-03-28T16:00:00+00:00",
      "quarter": 1,
      "clock": "14:55",
      "summary": {
        "home": {
          "name": "Battlehawks",
          "market": "St. Louis",
          "alias": "STL",
          "points": 0
        },
        "away": {
          "name": "Defenders",
          "market": "DC",
          "alias": "DC",
          "points": 0
        }
      },
      "sr_id": "sr:match:68165532"
    },
    "event": {
      "type": "play",
      "id": "c8992780-2aba-11f1-bb44-7d8e81a24ff9",
      "sequence": 1774713956580,
      "clock": "15:00",
      "home_points": 0,
      "away_points": 0,
      "created_at": "2026-03-28T16:05:56+00:00",
      "updated_at": "2026-03-28T16:05:57+00:00",
      "play_type": "kickoff",
      "description": "M.McCrane kicks 65 yards from DC 30 to the STL 5. G.Jennings returns the kickoff. Tackled by DC at STL 31."
    }
  },
  "locale": "en",
  "metadata": {
    "match": "sd:match:c5cce400-a716-49d0-bbbe-1a84fb200fa3,sr:match:68165532",
    "team": "sd:team:a3407150-c045-11ee-b66f-5d382d09dbaf,sr:competitor:661851",
    "league": "ufl",
    "locale": "en",
    "status": "inprogress",
    "event_type": "kickoff",
    "event_category": "",
    "operation": "update",
    "version": "v7"
  }
}
{
  "payload": {
    "event": {
      "type": "play",
      "id": "c8992780-2aba-11f1-bb44-7d8e81a24ff9",
      "clock": "15:00",
      "updated_at": "2026-03-28T16:06:08+00:00",
      "play_type": "kickoff",
      "description": "M.McCrane kicks 65 yards from DC 30 to the STL 5. G.Jennings returns the kickoff. Tackled by D.Parish at STL 31."
    }
  },
  "locale": "en",
  "metadata": {
    "match": "sd:match:c5cce400-a716-49d0-bbbe-1a84fb200fa3,sr:match:68165532",
    "team": "sd:team:a3407150-c045-11ee-b66f-5d382d09dbaf,sr:competitor:661851",
    "league": "ufl",
    "locale": "en",
    "status": "inprogress",
    "event_type": "kickoff",
    "event_category": "",
    "operation": "update",
    "version": "v7"
  }
}

The second tab is the same kickoff moments later: the stream re-sent event c8992780-... once the tackler was attributed (the description now names D.Parish, and updated_at moved). When a message carries an event id you have already consumed, replace the stored event with the new message. The metadata.operation value distinguishes an update (create or revise) from a delete, which tells you to remove the stored event instead.



Statistics Messages

Push Statistics streams two message shapes. Player messages carry the player and the statistics category a play just changed, and are small enough to apply directly. Team messages carry the full category set for one team; at kickoff they arrive as the game's opening baseline (trimmed here to the rushing category):

{
  "payload": {
    "player": {
      "full_name": "Gary Jennings Jr.",
      "first_name": "Gary",
      "last_name": "Jennings",
      "name_suffix": "Jr.",
      "id": "ab7edd60-cc67-11ee-a60a-8d7f07d3367e",
      "position": "WR",
      "name": "Gary Jennings Jr.",
      "jersey": "05"
    },
    "kick_returns": {
      "yards": 26,
      "avg_yards": 26,
      "touchdowns": 0,
      "longest": 26,
      "faircatches": 0,
      "number": 1
    }
  },
  "locale": "en",
  "metadata": {
    "match": "sd:match:c5cce400-a716-49d0-bbbe-1a84fb200fa3,sr:match:68165532",
    "league": "ufl",
    "locale": "en",
    "status": "inprogress",
    "participant": "sd:player:ab7edd60-cc67-11ee-a60a-8d7f07d3367e",
    "operation": "update",
    "version": "v7"
  }
}
{
  "payload": {
    "name": "Defenders",
    "market": "DC",
    "alias": "DC",
    "id": "c5cce400-a716-49d0-bbbe-1a84fb200fa3",
    "status": "inprogress",
    "quarter": 1,
    "clock": "15:00",
    "rushing": {
      "avg_yards": 0,
      "attempts": 0,
      "touchdowns": 0,
      "tlost": 0,
      "tlost_yards": 0,
      "yards": 0,
      "redzone_attempts": 0,
      "broken_tackles": 0,
      "kneel_downs": 0,
      "scrambles": 0,
      "yards_after_contact": 0,
      "firstdowns": 0
    },
    "sr_id": "sr:match:68165532"
  },
  "locale": "en",
  "metadata": {
    "match": "sd:match:c5cce400-a716-49d0-bbbe-1a84fb200fa3,sr:match:68165532",
    "league": "ufl",
    "locale": "en",
    "status": "inprogress",
    "participant": "sd:team:a3407150-c045-11ee-b66f-5d382d09dbaf",
    "operation": "update",
    "version": "v7"
  }
}

Two details of the team shape are worth noting: the top-level id and sr_id are the game's GUID and URN (the team is identified by name, market, and alias), and the message subject rides metadata.participant on both shapes (sd:team: or sd:player: wrapping the entity GUID).



Metadata and Routing

Every payload closes with a metadata block: the league, the game, the operation, and the event type or participant the message concerns. Comma-delimited values pair the sd:-prefixed GUID with the sr: URN for the same entity, so read them as an array:

  • "match": "sd:match:c5cce400-...,sr:match:68165532" is one game under both ID families
  • Route messages by metadata.match before parsing the payload when you track several games on one connection
  • Filter high-interest moments client-side with event_type and event_category, which carry the same values the query string parameters accept


Recovering from Disconnections

If heartbeats stop arriving, or the connection drops for any reason, reconnect with the same subscribe request. The stream resumes with current data only, so close the gap from the RESTful side:



Testing Push

Simulations replay UFL games on demand, including both Push feeds, so you can exercise connection handling, message parsing, and recovery at any time of year without waiting for the spring schedule.


Did this page help you?