Build a racing "next to go" dashboard in Python (free Australian racing API)
Australian racing runs almost non-stop — thoroughbreds, greyhounds and harness across dozens of meetings a day. The core view every racing product needs is "next to go": the upcoming races in jump-time order, with runners and live prices. In this tutorial we'll build exactly that in Python using the free PuntersEdge AU Odds API.
⚠️ 18+ only. This is racing *data* tooling, not tipping or a betting service. Racing moves fast — confirm prices live before acting. Not financial advice. 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
from datetime import datetime, timezone
BASE = "https://api.puntersedge.online/v1"
HEADERS = {"X-API-Key": "YOUR_FREE_KEY"}
Step 1 — pull the next races
/v1/racing/next-to-go returns upcoming races (horse + greyhound) in start-time order, each with its runners and per-bookmaker win/place prices:
def next_to_go():
r = requests.get(f"{BASE}/racing/next-to-go", headers=HEADERS, timeout=15)
r.raise_for_status()
return r.json()
for race in next_to_go()[:5]:
jump = datetime.fromisoformat(race["start_time"].replace("Z", "+00:00"))
mins = (jump - datetime.now(timezone.utc)).total_seconds() / 60
print(f"{race['venue']} R{race['race_number']} ({race['category']}) "
f"— jumps in {mins:.0f} min, {len(race['runners'])} runners")
Step 2 — best win price per runner
Each runner carries a bookmakers list; collapse it to the best available win price:
def best_win(runner):
prices = [b["win_price"] for b in runner["bookmakers"] if b.get("win_price")]
if not prices:
return None, None
best = max(prices)
book = next(b["key"] for b in runner["bookmakers"] if b.get("win_price") == best)
return best, book
race = next_to_go()[0]
print(f"{race['venue']} R{race['race_number']}")
for r in sorted(race["runners"], key=lambda x: (best_win(x)[0] or 9e9)):
price, book = best_win(r)
if price:
print(f" {r['number']:>2}. {r['name']:<22} {price:>5} @ {book}")
Sorting by price gives you the market order — favourites first — which is exactly how a next-to-go board reads.
Step 3 — a refreshing dashboard loop
Wrap it in a loop that reprints the next few jumps every 30 seconds:
import time
def board(n=4):
for race in next_to_go()[:n]:
jump = datetime.fromisoformat(race["start_time"].replace("Z", "+00:00"))
mins = (jump - datetime.now(timezone.utc)).total_seconds() / 60
fav = min(race["runners"], key=lambda x: best_win(x)[0] or 9e9)
fp, fb = best_win(fav)
print(f"{mins:4.0f}m {race['venue']:<16} R{race['race_number']:<2} "
f"{race['category']:<9} fav: {fav['name']} {fp} ({fb})")
while True: # Ctrl-C to stop
print("\n=== NEXT TO GO ===")
board()
time.sleep(30)
That's a live racing board: venue, race number, code, time to jump and the favourite's best price — refreshing on its own.
Wrap up
From here you can split horse vs greyhound (category), show place prices, add a per-runner price-comparison row, or push a notification when a runner's best price crosses a threshold.
- Free key + docs: https://puntersedge.online/api-platform
- Also on RapidAPI: https://rapidapi.com/Propertyscout001/api/puntersedge-au-odds
- Endpoint:
/v1/racing/next-to-go
(18+, gamble responsibly, Gambling Help 1800 858 858.)