Get a free key

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

  1. Request a league, filtered to the markets you display with markets.
  2. Group every bookmaker's outcomes by outcome ID: the same outcome has the same ID at every book.
  3. Sort each group by decimal_odds and mark the top one.
  4. Hide quotes where available is false.
  5. Show each price's age from observed_at, such as "seen 2 min ago".
  6. 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

best_prices.py
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.