18+ Only  |  Gambling can be addictive — please gamble responsibly  |  Gambling Help: 1800 858 858  |  GambleAware

Build a live odds comparison tool in Python (free Australian odds API)

An odds comparison tool answers one question for every selection: which bookmaker is paying the most? Across Australia's books — Sportsbet, TAB, Neds, Ladbrokes, Unibet, PointsBet and Betfair — the best price can vary by 10%+, and that gap (the "overlay") is the entire edge in price-driven betting.

In this tutorial we'll build a best-price comparison in Python using the free PuntersEdge AU Odds API. No scraping, no maintaining a connector per bookmaker.

⚠️ 18+ only. This is market-data tooling, not a betting service or financial advice. Bet only what you can afford to lose. Gambling Help: 1800 858 858.

Get a free key

Free key at puntersedge.online/api-platform (1,500 credits/month, no card), passed in X-API-Key.

import requests

BASE = "https://api.puntersedge.online/v1"
HEADERS = {"X-API-Key": "YOUR_FREE_KEY"}

Step 1 — best price per selection

/v1/best-odds/{sport} already collapses every bookmaker to the best price per selection, and includes all_prices so you can show the full row:

def best_odds(sport):
    r = requests.get(f"{BASE}/best-odds/{sport}", headers=HEADERS, timeout=15)
    r.raise_for_status()
    return r.json()

for ev in best_odds("afl"):
    print(f"\n{ev['home_team']} v {ev['away_team']}")
    for s in ev["selections"]:
        print(f"  {s['name']:<22} best {s['best_price']} @ {s['best_bookmaker']}")

Step 2 — render a comparison table

Pivot each selection's all_prices into a per-bookmaker grid, highlighting the best:

def table(event):
    books = sorted({p["bookmaker"] for s in event["selections"] for p in s["all_prices"]})
    print(f"{'Selection':<22}" + "".join(f"{b[:10]:>11}" for b in books))
    for s in event["selections"]:
        prices = {p["bookmaker"]: p["price"] for p in s["all_prices"]}
        row = ""
        for b in books:
            v = prices.get(b)
            cell = f"{v}{'*' if v == s['best_price'] else ' '}" if v else "-"
            row += f"{cell:>11}"
        print(f"{s['name']:<22}{row}")

table(best_odds("afl")[0])   # * marks the best price

Step 3 — measure the overlay (where the edge is)

/v1/arb/best-prices adds worst_price, avg_price, price_spread and overlay_pct per selection — the overlay is how far the best price sits above the market average, i.e. how much value the comparison is surfacing:

ev = requests.get(f"{BASE}/arb/best-prices", headers=HEADERS, timeout=15).json()[0]
print(f"{ev['home_team']} v {ev['away_team']}")
for s in ev["selections"]:
    print(f"  {s['name']:<22} best {s['best_price']} "
          f"(avg {s['avg_price']}, +{s['overlay_pct']}% overlay, spread {s['price_spread']})")

Sort selections by overlay_pct and you've got a value board: the biggest gaps between the best and average price across the market.

Wrap up

That's a working odds comparison: best price per selection, a full per-book table, and an overlay metric to rank where the value is. Drop it behind a web framework and you've got a comparison site; poll it and alert on a target overlay.

(18+, gamble responsibly, Gambling Help 1800 858 858.)

Get a free API key →

This site contains wagering-related analysis and is intended for Australian users aged 18+. Gambling involves risk. Please gamble responsibly.