Working code samples for every endpoint. Replace YOUR_API_KEY with your key.
Returns all sports with active odds coverage. Cost: 1 credit.
curl https://api.puntersedge.online/v1/sports \ -H "X-API-Key: YOUR_API_KEY"
import requests
r = requests.get(
"https://api.puntersedge.online/v1/sports",
headers={"X-API-Key": "YOUR_API_KEY"}
)
print(r.json())const res = await fetch("https://api.puntersedge.online/v1/sports", {
headers: { "X-API-Key": "YOUR_API_KEY" }
});
const data = await res.json();
console.log(data);[
{"key": "afl", "title": "AFL", "group": "Australian Rules", "active": true},
{"key": "nrl", "title": "NRL", "group": "Rugby League", "active": true},
{"key": "nba", "title": "NBA", "group": "Basketball", "active": true}
]Returns upcoming NRL matches with h2h prices from all bookmakers. Cost: 1 credit.
curl "https://api.puntersedge.online/v1/sports/nrl/odds?markets=h2h" \ -H "X-API-Key: YOUR_API_KEY"
r = requests.get(
"https://api.puntersedge.online/v1/sports/nrl/odds",
params={"markets": "h2h"},
headers={"X-API-Key": "YOUR_API_KEY"}
)
print(r.json())const res = await fetch(
"https://api.puntersedge.online/v1/sports/nrl/odds?markets=h2h",
{ headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();[
{
"id": "abc123",
"sport_key": "nrl",
"sport_title": "NRL",
"home_team": "Melbourne Storm",
"away_team": "Penrith Panthers",
"commence_time": "2026-06-07T09:50:00Z",
"bookmakers": [
{
"key": "sportsbet",
"title": "Sportsbet",
"markets": [
{
"key": "h2h",
"outcomes": [
{"name": "Melbourne Storm", "price": 1.85},
{"name": "Penrith Panthers", "price": 1.95}
]
}
]
}
]
}
]Get h2h and line (spreads) in one call. Cost: 2 credits (1 per market type).
curl "https://api.puntersedge.online/v1/sports/afl/odds?markets=h2h,spreads" \ -H "X-API-Key: YOUR_API_KEY"
r = requests.get(
"https://api.puntersedge.online/v1/sports/afl/odds",
params={"markets": "h2h,spreads"},
headers={"X-API-Key": "YOUR_API_KEY"}
)Returns the best available price per selection across all bookmakers, and flags any arbitrage opportunities. Cost: 3 credits.
curl "https://api.puntersedge.online/v1/best-odds/afl" \ -H "X-API-Key: YOUR_API_KEY"
r = requests.get(
"https://api.puntersedge.online/v1/best-odds/afl",
headers={"X-API-Key": "YOUR_API_KEY"}
)// Also a bare array. Each event carries `selections`, already merged across books.
const res = await fetch("https://api.puntersedge.online/v1/best-odds/afl", {
headers: { "X-API-Key": "YOUR_API_KEY" }
});
const events = await res.json();
for (const ev of events) {
console.log(`${ev.home_team} v ${ev.away_team}`);
for (const sel of ev.selections) {
console.log(` ${sel.name} ${sel.best_price} (${sel.best_bookmaker})`);
}
if (ev.arb_exists) console.log(` arb ${ev.arb_profit_pct}%`);
}[
{
"id": "def456",
"sport_key": "afl",
"home_team": "Collingwood",
"away_team": "Carlton",
"commence_time": "2026-08-22T09:20:00Z",
"selections": [
{"name": "Collingwood", "best_price": 1.92, "best_bookmaker": "tab"},
{"name": "Carlton", "best_price": 2.10, "best_bookmaker": "sportsbet"}
],
"arb_exists": false,
"arb_profit_pct": -3.8,
"data_age_seconds": 41,
"freshest_age_seconds": 3,
"stale": false,
"stale_bookmakers": []
}
]Scans upcoming markets for true arbitrage and best-odds overlays, returning arb_pct, optimal stakes and per-selection price comparison. Set min_profit_pct=0 to also see value overlays. Cost: 3 credits.
curl "https://api.puntersedge.online/v1/arb/sports?sport_key=nrl&min_profit_pct=0" \ -H "X-API-Key: YOUR_API_KEY"
r = requests.get(
"https://api.puntersedge.online/v1/arb/sports",
params={"sport_key": "nrl", "min_profit_pct": 0},
headers={"X-API-Key": "YOUR_API_KEY"}
)
for evt in r.json():
if evt["is_arb"]:
print(evt["home_team"], "vs", evt["away_team"], evt["arb_pct"], "%")[
{
"sport_key": "nrl",
"home_team": "Melbourne Storm",
"away_team": "Penrith Panthers",
"commence_time": "2026-06-21T09:50:00Z",
"is_arb": true,
"arb_pct": 2.84,
"max_overlay_pct": 3.1,
"optimal_stakes": [
{"name": "Melbourne Storm", "stake": 52.7, "bookmaker": "sportsbet", "profit_if_wins": 5.41},
{"name": "Penrith Panthers", "stake": 47.3, "bookmaker": "neds", "profit_if_wins": 5.39}
],
"selections": [
{"name": "Melbourne Storm", "best_price": 1.96, "best_bookmaker": "sportsbet",
"avg_price": 1.88, "overlay_pct": 3.1,
"all_prices": [{"bookmaker": "sportsbet", "price": 1.96}, {"bookmaker": "tab", "price": 1.90}]}
]
}
]Returns the best win and place price for every runner across the Australian bookmakers, with the book offering it, a deep link to that book's race page, and the market percentage so you can see the overround.
curl "https://api.puntersedge.online/v1/racing/best-odds?categories=horse" \ -H "X-API-Key: YOUR_API_KEY"
r = requests.get(
"https://api.puntersedge.online/v1/racing/best-odds",
params={"categories": "horse", "min_edge_pct": 1, "verify": 1},
headers={"X-API-Key": "YOUR_API_KEY"}
)[
{
"race_id": "race_123", "venue": "Rosehill", "race_number": 8, "category": "horse",
"country": "AU", "start_time": "2026-08-15T05:45:00Z", "race_name": "TAB ROSEBUD",
"track_condition": "Good (4)", "market_percentage": 106.4, "books_compared": 11,
"scratchings": [], "data_age_seconds": 41, "freshest_age_seconds": 3, "stale": false,
"runners": [
{
"name": "Chilly Girl", "number": 7, "barrier": 3,
"jockey": "J Mcdonald", "trainer": "C Waller",
"best_win": {"price": 6.5, "bookmaker": "betright", "age_seconds": 6, "stale": false},
"best_place": {"price": 2.15, "bookmaker": "tab", "age_seconds": 4, "stale": false}
}
]
}
]Snapshots over a date range and detected price moves. Available on Standard, Business and Unlimited (and legacy Pro, Growth and Enterprise keys). Free and Hobby get a 403. Cost: 5 credits each.
# Historical h2h snapshots for the last 7 days curl "https://api.puntersedge.online/v1/sports/afl/odds/history?market=h2h" \ -H "X-API-Key: YOUR_API_KEY" # Price movements in the last 24h (min 0.05 drift) curl "https://api.puntersedge.online/v1/sports/afl/odds/movements?min_delta=0.05" \ -H "X-API-Key: YOUR_API_KEY"
Returns the next N races with runners and current fixed odds. Cost: 2 credits.
# All racing categories curl "https://api.puntersedge.online/v1/racing/next-to-go?num_races=5" \ -H "X-API-Key: YOUR_API_KEY" # Horse racing only curl "https://api.puntersedge.online/v1/racing/next-to-go?num_races=5&categories=horse" \ -H "X-API-Key: YOUR_API_KEY"
r = requests.get(
"https://api.puntersedge.online/v1/racing/next-to-go",
params={"num_races": 5, "categories": "horse"},
headers={"X-API-Key": "YOUR_API_KEY"}
)// Node 18+ or any modern browser. Returns a JSON ARRAY of races.
const res = await fetch(
"https://api.puntersedge.online/v1/racing/next-to-go?num_races=5&categories=horse",
{ headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const races = await res.json();
for (const race of races) {
console.log(`${race.venue} R${race.race_number} (${race.category})`);
for (const runner of race.runners.slice(0, 4)) {
const best = runner.bookmakers.reduce((a, b) => (b.win_price > a.win_price ? b : a));
console.log(` ${runner.name} ${best.win_price} (${best.key})`);
}
}Returns credits used and remaining this month. Cost: 0 credits.
curl https://api.puntersedge.online/v1/usage \ -H "X-API-Key: YOUR_API_KEY"
{
"plan": "free",
"credits_limit": 1500,
"credits_used": 47,
"credits_remaining": 1453,
"reset_at": "2026-09-01T00:00:00",
"usage_by_endpoint": [
{"endpoint": "/v1/racing/next-to-go", "calls": 20, "credits": 40}
]
}# Every error is application/problem+json with the same four keys.
# Missing API key — 401
{"type": "https://puntersedge.online/errors/unauthorized",
"title": "X-API-Key header required",
"status": 401,
"detail": "X-API-Key header required"}
# Invalid API key — 401
{"type": "https://puntersedge.online/errors/unauthorized",
"title": "Invalid API key",
"status": 401,
"detail": "Invalid API key"}
# Monthly credits exhausted — 402 (detail names your plan and limit)
{"type": "https://puntersedge.online/errors/payment-required",
"title": "Credit limit reached (1500/mo on free plan). Upgrade at puntersedge.online/api",
"status": 402,
"detail": "Credit limit reached (1500/mo on free plan). Upgrade at puntersedge.online/api"}
# Plan does not include this endpoint — 403 (historical odds & movements)
{"type": "https://puntersedge.online/errors/forbidden",
"title": "Historical odds are available on Standard, Business, Unlimited and Enterprise plans only",
"status": 403,
"detail": "Historical odds are available on Standard, Business, Unlimited and Enterprise plans only"}
# Unknown sport_key — 404 (the full list of valid keys is returned with it)
{"type": "https://puntersedge.online/errors/not-found",
"title": "Unknown sport_key 'notasport'. Valid sport_keys: afl, aflw, basketball_other, ... See GET /v1/sports.",
"status": 404,
"detail": "Unknown sport_key 'notasport'. Valid sport_keys: ... See GET /v1/sports."}
# The live response spells out every active key (19 as at 2026-08-16). Read them from
# GET /v1/sports rather than hard-coding this list — sports are added without notice.
# Too many requests — 429 (detail is an object here, not a string)
{"type": "https://puntersedge.online/errors/rate-limit",
"title": "Error",
"status": 429,
"detail": {"error": "rate_limit_exceeded",
"message": "Rate limit exceeded: 30 requests/minute on free plan.",
"upgrade_url": "https://puntersedge.online/api",
"retry_after_seconds": 60}}