Scheduled Sports Feeds Integration¶
Abstraction of Leagues and Tournaments¶
First off, it is important to note that we’re abstracting away the difference between Leagues and Tournaments by claiming that a League is a tournament with 1 big group, and no knockout stages. Such an abstraction prevents the integration team from re-implementing the importers twice, once for leagues and once for tournaments.
As an example:
- Euro 2024 is a tournament that has 24 teams, 6 Groups, 4 Knockout rounds.
- English Premier league is a leauge that has 20 teams, 1 Group, no Knockout rounds.
Chronology of events¶
There are 5 noteworthy events for rounds and 4 for seasons:
- Rounds:
- Pending: This status can only happen for tournament's knockout stages. Essentially, these are rounds that we know are going to happen but whose fixtures have not yet been established.
- Created: Happens when rounds get created. For leagues, this happens ahead of time. For tournament’s group stage rounds, this happens ahead of time as well. However, for tournament’s knockout rounds, this is deferred to after the group stage is done.
- Resulted: The happens BEFORE the round starts to give time to the operator to import the result and start settling. Optionally, this can be set to occur with the start of the event instead.
- Started: This is the time at which the matches start.
- Finished: This is the time at which the matches end.
- Seasons:
- Created: Happens when a new season is generated.
- Started: Happens when the season starts. Please note that the start time of a season coincides the start time of the first round of that season.
- Resulted: Happens as soon as all the rounds have been successfully resulted.
- Finished: Happens at the end of the season.
NOTE: At the time of writing, we're not offering Outright markets, mainly because we recommend Outright markets to be done in conjunction with cashouts and live odds. In the following examples we will assume that we're focusing mainly on classic fixture markets.
The following diagram depicts the typical lifecycle of a league's season:
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'timeline': {'disableMulticolor': true}}}%%
timeline
title Round Lifetime
section Round 1
0s : Preamble 1 starts (90secs)
85s : Round 1 Resulting
90s : Round 1 Start (30secs) : Season Start
120s : Round 1 Finish
section Round 2 - 37
section Round 38
0s : Preamble 2 starts (90secs)
85s : Round 2 Resulting
90s : Round 2 Start (30secs)
120s : Round 2 Finish : Season Finish
Since we’re doing Virtual games, we can result BEFORE the round starts. We do this to allow the operator to start settling before the fixtures starts and the player find their winnings as soon as the round ends. However, it is the responsibility of the operator to make sure that any results imported to the system are not exposed to the players, as this could allow the players to understand the result ahead of time.
Additionally, we recommend the integration team should be importing a few seasons ahead of time. This will assure that players have rounds to play on even in the event of the importer failing. Please note that in case of a failed importer, results wouldn't be imported anyway which severely harms the overall experience. Therefore, any importer failures on the operator side should be tackled immediately.
Pseudocode for Tournament / League¶
MainLoop()
{
loop through every competition by using the '/competitions/' API
{
ImportFutureRounds(competitionId);
ImportPendingRounds(competitionId);
ImportRoundResults(competitionId);
ImportStandingsAndStatsForFinishedRounds(competitionId);
}
}
ImportFutureRounds(competitionId)
{
Check If we have enough rounds in the system for the input $competitionId
If yes return;
// Arbitrarily chosen 10 rounds.
$numberOfRoundsAheadOfTime = 10;
If no round has ever been imported call the api to get the rounds:
'/rounds?competition=$competitionId&nextCount=$numberOfRoundsAheadOfTime'
Else if have rounds already in the system:
// Please note that this will prevent the api from re-importing rounds. We only get rounds after
// a specified round id.
$roundsToImport = $numberOfRoundsAheadOfTime - $roundsInSystem
/rounds?competition=$competitionId&nextCount=$roundsToImport&afterRoundId=$lastRoundId
For each imported round:
- Take the value of "StartTimeUtc", and queue an action to call ImportFutureRounds() whenever a round starts.
- Take the value of "ResultsAvailableAtTimeUtc" and call ImportRoundResult(roundId). Please note that you should only do this in case the value is in the future (i.e. for knockout rounds that are not yet available)
- Take the value of "FixturesAvailableAtTimeUtc" and call ImportPendingRounds(roundId)
- Take the value of "EndTimeUtc" and call ImportStandingsAndStatsForFinishedRound(roundId)
}
// This method is needed only for tournaments.
ImportPendingRound(roundId)
{
Call the '/round/$roundId' API to get the latest changes. At this point, you should have the fixtures available.
}
ImportRoundResults(roundId)
{
Call the '/round/$roundId' API to get the latest round changes. At this point you should find:
- Playout information
- Fixture Result
- Market / Selection Winning Outcomes.
}
ImportStandingsAndStatsForFinishedRound(roundId)
{
Import the round's statistics using the api:
/round/$roundId/statistics
Import the season's group standing using the api:
/season/$seasonId
}