Skip to content

efcasado/uof_api

Repository files navigation

Betradar's Unified Odds Feed (UOF) HTTP API

CI Package Version hexdocs.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:

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 under UOF.API.Schemas.*, generated from Betradar's official XSDs (see Regenerating the schemas). The structs mirror the XSD nesting faithfully, so lists are wrapped (e.g. competitors.competitor) and field types follow the XSD (dates/datetimes are cast, odds/probabilities are Decimal, and some feed values such as scores are strings).

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.API.Schemas.Sports.Fixture{
#   id: "sr:match:8696826",
#   status: "closed",
#   liveodds: "not_available",
#   scheduled: ~U[2016-10-31 18:00:00Z],
#   tournament: %UOF.API.Schemas.Sports.Tournament{
#     name: "Ettan, Sodra",
#     sport: %UOF.API.Schemas.Sports.Sport{name: "Soccer", ...},
#     ...
#   },
#   season: %UOF.API.Schemas.Sports.SeasonExtended{
#     name: "Div 1, Sodra 2016",
#     start_date: ~D[2016-04-16],
#     ...
#   },
#   competitors: %UOF.API.Schemas.Sports.SportEventCompetitors{
#     competitor: [
#       %UOF.API.Schemas.Sports.TeamCompetitor{id: "sr:competitor:1860", name: "IK Oddevold", qualifier: "home", ...},
#       %UOF.API.Schemas.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.API.Schemas.Sports.CompetitorProfileEndpoint{
#   competitor: %UOF.API.Schemas.Sports.TeamExtended{name: "Bayern Munich", ...},
#   venue:   %UOF.API.Schemas.Sports.Venue{name: "Allianz Arena", capacity: 75000, ...},
#   jerseys: %UOF.API.Schemas.Sports.Jerseys{jersey: [...]},   # 4
#   players: %UOF.API.Schemas.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)

Regenerating the schemas

The Ecto schemas under lib/uof/api/schemas/ are generated from Betradar's official XSDs, taken from the Unified Odds SDK for .NET and pinned to a single release tag for reproducibility. The exact tag lives in @sdk_tag in Mix.UOF.XSD.Sources (the single source of truth); mix uof.xsd.fetch prints it.

The XSDs are downloaded on demand into the git-ignored priv/xsd/ cache; they are never vendored into the repo:

mix uof.xsd.fetch     # download the XSDs
mix uof.gen.schemas   # generate the schemas

To move to a newer SDK release, bump @sdk_tag there and re-run mix uof.gen.schemas.

Contributing

This project uses Conventional Commits.

The list of supported commit types can be found here.

About

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

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors