Betradar UOF HTTP API

CIPackage Versionhexdocs.pm

Important

This is an unofficial client for Betradar's Unified Odds Feed (UOF) HTTP API. Betradar offers official Java and .NET SDKs. You can read more about these here.

Elixir client for Betradar's Unified Odds Feed (UOF) HTTP API.

It covers the documented HTTP API surface across these modules:

ModuleAPI
UOF.API.SportsSchedules and fixtures, fixture/result changes, summaries, timelines, sports, tournaments, seasons, categories, and player/competitor/venue profiles
UOF.API.DescriptionsBetting descriptions: markets, variants, producers, match/betting statuses, betstop/void reasons
UOF.API.ProbabilitySport-event probabilities (cashout)
UOF.API.CustomBetAvailable selections and odds/probability calculation
UOF.API.RecoveryOdds and stateful-message recovery
UOF.API.BookingBooking events for live odds
UOF.API.UsersToken / bookmaker information

Responses are parsed into Ecto embedded schemas from the uof_schemas package.

Get Started

Configuration

To be able to interact with Betradar's API, you first need to configure a valid authentication token and the base url of the Betradar environment you want to use.

:ok = Application.put_env(:uof_api, :base_url, "<betradar-uof-base-url>")
:ok = Application.put_env(:uof_api, :auth_token, "<betradar-uof-auth-token>")

Usage

Stream all available fixtures. Pagination over the prematch schedule is handled for you, and pages are fetched lazily so the stream composes with Stream/Enum and supports early termination.

UOF.API.Sports.Fixtures.stream()
|> Enum.count()
# => 51591

Compose Stream operations to narrow the catalogue down without loading it all into memory — for example, all events currently bookable for live odds:

UOF.API.Sports.Fixtures.stream()
|> Stream.filter(&(&1.liveodds == "bookable"))
|> Enum.to_list()

Aggregating over the streamed events works as you would expect:

UOF.API.Sports.Fixtures.stream()
|> Stream.map(& &1.tournament.sport.name)
|> Enum.uniq()
# => ["Soccer", "Handball", "Basketball", ...]

Fetch the details of a single fixture:

{:ok, %{fixture: fixture}} = UOF.API.Sports.fixture("sr:match:8696826")
# =>
# %UOF.Schemas.API.Sports.Fixture{
# id: "sr:match:8696826",
# status: "closed",
# liveodds: "not_available",
# scheduled: ~U[2016-10-31 18:00:00Z],
# tournament: %UOF.Schemas.API.Sports.Tournament{
# name: "Ettan, Sodra",
# sport: %UOF.Schemas.API.Sports.Sport{name: "Soccer", ...},
# ...
# },
# season: %UOF.Schemas.API.Sports.SeasonExtended{
# name: "Div 1, Sodra 2016",
# start_date: ~D[2016-04-16],
# ...
# },
# competitors: %UOF.Schemas.API.Sports.SportEventCompetitors{
# competitor: [
# %UOF.Schemas.API.Sports.TeamCompetitor{id: "sr:competitor:1860", name: "IK Oddevold", qualifier: "home", ...},
# %UOF.Schemas.API.Sports.TeamCompetitor{id: "sr:competitor:22356", name: "Tvaakers IF", qualifier: "away", ...}
# ]
# },
# ...
# }

Fetch an entity profile (note the faithful nesting — jerseys.jersey, players.player):

{:ok, profile} = UOF.API.Sports.competitor("sr:competitor:2672")
# =>
# %UOF.Schemas.API.Sports.CompetitorProfileEndpoint{
# competitor: %UOF.Schemas.API.Sports.TeamExtended{name: "Bayern Munich", ...},
# venue: %UOF.Schemas.API.Sports.Venue{name: "Allianz Arena", capacity: 75000, ...},
# jerseys: %UOF.Schemas.API.Sports.Jerseys{jersey: [...]}, # 4
# players: %UOF.Schemas.API.Sports.Players{player: [...]}, # 32
# ...
# }

Betting descriptions:

{:ok, %{market: markets}} = UOF.API.Descriptions.markets()
{:ok, %{producer: producers}} = UOF.API.Descriptions.producers()

Custom bet lets you combine markets across fixtures into a single accumulator. First list the markets available for a fixture:

{:ok, available} = UOF.API.CustomBet.available_selections("sr:match:42795059")
market = hd(available.markets)
outcome = hd(market.outcomes)
# a selection is a {fixture_id, market_id, outcome_id} tuple
{"sr:match:42795059", market.id, outcome.id}

Then calculate the combined odds and probability for a list of selections:

{:ok, calculation} = UOF.API.CustomBet.calculate([
{"sr:match:42795059", 97, 74},
{"sr:match:42795059", 10, 9}
])
# calculation.calculation.odds => #Decimal<5.22>
# calculation.calculation.probability => #Decimal<0.15>

Pass true as the second argument to calculate/2 to also get back the further markets that can still be added to the bet.

Probabilities (cashout):

{:ok, cashout} = UOF.API.Probability.probabilities("sr:match:41878167")

Booking. There are no booking-calendar GET endpoints; booking state is read from a schedule via the liveodds attribute:

{:ok, _ack} = UOF.API.Booking.book("sr:match:12345")
{:ok, schedule} = UOF.API.Sports.schedule("2024-12-01")
UOF.API.Sports.Fixtures.bookable(schedule)
# also: booked/1, buyable/1, with_liveodds/2

Odds recovery (the recovered messages arrive over the AMQP feed; the HTTP call returns an acknowledgement):

{:ok, _ack} = UOF.API.Recovery.recover("liveodds", request_id: 1, after: 1_700_000_000_000)
{:ok, _ack} = UOF.API.Recovery.recover_event("liveodds", "sr:match:12345", request_id: 2)

Contributing

This project uses Conventional Commits.

The list of supported commit types can be found here.