Skip to content
  • There are no suggestions because the search field is empty.

Oddin.gg Bragi - Data Feed documentation

Introduction

At Oddin.gg we believe the future belongs to Esports, and we want to help drive that future. Bragi is our data feed: it streams real-time information for every match we distribute. For each match we provide the current live state, score, team and player statistics, and a great deal of supporting information that you can use to power your own products.

1. General information

This chapter explains the core concepts behind the Bragi data feed. If anything below is unclear, please get in touch through your usual Oddin.gg communication channel.

1.1. Concept

The API is built on gRPC and protocol buffers. gRPC is a proven, high-performance framework used at scale by Google, Microsoft and many others. It generates client and server bindings for most popular languages, including Java, C#, Python, Node.js, Go and others. Protocol buffers are used as the message format: they are compact, fast to encode and decode, and well supported across the industry.

1.2. Environments

Two environments are available. Use the integration environment for all development and testing, and only move to the production environment once your integration is complete and ready for live traffic.

Environment API URL
Production api-bragi.oddin.gg:443
Integration api-bragi.integration.oddin.gg:443

1.3. gRPC schema definition

The full schema is open and published on GitHub:

You can generate client bindings for your language of choice directly from the .proto files or use one of our pre-generated bindings for Java, Go, or Node.js.

1.4. Authentication

  • IP whitelisting: access to the API is allowed only from known IP addresses. Each environment has its own whitelist. Send the IPs (or IP ranges) you want to register, together with the environment name, to your technical integration contact.
  • Access token: every call to the data feed must carry a valid access token. You receive a separate token for each environment from our back-office. Tokens are normally valid for one year and are auto-extended.

ℹ️ A maximum of fifty (50) concurrent connections can be made to any of the streams, applied separately to each environment.

1.5. Service definition

The Bragi service exposes both unary calls (single request, single response) and server streams (single request, ongoing stream of responses). The table below summarises every remote procedure call (RPC) defined in the schema.

RPC Type Description
MatchTimelineSports Unary Returns every sport together with the count of planned or currently played matches.
MatchTimelineTournaments Unary Returns every tournament together with the count of planned or currently played matches.
MatchTimeline Unary Returns every planned or currently played match.
TeamProfile Unary Returns comprehensive information for a single team, including external identities and the current map roster.
MatchTimelineSportsFeed Stream Streams real-time updates of the per-sport match counts.
MatchTimelineTournamentsFeed Stream Streams real-time updates of the per-tournament match counts.
MatchTimelineFeed Stream Streams every upcoming and live match, plus real-time updates whenever a match status changes. Stay connected to keep your timeline current.
LiveDataFeed Stream Streams LiveDataFeedMessage frames in a single direction (server to client). This is the main live match-state stream.
MatchEventsFeed Stream Streams historical events for currently played matches, followed by real-time event updates.

2. Match timeline

MatchTimeline provides three categories of gRPC endpoints for retrieving real-time and planned match data: Sports, Tournaments and Matches. Each category exposes a unary endpoint for one-off requests and a server-streamed endpoint for continuous updates.

Endpoint category Purpose Unary endpoint Stream endpoint Key filtering parameters
Sports List sports and per-sport match counts. MatchTimelineSports MatchTimelineSportsFeed live_only (boolean)
Tournaments List tournaments and per-tournament match counts. MatchTimelineTournaments MatchTimelineTournamentsFeed live_only (boolean), sport (enum)
Matches List every current and planned match. MatchTimeline MatchTimelineFeed live_only, sport, tournament_urn, match_urn, team_name

Both count-based endpoints (Sports and Tournaments) use the live_only parameter to choose whether the count should include all matches or only live matches. The Matches endpoints offer the richest filtering, including by URN, sport and team name.

2.1. MatchTimeline sports

Two gRPC endpoints return the list of sports together with a count of current and upcoming matches per sport. The count returned depends on the live_only flag in the request:

  • MatchTimelineSports — a one-off (unary) call.
  • MatchTimelineSportsFeed — a stream that pushes updates as match counts change.

MatchTimelineSportsRequest / MatchTimelineSportsFeedRequest

Parameter Type Description
live_only bool If false, the endpoint returns the total count of all matches for a given sport. If true, only live matches are counted.

MatchTimelineSportsResponse / MatchTimelineSportsFeedResponse

Field Type Description
sports repeated SportMatchCount List of sports with their corresponding match counts.

SportMatchCount (nested message)

Field Type Description
sport Sport The sport this row refers to. See the Sport enum below.
match_count uint32 Number of matches for that sport, filtered by live_only.

Example JSON — request and response

// MatchTimelineTournamentsRequest
{
"live_only": false,
"sport": "SPORT_CS2"
}

// MatchTimelineTournamentsResponse
{
"tournaments": [
{
"tournament": {
"urn": "od:tournament:1001",
"name": "ESL Pro League",
"is_offline": false,
"start_date": "2026-03-15T14:00:00Z",
"organizer_id": 42,
"organizer_name": "ESL"
},
"match_count": 24
}
]
}

2.2. MatchTimeline tournaments

Two gRPC endpoints return the list of tournaments together with a count of current and upcoming matches per tournament. The count returned depends on the live_only flag in the request:

  • MatchTimelineTournaments — a one-off (unary) call.
  • MatchTimelineTournamentsFeed — a stream that pushes updates as match counts change.

MatchTimelineTournamentsRequest / MatchTimelineTournamentsFeedRequest

Parameter Type Description
live_only bool If false, returns the total count for each tournament. If true, only live matches are counted.
sport Sport (enum) Restricts the response to tournaments belonging to the given sport.

MatchTimelineTournamentsResponse / MatchTimelineTournamentsFeedResponse

Field Type Description
tournaments repeated TournamentMatchCount List of tournaments with their match counts.

TournamentMatchCount (nested message)

Field Type Description
tournament Tournament The tournament this row refers to.
match_count uint32 Number of matches for that tournament, filtered by live_only.

Example JSON — request and response

// MatchTimelineTournamentsRequest
{
"live_only": false,
"sport": "SPORT_CS2"
}

// MatchTimelineTournamentsResponse
{
"tournaments": [
{
"tournament": {
"urn": "od:tournament:1001",
"name": "ESL Pro League",
"is_offline": false,
"start_date": "2026-03-15T14:00:00Z",
"organizer_id": 42,
"organizer_name": "ESL"
},
"match_count": 24
}
]
}

2.3. MatchTimeline matches

Two gRPC endpoints return every currently played and planned match:

  • MatchTimeline — a oneof (unary) call.
  • MatchTimelineFeed — a stream that automatically pushes updates whenever a match status changes.

ℹ️ The MatchTimelineFeed endpoint may include matches that have not yet started. For those matches, you will not have received any update message through the LiveDataFeed yet.

MatchTimelineRequest / MatchTimelineFeedRequest

Parameter Required Type Description
live_only No bool When true, only live matches are returned.
sport No Sport (enum) Restricts the response to a single sport.
tournament_urn No string Unique identifier of a tournament, for example od:tournament:12345.
match_urn No string Unique identifier of a match. A partial URN such as od:match:23 returns every match whose URN starts with that string.
team_name No string A substring; matches whose team names contain it are returned.

MatchTimelineResponse

Field Type Description
matches repeated Match List of matches that satisfy the supplied filters.

MatchTimelineFeedMessage

Wraps a single frame on the MatchTimelineFeed stream. Exactly one of the oneof fields below is set per message.

Field Type Description
keepalive KeepAlive Deprecated. Replaced by the built-in gRPC keep-alive (see section 3.4).
timeline MatchTimeline A full timeline snapshot containing the current set of matches.
match_update Match An incremental update for a single match.

Example JSON — MatchTimelineFeedMessage

// Initial timeline frame
{
"timeline": {
"matches": [
{
"match_urn": "od:match:55501",
"sport": "SPORT_CS2",
"home_score": 0,
"away_score": 0,
"match_status": "MATCH_STATUS_TYPE_NOT_STARTED",
"planned_start": "2026-05-27T18:00:00Z",
"tournament": { "urn": "od:tournament:1001", "name": "ESL Pro League" },
"teams": [
{ "urn": "od:team:101", "name": "Team Alpha", "is_home": true },
{ "urn": "od:team:202", "name": "Team Bravo", "is_home": false }
]
}
]
}
}

// Subsequent update frame
{
"match_update": {
"match_urn": "od:match:55501",
"sport": "SPORT_CS2",
"home_score": 1,
"away_score": 0,
"match_status": "MATCH_STATUS_TYPE_LIVE"
}
}

2.4. Common match data structures

The messages below are returned across the MatchTimeline endpoints and are reused throughout the schema. They describe the basic shape of a match, the tournament it belongs to, the teams involved and the players on those teams.

MatchTimeline

Field Type Description
matches repeated Match The list of matches in this timeline snapshot.

Match

Field Type Description
match_urn string Unique match identifier, e.g., od:match:55501.
tournament_urn string Deprecated. Use tournament instead.
sport Sport Sport this match belongs to.
home_team_urn string Deprecated. Use teams instead.
away_team_urn string Deprecated. Use teams instead.
home_score uint32 Current score of the home team.
away_score uint32 Current score of the away team.
match_status MatchStatusType Current status (not started, live, finished, cancelled or placeholder).
plannet_start google.protobuf.Timestamp Planned start time of the match (UTC).
tournament Tournament Tournament the match belongs to.
teams repeated Team Teams taking part in the match.
players repeated Player Players taking part in the match.

Tournament

Field Type Description
urn string Unique tournament identifier, e.g., od:tournament:1001.
name string Display name.
is_offline bool True if the tournament is held offline (LAN), false otherwise.
start_date google.protobuf.Timestamp Tournament start date and time (UTC).
organizer_id uint32 Internal identifier of the tournament organizer.
organizer_name string Display name of the organizer.

Team

Field Type Description
urn string Unique team identifier, e.g., od:team:123.
name string Team display name.
is_home bool True if the team is the home team.

Player

Field Type Description
urn string Unique player identifier, e.g., od:player:123.
nickname string Player's in-game nickname.
team_urn string URN of the team the player belongs to.

3. Processing the data feed

3.1. Connection to the data feed

To open the live data stream, the client calls the LiveDataFeed RPC and sends a LiveDataFeedRequest. LiveDataFeedRequest has a single optional timestamp field named after.

When connecting for the first time, leave the after field unset (null). The server then sends the data for every currently played match. If you want to receive matches older than those currently in play, set after to the timestamp of the last update you processed (UNIX milliseconds). The server will then send data for the matches whose latest update was processed at or after that timestamp.

LiveDataFeedRequest

Field Type Description
after google.protobuf.Timestamp (optional) Optional. The timestamp from which match states should be received. If unset, only currently played matches are returned. If set, the server returns matches whose latest update was processed at or after this value.

Example JSON — LiveDataFeedRequest

// First-time connection (no "after")
{}

// Reconnect, resuming from the last processed update
{
"after": "2026-05-27T17:32:11.250Z"
}

3.2. Supported Esports and eSims

Throughout this documentation, the placeholder (Game) is used to refer to any one of the supported Esports or eSims. To use the schema for a specific Esport or eSim, replace (Game) with the relevant prefix (for example, CS2MatchMessage).

Esport Description Active
CS2 Counter-Strike 2 ✅ Yes
DOTA2 Dota 2 ✅ Yes
LOL League of Legends ❌ No
VALORANT Valorant ❌ No
RUSH_BASKETBALL eBasketball ✅ Yes
RUSH_SOCCER eFootball ✅ Yes
RUSH_CRICKET eCricket ✅ Yes

3.3. Match state caching

The stream carries information for many matches and several different Esports. Each match is identified by a unique match URN. Your client is expected to process the incoming messages and keep the current state of every active match in its cache.

A match snapshot contains everything the server knows about a match. The client receives one snapshot per match at the start of the stream and keeps it up to date by applying the updates that follow. The details of this update process are described in (Game)MatchSnapshot message below.

3.4. Keepalive

To keep the live feed connection healthy, configure the keepalive settings in your gRPC client. The recommended values are listed below.

Parameter Value Description Behaviour
Time 10 seconds How often the client sends keepalive pings to the server. A ping is sent every 10 seconds.
Timeout 5 seconds How long the client waits for a pong before considering the connection broken. If no response arrives within 5 seconds, the connection is treated as dead.
PermitWithoutStream true Whether keepalive pings may be sent when there is no active RPC. Keepalive pings are still sent during idle periods, which keeps the connection open.

ℹ️ Make sure these parameters are set in your gRPC client to keep the live data feed connection stable and responsive.

Sample code (Go)

grpc.WithKeepaliveParams(
keepalive.ClientParameters{
Time: 10 * time.Second,
Timeout: 5 * time.Second,
PermitWithoutStream: true,
},
)

3.5. Supported messages

This section describes the protocol buffer messages that flow on the live data feed and how to process them.

3.5.1. LiveDataFeedMessage

LiveDataFeedMessage is the wrapping envelope for every message you receive from the server.

Field Type Description
keepalive KeepAlive Deprecated. Replaced by the built-in gRPC keep-alive.
match MatchMessage Carries the information for a particular match (either an initial snapshot, an update, or an announcement).
3.5.2. MatchMessage

MatchMessage uses a protocol buffer oneof to carry either an AnnouncementUpdate or a game-specific (Game)MatchMessage. The fields below show the available payload types. Each frame from the server sets exactly one of these fields.

Field Type Description
announcement AnnouncementUpdate Append the announcement payload to the announcements array of the cached (Game)MatchSnapshot.
cs2 CS2MatchMessage Wraps a CS2MatchSnapshot or CS2MatchUpdate for a CS2 match.
dota2 Dota2MatchMessage Wraps a Dota2MatchSnapshot or Dota2MatchUpdate for a Dota 2 match.
lol LolMatchMessage Wraps a LolMatchSnapshot or LolMatchUpdate for a League of Legends match.
valorant ValorantMatchMessage Wraps a ValorantMatchSnapshot or ValorantMatchUpdate for a Valorant match.
rush_soccer RushSoccerMatchMessage Wraps a RushSoccerMatchSnapshot or RushSoccerMatchUpdate for an eFootball match.
rush_basketball RushBasketballMatchMessage Wraps a RushBasketballMatchSnapshot or RushBasketballMatchUpdate for an eBasketball match.
rush_cricket RushCricketMatchMessage Wraps a RushCricketMatchSnapshot or RushCricketMatchUpdate for an eCricket match.
active_data_source_type* uint32 Identifier of the active data source that produced this message. *Not yet supported.
3.5.2.1. AnnouncementUpdate message

An AnnouncementUpdate informs your client about operational events during the life of a match — for example, the match has been postponed, or there will be a server outage. The AnnouncementUpdate wraps an Announcement and adds sequence and timestamp fields. When you receive one, append the Announcement payload to the announcements array on the cached (Game)MatchSnapshot.

AnnouncementUpdate

Field Type Description
match_urn string Match this announcement applies to.
sequence uint64 Sequence number; used to detect missing updates (see section 3.5.2.2.1).
timestamp google.protobuf.Timestamp Time the update was produced (UTC).
payload Announcement The announcement itself.

Announcement

Field Type Description
created_at google.protobuf.Timestamp Time the announcement was created.
payload Announcement.Payload Oneof: either a ControlAnnouncement or a ControlErrorAnnouncement.

ControlAnnouncement

Field Type Description
type ControlAnnouncementType The kind of control announcement.
message string (optional) Free-form human-readable description.

ControlErrorAnnouncement

Field Type Description
type ControlErrorAnnouncementType The kind of error announcement.
message string (optional) Free-form human-readable description.

Example JSON — AnnouncementUpdate

{
"match_urn": "od:match:55501",
"sequence": 432,
"timestamp": "2026-05-27T17:34:02.110Z",
"payload": {
"created_at": "2026-05-27T17:34:02.000Z",
"payload": {
"control": {
"type": "CONTROL_ANNOUNCEMENT_TYPE_UNSPECIFIED",
"message": "Match postponed by 15 minutes."
}
}
}
}
3.5.2.2. (Game)MatchMessage message

Each sport has its own MatchMessage type — for example, CS2MatchMessage or Dota2MatchMessage. Protocol buffers do not support interfaces or traits, so there is no generic MatchMessage type at the schema level; we use the (Game)MatchMessage label only in this documentation.

Every (Game)MatchMessage has exactly four properties. Three are common to all sports (match_urn, sequence, timestamp); the fourth, payload, is sport-specific (for example, CS2MatchState).

Property Description
match_urn Identifies the match this message applies to.
sequence A positive integer used to confirm that updates arrive in order. See (Game)MatchSnapshot message below for the full rules.
timestamp Timestamp of the latest update for this match. See (Game)MatchSnapshot message below for how to use it.
payload Oneof. Carries either:
• (Game)MatchSnapshot — sent only as the first message for a match. Cache it in memory, then apply later updates to it.
• (Game)MatchUpdate — sent after the initial snapshot. Updates are applied to the cached snapshot.

The processing rules are the same across every sport. For brevity, the explanation below uses CS2; the same approach applies to Dota 2, eBasketball and the other games. See Match state processing in section 3.5.2.2.1.1 for more detail.

CS2MatchMessage (representative example of a (Game)MatchMessage)

Field Type Description
match_urn string Match the message refers to.
sequence uint64 Sequence number for ordering and gap detection.
timestamp google.protobuf.Timestamp Time the message was produced.
data_status DataStatus Quality flag for the underlying data (valid, disabled or corrupted).
payload CS2MatchMessage.Payload Oneof: either snapshot (CS2MatchSnapshot) or update (CS2MatchUpdate).
3.5.2.2.1. (Game)MatchSnapshot message

Each sport has its own snapshot type — for example, CS2MatchSnapshot. Because protocol buffers cannot express a common interface, the schema does not define a generic MatchSnapshot; we use that label only here.

A (Game)MatchSnapshot has exactly five properties. Four are common across all sports (match_urn, sequence, timestamp, announcements); the fifth, match_state, is sport-specific (for example, CS2MatchState).

The snapshot represents the full current state of a match. You receive it exactly once per match, and it is always the first (Game)MatchMessage you see for that match after connecting. Cache the snapshot in memory and apply later update messages (for example, CS2MatchMessage or AnnouncementUpdate) on top of it.

Property Description
match_urn Match identification.
sequence A positive integer used to confirm updates arrive in order. Every later update message carries a sequence value that must equal the cached sequence + 1. If it does not, something went wrong and the client should restart the stream. After applying an update, replace the cached sequence with the value from the update.
timestamp Tied to sequence: the timestamp of the most recent applied update. After applying an update, replace the cached timestamp with the value from the update. If you need to reconnect, send a new LiveDataFeedRequest with after set to the cached timestamp.
announcements Array of Announcement messages that inform the consumer about operational events during the match life — for example, a postponement or a server outage.
match_state Sport-specific current state of the match and its statistics. All future updates are applied to this field.

CS2MatchSnapshot (representative example of a (Game)MatchSnapshot)

Field Type Description
match_urn string Match identifier.
sequence uint64 Initial sequence number for this match.
timestamp google.protobuf.Timestamp Time of this snapshot.
data_status DataStatus Quality flag for the underlying data.
announcements repeated Announcement Operational announcements that apply to the match.
match_state CS2MatchState Full current state of the CS2 match.
tournament Tournament Tournament the match belongs to.
3.5.2.2.1.1. Match state processing

Match state represents the current state of a match and is cached in the match_state property of the (Game)MatchSnapshot. For simplicity, the rules below are described for CS2 (CS2MatchState), but they apply to every other sport in the same way.

Property type Description
sub-states States defined by a protobuf message whose name ends with the suffix State. We refer to these as sub-states (for example, CS2MatchScoreState). A sub-state may contain nested sub-states or protobuf maps where the key is a URN of the sub-state and the value is the sub-state itself (for example, CS2MapState has a map of CS2TeamMapState). These properties can be deeply nested. Sub-states represent groups of fields that change often during a match (for example, player position). To make partial updates simple, the server sends an idempotent update for each sub-state; you replace the cached sub-state with the version you receive.
scalar protobuf type Fields that change less often, or that already live inside another sub-state, are exposed directly as scalar protobuf types (see the protobuf scalar types documentation). The value is updated only when the enclosing state or sub-state is replaced. For example: map_order with type uint32.
scalar Properties that are protobuf messages but whose names do not end with State. These are treated as scalar properties (described above).

ℹ️ (Game)MatchState is effectively a sub-state of (Game)MatchSnapshot — clients should treat it the same way.

3.5.2.2.2. Updates

Updates are carried inside (Game)MatchMessage messages. The rules below are explained for CS2, but they apply to every other sport in the same way.

Bear in mind that the stream carries messages for many matches at once. We describe the update flow for a single match here, but in practice your client will maintain many match states and their cached snapshots (for example, CS2MatchSnapshot). The rules for applying updates are identical for each.

CS2MatchMessage is the parent of both the initial snapshot and every later update. It carries the sequence and timestamp fields (see (Game)MatchSnapshot for how to apply them to the cached state), a match_urn that identifies the match the update is for, and a oneof payload property with two variants:

Type Description
(Game)MatchSnapshot Cache this in memory when you receive it. You will receive it exactly once per match. To recover it later, you must restart the stream.
(Game)MatchUpdate Apply this to the match_state property of the cached snapshot.
3.5.2.2.2.1. (Game)MatchUpdate message

A (Game)MatchUpdate carries content that should be applied to the match_state property of the cached (Game)MatchSnapshot. The update arrives as the payload of a (Game)MatchMessage, which provides the sequence and timestamp fields. Once you have applied the update, replace the cached sequence and timestamp values with the ones from the (Game)MatchMessage.

⚠️ If any update is missing (the sequence number is not exactly one greater than the cached value), the client must recover the whole snapshot by restarting the connection.

A (Game)MatchUpdate contains two fields: payload and events.

Property Description
payload Oneof with two variants:
• (Game)MatchState — an idempotent message containing the entire match state. Replace the match_state field of the cached (Game)MatchSnapshot with this value.
• (Game)MatchStatePartialUpdates — a wrapper around an array of (Game)MatchStatePartialUpdate messages. See section 3.5.2.2.2.1.1 below.
events (deprecated) Array of zero or more (Game)Event messages that describe the history of what happened during the match (for example, Player 1 was killed by Player 2). (Game)Event messages are non-idempotent and are NOT applied to the match state. You can either ignore them or process them as you wish, but be aware that there is no way to recover missed events.
Note: events are deprecated; use the MatchEventsFeed described in section 4 instead.

ℹ️ For example, when the position of Player 1 changes, the client receives a CS2MatchUpdate with an empty events array and a payload of type CS2MatchStatePartialUpdates containing a single partial update that wraps a CS2PlayerPositionState. When Player 1 kills Player 2, the client receives a CS2MatchUpdate with two CS2Events (a CS2Kill and a CS2Death) and two partial updates that wrap CS2PlayerCurrentRoundStatisticsState, one for each player.

As described above, the payload of a (Game)MatchUpdate is always either a (Game)MatchState or a non-empty array of partial updates. The payload always carries information about a change to the match state. The events field, by contrast, can be empty.

CS2MatchUpdate (representative example)

Field Type Description
payload CS2MatchUpdate.Payload Oneof: match_state (a full CS2MatchState) or partial_updates (CS2MatchStatePartialUpdates).
events repeated CS2Event Deprecated. Use MatchEventsFeed.
3.5.2.2.2.1.1. (Game)MatchStatePartialUpdates message

(Game)MatchStatePartialUpdates wraps a non-empty array of idempotent updates to be applied to the match_state property (of type (Game)MatchState) inside (Game)MatchSnapshot. We call each item a partial update (for example, CS2MatchStatePartialUpdate). A partial update is a message containing a sub-state update (which replaces a specific cached sub-state) plus the set of URN properties that locate that sub-state. Note that a partial update can itself wrap another partial update (for example, CS2MatchStatePartialUpdate can wrap CS2CurrentMapStatePartialUpdate).

CS2MatchStatePartialUpdates

Field Type Description
updates repeated CS2MatchStatePartialUpdate Non-empty list of partial updates to apply, in order.
3.5.2.2.2.1.2. How to apply partial updates

A partial update is either a oneof protobuf message or a protobuf message with a payload field that is itself a oneof. Each partial update is a wrapper around some sub-state — which replaces a specific cached sub-state — and its URNs. A partial update can wrap another partial update, but the innermost level is always a sub-state.

Partial update message names start with the type they update and end with the suffix PartialUpdate (for example, CS2MatchStatePartialUpdate is applied to the CS2MatchState type). As noted above, a partial update is itself a oneof message, or it contains a nested Payload type that is a oneof. The name of the oneof field matches the name of the property being updated.

Here is a worked example. When the current round's score changes, the client receives a CS2MatchMessage carrying a CS2MatchUpdate with one CS2MatchStatePartialUpdate in the updates array. That partial update is of type CS2MatchScoreState. The fact that the type is CS2MatchScoreState tells you it can only replace CS2MatchScoreState properties, and its score field tells you exactly which property to overwrite.

Example JSON — partial update flow

// CS2MatchMessage carrying a CS2MatchUpdate with one partial update
{
"match_urn": "od:match:55501",
"sequence": 1024,
"timestamp": "2026-05-27T18:14:55.000Z",
"data_status": "DATA_STATUS_VALID_DATA",
"payload": {
"update": {
"payload": {
"partial_updates": {
"updates": [
{
"score": {
"home_score": 9,
"away_score": 6
}
}
]
}
}
}
}
}
3.5.3. MatchSnapshot and MatchState helper wrappers

The schema also defines two helper oneof messages that join all (Game)MatchSnapshot and (Game)MatchState types into a single union. These are convenient when you want a generic container; they are NOT required for maintaining or rebuilding match state, which always uses the game-specific types directly.

MatchSnapshot

Field Type Description
cs2 CS2MatchSnapshot Snapshot for a CS2 match.
dota2 Dota2MatchSnapshot Snapshot for a Dota 2 match.
lol LolMatchSnapshot Snapshot for a League of Legends match.
valorant ValorantMatchSnapshot Snapshot for a Valorant match.
rush_soccer RushSoccerMatchSnapshot Snapshot for an eFootball match.
rush_basketball RushBasketballMatchSnapshot Snapshot for an eBasketball match.
rush_cricket RushCricketMatchSnapshot Snapshot for an eCricket match.

MatchState

Field Type Description
cs2 CS2MatchState Match state for a CS2 match.
dota2 Dota2MatchState Match state for a Dota 2 match.
lol LolMatchState Match state for a League of Legends match.
valorant ValorantMatchState Match state for a Valorant match.
rush_soccer RushSoccerMatchState Match state for an eFootball match.
rush_basketball RushBasketballMatchState Match state for an eBasketball match.
rush_cricket RushCricketMatchState Match state for an eCricket match.
3.5.4. KeepAlive (deprecated)

KeepAlive was originally a heartbeat message sent periodically from the server. It has been replaced by the built-in gRPC keep-alive (see section 3.4.) and remains in the schema for backwards compatibility.

Field Type Description
timestamp google.protobuf.Timestamp Time at which the heartbeat was sent.
3.5.5. Common enumerations

The enums below are shared across many of the messages described elsewhere in the schema.

Sport

Value Description
SPORT_UNSPECIFIED Default value; never expected in practice.
SPORT_CS2 Counter-Strike 2.
SPORT_DOTA2 Dota 2.
SPORT_LOL League of Legends.
SPORT_VALORANT Valorant.
SPORT_RUSH_SOCCER eFootball.
SPORT_RUSH_BASKETBALL eBasketball.
SPORT_RUSH_CRICKET eCricket.

BestOfType

Value Description
BEST_OF_TYPE_UNSPECIFIED Default value.
BEST_OF_TYPE_BO1 Best of 1.
BEST_OF_TYPE_BO2 Best of 2.
BEST_OF_TYPE_BO3 Best of 3.
BEST_OF_TYPE_BO4 Best of 4.
BEST_OF_TYPE_BO5 Best of 5.
BEST_OF_TYPE_BO6 Best of 6.
BEST_OF_TYPE_BO7 Best of 7.

MatchStatusType

Value Description
MATCH_STATUS_TYPE_UNSPECIFIED Default value.
MATCH_STATUS_TYPE_NOT_STARTED Match has not yet started.
MATCH_STATUS_TYPE_LIVE Match is currently being played.
MATCH_STATUS_TYPE_FINISHED Match has ended.
MATCH_STATUS_TYPE_CANCELED Match has been cancelled.
MATCH_STATUS_TYPE_PLACEHOLDER Placeholder entry; the match exists in our system but its participants are not yet confirmed.

DataStatus

Value Description
DATA_STATUS_UNSPECIFIED Default value.
DATA_STATUS_DISABLED_DATA The underlying data source has been disabled.
DATA_STATUS_CORRUPTED_DATA The data is known to be incorrect; treat it with caution.
DATA_STATUS_VALID_DATA The data is healthy and can be trusted.

3.6. Player URN format variants

A Player URN is the unique identifier of an individual player (for example, the player_urn property of CS2PlayerMapState) inside the match state. It is central to maintaining a correct match state. The URN is a string made up of three parts separated by colons. The parts and the three URN variants are described below.

  1. The first part is always the literal string "od", which is the Oddin.gg system prefix.
  2. The second part identifies which variant of the URN you have:
Variant Second part Description
Internal ID player Unique identifier of a player who exists in the Oddin.gg database and therefore has an internal ID.
External ID player-ext Unique identifier of a player who has no internal ID assigned, but whose external ID is known from a data source (for example, a Steam ID).
Slot ID player-slot A globally non-unique identifier for a player who has no internal ID and no known external ID. Within a single match, each player has a unique slot ID (for example, 1–10 for CS2), but the same slot ID may refer to a different player in another match.
  1. The third part is the player-specific identifier, formatted as follows:
Variant Third part format Example
Internal ID number 7811
External ID arbitrary string 76561197960287930, "<arbitrary-string>", UUID, etc.
Slot ID slot number 1

Examples of possible player URN variants

Variant Example
Internal ID od:player:7811
External ID od:player-ext:76561197960287930
Slot ID od:player-slot:1

4. Match events

In addition to LiveDataFeed, we provide a separate MatchEventsFeed endpoint that streams real-time game events for currently played matches.

4.1. Consuming the feed

To open the match-events stream, the client calls the MatchEventsFeed RPC and sends a MatchEventsFeedRequest.

Once connected, the server begins streaming MatchEventsFeedMessage frames for each active match. The first message for a match is a snapshot of all previous events; later messages each carry a single new event as it happens.

MatchEventsFeedRequest

Field Type Description
(no fields) — The request takes no parameters.

4.2. MatchEventsFeedMessage

MatchEventsFeedMessage is the wrapping envelope for every match event frame. The payload is a oneof.

Field Type Description
cs2 CS2MatchEvents An array of CS2 events for a particular match.
4.2.1. CS2MatchEvents

The first frame for a match contains a snapshot of every historical event for that match. Every later frame carries a single new event in real time.

Property Type Description
match_urn string Identifies the match.
events repeated CS2Event List of events. On the initial frame this contains the full history; on later frames it contains a single new event.
4.2.1.1. CS2Event

A CS2Event records what happened (its event payload), when it happened (its timestamp), and which map it relates to (its map_id).

Property Type Description
timestamp google.protobuf.Timestamp When the event was triggered.
map_id uint64 Identifies the map within the match.
event oneof (see event types table) One of the CS2 event payload types. See the next section for the supported list.
4.2.1.2. CS2 event types

Only the events listed below are produced for CS2 matches today. The list will grow as we support more event types.

Event Message type Example
map_start CS2MapStart Map {X} started
map_end CS2MapEnd Map {X} ended — Winner: Team A ({X:X})
round_start CS2RoundStart Round {X} started
round_end CS2RoundEnd Round {X} ended (elimination) — Winner: Team B
round_pause CS2RoundPause Round {X} paused
round_resume CS2RoundResume Round {X} resumed
round_rollback CS2RoundRollback Round {X} rolled back; next round is {Y}
world_bomb CS2WorldBomb The bomb exploded
bomb_planted CS2BombPlanted Player A has planted the bomb
bomb_plant_started CS2BombPlantStarted Player A has started planting the bomb
bomb_defuse_started CS2BombDefuseStarted Player B has started defusing the bomb
bomb_defused CS2BombDefused Player B has defused the bomb
bomb_exploded CS2BombExploded The bomb has exploded
kill CS2Kill Player A killed Player B
death CS2Death Player A was killed
damage_dealt CS2DamageDealt Player A dealt damage to Player B
freeze_time_started CS2FreezeTimeStarted Freeze time started
freeze_time_ended CS2FreezeTimeEnded Freeze time ended
item_drop CS2ItemDrop Player A dropped item
item_pick_up CS2ItemPickUp Player A picked up item
item_purchase CS2ItemPurchase Player A bought item
item_throw CS2ItemThrow Player A threw Smoke Grenade

Example JSON — CS2MatchEvents (initial frame, then a real-time update)

// Initial frame: snapshot of historical events
{
"cs2": {
"match_urn": "od:match:55501",
"events": [
{
"timestamp": "2026-05-27T18:00:05.000Z",
"map_id": 1,
"map_start": { "map_name": "de_mirage" }
},
{
"timestamp": "2026-05-27T18:00:20.000Z",
"map_id": 1,
"round_start": {
"time_remaining": "115s",
"current_round_number": 1
}
}
]
}
}

// Real-time frame: a single new event
{
"cs2": {
"match_urn": "od:match:55501",
"events": [
{
"timestamp": "2026-05-27T18:02:42.500Z",
"map_id": 1,
"kill": {
"time_remaining": "67s",
"current_round_number": 3,
"killer_position": { "x": 102.3, "y": -45.8, "z": 12.1, "angle": 87.0 },
"killer_urn": "od:player:7811",
"killer_team_urn": "od:team:101",
"victim_urn": "od:player-ext:76561197960287930",
"victim_team_urn": "od:team:202",
"weapon": "ak47",
"headshot": true,
"penetrated": false,
"assistants": []
}
}
]
}
}

5. Team profile

The TeamProfile RPC returns full, up-to-date information for a team identified by its URN. The response includes team metadata, external identifiers, every player on file for the team, and the players currently set as the map roster. It is a unary (request/response) call.

5.1. TeamProfileRequest

Field Type Description
team_urn string Unique identifier of the team, for example od:competitor:12345.

5.2. TeamProfileResponse

Field Type Description
team TeamProfile The team's profile.
5.3.1. TeamProfile

Full profile for a team.

Field Type Description
urn string Unique team identifier, for example od:competitor:12345.
name string Team display name.
icon_path string (optional) Path to the team's icon image.
external_identities map<string, ExternalIdentityList> Key-value pairs mapping external identity providers to their corresponding team identifiers. For example: {"LIQUIPEDIA": ["456", "789"]}.
players repeated PlayerProfile Every player known to be associated with the team.
current_map_roster repeated PlayerProfile Players currently in the team's active roster for the current map.
5.3.1.1. PlayerProfile

Profile for an individual player.

Field Type Description
urn string Unique player identifier, for example od:player:123.
nickname string Player's in-game nickname.
real_name string (optional) Player's real name.
shortcut string (optional) Short abbreviation for the player.
icon_path string (optional) Path to the player's icon image.
age uint32 (optional) Player's age.
external_identities map<string, ExternalIdentityList> Key-value pairs mapping external identity providers to their corresponding player identifiers. For example: {"LIQUIPEDIA": ["456", "789"]}.
5.3.1.1.1. ExternalIdentityList

Wrapper for the list of external identifiers associated with a single provider.

Field Type Description
ids repeated string List of identifiers for the provider.

Example JSON — TeamProfileRequest and TeamProfileResponse

// TeamProfileRequest
{
"team_urn": "od:competitor:12345"
}

// TeamProfileResponse
{
"team": {
"urn": "od:competitor:12345",
"name": "Team Alpha",
"icon_path": "icons/team_alpha.png",
"external_identities": {
"LIQUIPEDIA": { "ids": ["456", "789"] },
"STEAM": { "ids": ["76561198000000001"] }
},
"players": [
{
"urn": "od:player:7811",
"nickname": "AlphaStar",
"real_name": "Alex Smith",
"shortcut": "AST",
"icon_path": "icons/player_7811.png",
"age": 22,
"external_identities": {
"LIQUIPEDIA": { "ids": ["101"] }
}
}
],
"current_map_roster": [
{
"urn": "od:player:7811",
"nickname": "AlphaStar"
}
]
}
}

6. Game-specific schemas

Every game has its own message and state schema. Each is documented in its own article:

7. Content updates

This section lists changes to the documentation and the underlying schema, newest first.

[v0.2.30] - 2026-05-29

  • Added SPORT_CS2_DUELS to Sport enum.
  • Added extended tables and JSON examples to the documentation.

[v0.2.29] - 2026-05-29

  • Added SPORT_RUSH_CRICKET to Sport enum.

[v0.2.28] - 2026-05-20

  • Added optional roshan_kills field to Dota 2 team map state.

[v0.2.27] - 2026-05-07

  • Reverted the Roshans' logic.

[v0.2.26] - 2026-05-04

  • Added organizer info into the Bragi API.

[v0.2.25] - 2026-05-01

  • Added active_data_source_type to MatchMessage.

[v0.2.24] - 2026-04-08

  • Added Roshans’ logic.

[v0.2.23] - 2026-03-12

  • Added multiple external identity sources on the team profile.

[v0.2.22] - 2026-02-27

  • Added team profile.

[v0.2.21] - 2026-02-25

  • Added player external ID to Live Data Feed.

[v0.2.20] - 2026-02-12

  • Added BallPossession field to Rush Basketball map state and partial updates.

[v0.2.19] - 2025-12-09

  • Added start_date field to tournaments.

[v0.2.18] - 2025-11-20

  • Added Match timeline filtering by team name.

[v0.2.17] - 2025-11-20

  • Added Match timeline filtering.

[v0.2.16] - 2025-08-19

  • Undeprecated PicksAndBansSelections. The schema now guarantees correct sequencing of picks and bans regardless of connection time and independent of any disruptions in data collection.

[v0.2.15] - 2025-06-05

  • Added tournament online/offline flag on LiveDataFeed, MatchTimeline and MatchTimelineFeed.

[v0.2.14] - 2025-05-23

  • Live eCricket support.

[v0.2.13] - 2025-04-09

  • Added MatchEventsFeed to stream real-time match events. Currently only CS2 is supported.

[v0.2.12] - 2025-04-04

  • Added the representation of picks and bans per team.
  • Deprecated the previous picks and bans implementation.

[v0.2.11] - 2025-03-27

  • Added the parameters timestamp and map_id for CSEvents.
  • Added a separate CS2WorldBomb.

[v0.2.10] - 2025-03-06

  • Undeprecated CS2 events.
  • Added a few attributes.

[v0.2.9] - 2025-01-22

  • Added the Roshan position on the minimap.

[v0.2.7] - 2025-01-22

  • Added Dota 2 picks and bans ended boolean.

[v0.2.5] - 2024-12-16

  • Dota 2 picks and bans were added to Dota2MatchSnapshot and Dota2MatchUpdate, in both the match state and the partial updates, as shown in the protobuf schema.