Use case: odds comparison
Odds comparison API for Australian bookmakers
Show punters the best price on a game across every Australian book, and how fresh each price is. One request per league gives you all of it.
The recipe
From response to price table
- Request a league, filtered to the markets you display with
markets. - Group every bookmaker's outcomes by outcome ID: the same outcome has the same ID at every book.
- Sort each group by
decimal_oddsand mark the top one. - Hide quotes where
availableis false. - Show each price's age from
observed_at, such as "seen 2 min ago". - Put Pinnacle or the Betfair Exchange beside the best price, so a reader can see how far it sits from the sharpest view.
Why it is less work here
One market, one shape, every book
Comparison sites usually spend their effort on matching: is "Sydney Swans v Collingwood" at one book the same game as "Sydney vs Collingwood Magpies" at another, and is their "Line" the same market as someone else's "Handicap"? In this feed that matching is already done. Each game has one event ID, and each outcome one ID shared by every bookmaker, so lining the books up is a lookup.
Lines and totals are matched too. Each number is its own market, so two books share an outcome ID only when they hang the same line, and a table never ranks a price at 40.5 against one at 44.5.
Code
A best-price table in Python
import os
import requests
resp = requests.get(
"https://api.sockodds.com/v1/odds",
params={"league": "afl", "markets": "winner"},
headers={"Authorization": f"Bearer {os.environ['SOCKODDS_KEY']}"},
timeout=20,
)
resp.raise_for_status()
for event in resp.json()["data"]:
print(event["name"])
# Every book's price per outcome: an outcome has one ID at every book.
table = {} # outcome ID -> (outcome name, [(price, bookmaker)])
for book in event["bookmakers"]:
for market in book["markets"]:
if market["period"] != "full":
continue
for o in market["outcomes"]:
if o.get("available"):
table.setdefault(o["id"], (o["name"], []))[1].append((o["decimal_odds"], book["name"]))
for name, quotes in table.values():
quotes.sort(reverse=True)
price, book = quotes[0]
print(f" {name}: best {price} at {book}")
print(f" then {', '.join(f'{p} {b}' for p, b in quotes[1:4])}")
Publishing prices
If your table faces the public
Keep the API key on your server and serve visitors from your own cache or database, refreshed every few minutes. That also means a traffic spike on your site never becomes a spike in API calls.
If you publish prices to punters in Australia, wagering advertising rules and responsible gambling messaging may apply to you, particularly if you earn from bookmaker affiliate links. Check your obligations before launch.
Which plan? A comparison that only covers the big three books on the AFL, NRL, NFL and MLB can start free. Showing the books punters expect, bet365, Neds, PointsBet, Unibet and Betfair among them, needs Rookie. Covering the whole Australian market needs Pro. Size your usage
Questions
Comparison builds
Can I compare props and alternate lines, not just head to head?
Yes. Player props, team props and alternate lines come in the same response, in the same bookmakers, markets and outcomes layout. Grouping by outcome ID keeps each number apart, since books hang different lines.
Which price formats are included?
Every quote has decimal_odds and its implied_probability. Australian readers expect decimal; if you want American or fractional too, the converter shows the arithmetic.
How fresh will my table be?
Each book is re-read about every five minutes. With your own refresh every five minutes or so on top, a reader typically sees prices five to ten minutes old, and the timestamp lets you say so on the page.
Start now
Your first Australian price is one request away.
Free key, no card, AFL and NRL included. Keys are issued on sockodds.com.