Betradar UOF HTTP API
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:
| Module | API |
|---|---|
UOF.API.Sports | Schedules and fixtures, fixture/result changes, summaries, timelines, sports, tournaments, seasons, categories, and player/competitor/venue profiles |
UOF.API.Descriptions | Betting descriptions: markets, variants, producers, match/betting statuses, betstop/void reasons |
UOF.API.Probability | Sport-event probabilities (cashout) |
UOF.API.CustomBet | Available selections and odds/probability calculation |
UOF.API.Recovery | Odds and stateful-message recovery |
UOF.API.Booking | Booking events for live odds |
UOF.API.Users | Token / 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.