Skip to main content
Version: main

๐ŸŽฒ Betting odds with sportsdataverse-py

Welcome! In a few lines of Python you're about to pull live betting odds from a whole market of sportsbooks โ€” moneylines, spreads, totals, player props, scores, even point-in-time history. sportsdataverse.odds wraps The Odds API v4 and hands you back tidy polars DataFrames that are ready to model. ๐Ÿš€

If you've used the R package oddsapiR, the toa_* names will feel right at home. Let's dive in!

๐Ÿงฐ The toolboxโ€‹

Every function returns a tidy polars DataFrame by default โ€” pass return_as_pandas=True for pandas, or return_parsed=False for the raw JSON. Here's the whole kit (click any name for the full reference):

FunctionWhat it gives youQuota
toa_sportsEvery in-season sport/league key (the sport= value)๐Ÿ†“ free
toa_sports_oddsCurrent odds for a sport โ€” one row per outcome๐Ÿ’ณ paid
toa_event_oddsOdds for a single game, including player props๐Ÿ’ณ paid
toa_event_marketsWhich markets a game has on offer๐Ÿ†“ free
toa_sports_scoresLive + recently-completed scores๐Ÿ†“ free
toa_sports_eventsUpcoming + live event list (grab event_ids here)๐Ÿ†“ free
toa_sports_participantsTeams / participants for a sport๐Ÿ†“ free
toa_sports_odds_historyHistorical odds snapshot (paid plans)๐Ÿ’ณ paid
toa_sports_events_historyHistorical event snapshot๐Ÿ’ณ paid
toa_event_odds_historyHistorical single-game odds๐Ÿ’ณ paid
toa_usageYour remaining quota (reads cached headers)๐Ÿ†“ free

๐Ÿ”‘ Setupโ€‹

pip install sportsdataverse

The Odds API needs a key โ€” grab a free one at the-odds-api.com. Set it once as the ODDS_API_KEY environment variable (the same name oddsapiR uses) or pass api_key= to any call. The live cells below run only when a key is present, so this page is happy either way. ๐Ÿ˜Š

import os
import polars as pl
import sportsdataverse.odds as odds

HAS_KEY = bool(os.environ.get("ODDS_API_KEY"))
print("ODDS_API_KEY set:", HAS_KEY, "โ€” live cells will" + ("" if HAS_KEY else " NOT") + " run")
ODDS_API_KEY set: True โ€” live cells will run

๐Ÿ—‚๏ธ What's on the board?โ€‹

Start with toa_sports โ€” it lists every sport/league key, and it's free (doesn't touch your quota). The key column is what you pass as sport= everywhere else.

if HAS_KEY:
sports = odds.toa_sports(all_sports=True)
out = sports.select([c for c in ["key", "group", "title", "active"] if c in sports.columns]).head(12)
else:
out = "set ODDS_API_KEY to run: odds.toa_sports(all_sports=True)"
out
shape: (12, 4)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ key โ”† group โ”† title โ”† active โ”‚
โ”‚ --- โ”† --- โ”† --- โ”† --- โ”‚
โ”‚ str โ”† str โ”† str โ”† bool โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ americanfootball_cfl โ”† American Football โ”† CFL โ”† true โ”‚
โ”‚ americanfootball_ncaaf โ”† American Football โ”† NCAAF โ”† true โ”‚
โ”‚ americanfootball_ncaaf_champioโ€ฆ โ”† American Football โ”† NCAAF Championship Winner โ”† true โ”‚
โ”‚ americanfootball_ncaaf_fcs โ”† American Football โ”† NCAAF FCS โ”† false โ”‚
โ”‚ americanfootball_nfl โ”† American Football โ”† NFL โ”† true โ”‚
โ”‚ โ€ฆ โ”† โ€ฆ โ”† โ€ฆ โ”† โ€ฆ โ”‚
โ”‚ americanfootball_ufl โ”† American Football โ”† UFL โ”† false โ”‚
โ”‚ aussierules_afl โ”† Aussie Rules โ”† AFL โ”† true โ”‚
โ”‚ aussierules_aflw โ”† Aussie Rules โ”† AFL Women's โ”† true โ”‚
โ”‚ baseball_kbo โ”† Baseball โ”† KBO โ”† true โ”‚
โ”‚ baseball_milb โ”† Baseball โ”† MiLB โ”† true โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ’ฐ The main event: live oddsโ€‹

toa_sports_odds is the workhorse. It returns long format โ€” one row per event ร— bookmaker ร— market ร— outcome โ€” which is exactly the shape you want for filtering and modelling. Knobs:

  • regions โ€” bookmaker regions: us, us2, uk, eu, au (comma-separate to mix).
  • markets โ€” h2h (moneyline), spreads, totals, outrights, โ€ฆ (comma-separated).
  • odds_format โ€” american or decimal.
  • bookmakers โ€” pin specific books (takes precedence over regions).
if HAS_KEY:
board = odds.toa_sports_odds(sport="americanfootball_nfl", regions="us", markets="h2h,spreads")
keep = ["home_team", "away_team", "bookmaker_key", "market_key", "outcome_name", "outcome_point", "outcome_price"]
out = board.select([c for c in keep if c in board.columns]).head(10)
else:
board = None
out = "set ODDS_API_KEY to run: odds.toa_sports_odds(sport='americanfootball_nfl', regions='us')"
out
shape: (10, 7)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ home_team โ”† away_team โ”† bookmaker_k โ”† market_key โ”† outcome_nam โ”† outcome_poi โ”† outcome_pri โ”‚
โ”‚ --- โ”† --- โ”† ey โ”† --- โ”† e โ”† nt โ”† ce โ”‚
โ”‚ str โ”† str โ”† --- โ”† str โ”† --- โ”† --- โ”† --- โ”‚
โ”‚ โ”† โ”† str โ”† โ”† str โ”† f64 โ”† i64 โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ Seattle โ”† New England โ”† draftkings โ”† h2h โ”† New England โ”† null โ”† 145 โ”‚
โ”‚ Seahawks โ”† Patriots โ”† โ”† โ”† Patriots โ”† โ”† โ”‚
โ”‚ Seattle โ”† New England โ”† draftkings โ”† h2h โ”† Seattle โ”† null โ”† -175 โ”‚
โ”‚ Seahawks โ”† Patriots โ”† โ”† โ”† Seahawks โ”† โ”† โ”‚
โ”‚ Seattle โ”† New England โ”† draftkings โ”† spreads โ”† New England โ”† 3.5 โ”† -118 โ”‚
โ”‚ Seahawks โ”† Patriots โ”† โ”† โ”† Patriots โ”† โ”† โ”‚
โ”‚ Seattle โ”† New England โ”† draftkings โ”† spreads โ”† Seattle โ”† -3.5 โ”† -102 โ”‚
โ”‚ Seahawks โ”† Patriots โ”† โ”† โ”† Seahawks โ”† โ”† โ”‚
โ”‚ Seattle โ”† New England โ”† betus โ”† h2h โ”† New England โ”† null โ”† 150 โ”‚
โ”‚ Seahawks โ”† Patriots โ”† โ”† โ”† Patriots โ”† โ”† โ”‚
โ”‚ Seattle โ”† New England โ”† betus โ”† h2h โ”† Seattle โ”† null โ”† -175 โ”‚
โ”‚ Seahawks โ”† Patriots โ”† โ”† โ”† Seahawks โ”† โ”† โ”‚
โ”‚ Seattle โ”† New England โ”† betus โ”† spreads โ”† New England โ”† 3.5 โ”† -120 โ”‚
โ”‚ Seahawks โ”† Patriots โ”† โ”† โ”† Patriots โ”† โ”† โ”‚
โ”‚ Seattle โ”† New England โ”† betus โ”† spreads โ”† Seattle โ”† -3.5 โ”† 100 โ”‚
โ”‚ Seahawks โ”† Patriots โ”† โ”† โ”† Seahawks โ”† โ”† โ”‚
โ”‚ Seattle โ”† New England โ”† fanduel โ”† h2h โ”† New England โ”† null โ”† 158 โ”‚
โ”‚ Seahawks โ”† Patriots โ”† โ”† โ”† Patriots โ”† โ”† โ”‚
โ”‚ Seattle โ”† New England โ”† fanduel โ”† h2h โ”† Seattle โ”† null โ”† -188 โ”‚
โ”‚ Seahawks โ”† Patriots โ”† โ”† โ”† Seahawks โ”† โ”† โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿณ Cookbook: common odds tasksโ€‹

Because everything is one tidy long frame, the fun stuff is just a few polars expressions away. Twelve recipes you'll reach for constantly โ€” every live cell is key-guarded, so the page renders fine with or without a key.

Recipe 1 โ€” Best available moneyline (line shopping ๐Ÿ›’)โ€‹

For each team, find the highest moneyline price across every book โ€” and which book is offering it. Sort by price descending, group, take the top.

if HAS_KEY and board is not None:
h2h = board.filter(pl.col("market_key") == "h2h")
best = (
h2h.sort("outcome_price", descending=True)
.group_by(["home_team", "away_team", "outcome_name"], maintain_order=True)
.agg(pl.first("outcome_price").alias("best_price"), pl.first("bookmaker_key").alias("best_book"))
)
out = best.head(10)
else:
out = "needs ODDS_API_KEY"
out
shape: (10, 5)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ home_team โ”† away_team โ”† outcome_name โ”† best_price โ”† best_book โ”‚
โ”‚ --- โ”† --- โ”† --- โ”† --- โ”† --- โ”‚
โ”‚ str โ”† str โ”† str โ”† i64 โ”† str โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ Los Angeles Rams โ”† Arizona Cardinals โ”† Arizona Cardinals โ”† 650 โ”† williamhill_us โ”‚
โ”‚ Seattle Seahawks โ”† Arizona Cardinals โ”† Arizona Cardinals โ”† 575 โ”† draftkings โ”‚
โ”‚ Buffalo Bills โ”† Miami Dolphins โ”† Miami Dolphins โ”† 500 โ”† williamhill_us โ”‚
โ”‚ San Francisco 49ers โ”† Miami Dolphins โ”† Miami Dolphins โ”† 490 โ”† draftkings โ”‚
โ”‚ San Francisco 49ers โ”† Arizona Cardinals โ”† Arizona Cardinals โ”† 470 โ”† draftkings โ”‚
โ”‚ Green Bay Packers โ”† Miami Dolphins โ”† Miami Dolphins โ”† 470 โ”† draftkings โ”‚
โ”‚ Kansas City Chiefs โ”† Arizona Cardinals โ”† Arizona Cardinals โ”† 450 โ”† williamhill_us โ”‚
โ”‚ Los Angeles Chargers โ”† Arizona Cardinals โ”† Arizona Cardinals โ”† 425 โ”† betus โ”‚
โ”‚ New England Patriots โ”† Miami Dolphins โ”† Miami Dolphins โ”† 425 โ”† draftkings โ”‚
โ”‚ Dallas Cowboys โ”† Arizona Cardinals โ”† Arizona Cardinals โ”† 410 โ”† draftkings โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Recipe 2 โ€” Spreads & totals for a slate ๐Ÿ“‹โ€‹

Ask for markets="spreads,totals" and the outcome_point column carries the line (the spread number / the over-under total).

if HAS_KEY:
st = odds.toa_sports_odds(sport="americanfootball_nfl", regions="us", markets="spreads,totals")
out = (
st.filter(pl.col("bookmaker_key") == st["bookmaker_key"][0])
.select(["home_team", "away_team", "market_key", "outcome_name", "outcome_point", "outcome_price"])
.head(10)
if st.height else "no spreads/totals on the board right now"
)
else:
out = "needs ODDS_API_KEY"
out
shape: (10, 6)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ home_team โ”† away_team โ”† market_key โ”† outcome_name โ”† outcome_point โ”† outcome_price โ”‚
โ”‚ --- โ”† --- โ”† --- โ”† --- โ”† --- โ”† --- โ”‚
โ”‚ str โ”† str โ”† str โ”† str โ”† f64 โ”† i64 โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ Seattle โ”† New England โ”† spreads โ”† New England โ”† 3.5 โ”† -118 โ”‚
โ”‚ Seahawks โ”† Patriots โ”† โ”† Patriots โ”† โ”† โ”‚
โ”‚ Seattle โ”† New England โ”† spreads โ”† Seattle Seahawks โ”† -3.5 โ”† -102 โ”‚
โ”‚ Seahawks โ”† Patriots โ”† โ”† โ”† โ”† โ”‚
โ”‚ Seattle โ”† New England โ”† totals โ”† Over โ”† 44.5 โ”† -105 โ”‚
โ”‚ Seahawks โ”† Patriots โ”† โ”† โ”† โ”† โ”‚
โ”‚ Seattle โ”† New England โ”† totals โ”† Under โ”† 44.5 โ”† -115 โ”‚
โ”‚ Seahawks โ”† Patriots โ”† โ”† โ”† โ”† โ”‚
โ”‚ Los Angeles โ”† San Francisco โ”† spreads โ”† Los Angeles Rams โ”† -3.5 โ”† -108 โ”‚
โ”‚ Rams โ”† 49ers โ”† โ”† โ”† โ”† โ”‚
โ”‚ Los Angeles โ”† San Francisco โ”† spreads โ”† San Francisco โ”† 3.5 โ”† -112 โ”‚
โ”‚ Rams โ”† 49ers โ”† โ”† 49ers โ”† โ”† โ”‚
โ”‚ Los Angeles โ”† San Francisco โ”† totals โ”† Over โ”† 48.5 โ”† -105 โ”‚
โ”‚ Rams โ”† 49ers โ”† โ”† โ”† โ”† โ”‚
โ”‚ Los Angeles โ”† San Francisco โ”† totals โ”† Under โ”† 48.5 โ”† -115 โ”‚
โ”‚ Rams โ”† 49ers โ”† โ”† โ”† โ”† โ”‚
โ”‚ Pittsburgh โ”† Atlanta Falcons โ”† spreads โ”† Atlanta Falcons โ”† 3.5 โ”† -118 โ”‚
โ”‚ Steelers โ”† โ”† โ”† โ”† โ”† โ”‚
โ”‚ Pittsburgh โ”† Atlanta Falcons โ”† spreads โ”† Pittsburgh โ”† -3.5 โ”† -102 โ”‚
โ”‚ Steelers โ”† โ”† โ”† Steelers โ”† โ”† โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Recipe 3 โ€” Just one book ๐ŸŽฏโ€‹

Pin a single sportsbook with bookmakers=. Great for tracking your book's line without paying for a whole region.

if HAS_KEY:
dk = odds.toa_sports_odds(sport="americanfootball_nfl", bookmakers="draftkings", markets="h2h")
out = dk.select(["home_team", "away_team", "outcome_name", "outcome_price"]).head() if dk.height else "no lines yet"
else:
out = "needs ODDS_API_KEY"
out
shape: (5, 4)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ home_team โ”† away_team โ”† outcome_name โ”† outcome_price โ”‚
โ”‚ --- โ”† --- โ”† --- โ”† --- โ”‚
โ”‚ str โ”† str โ”† str โ”† i64 โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ Seattle Seahawks โ”† New England Patriots โ”† New England Patriots โ”† 145 โ”‚
โ”‚ Seattle Seahawks โ”† New England Patriots โ”† Seattle Seahawks โ”† -175 โ”‚
โ”‚ Los Angeles Rams โ”† San Francisco 49ers โ”† Los Angeles Rams โ”† -185 โ”‚
โ”‚ Los Angeles Rams โ”† San Francisco 49ers โ”† San Francisco 49ers โ”† 154 โ”‚
โ”‚ Pittsburgh Steelers โ”† Atlanta Falcons โ”† Atlanta Falcons โ”† 150 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Recipe 4 โ€” Implied probability & the hold ๐Ÿงฎโ€‹

American moneyline prices convert to implied win probability with a tiny formula. Add up both sides and the excess over 100% is the book's hold (the vig). Pure polars math on the frame you already pulled โ€” no extra API call.

if HAS_KEY and board is not None:
h2h = board.filter(pl.col("market_key") == "h2h")
devig = (
h2h.with_columns(
pl.when(pl.col("outcome_price") < 0)
.then(-pl.col("outcome_price") / (-pl.col("outcome_price") + 100))
.otherwise(100 / (pl.col("outcome_price") + 100))
.alias("implied_prob")
)
.group_by(["home_team", "away_team", "bookmaker_key"], maintain_order=True)
.agg(pl.sum("implied_prob").alias("market_total"))
.with_columns(((pl.col("market_total") - 1) * 100).round(2).alias("hold_pct"))
.sort("hold_pct")
)
out = devig.head(10)
else:
out = "needs ODDS_API_KEY"
out
shape: (10, 5)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ home_team โ”† away_team โ”† bookmaker_key โ”† market_total โ”† hold_pct โ”‚
โ”‚ --- โ”† --- โ”† --- โ”† --- โ”† --- โ”‚
โ”‚ str โ”† str โ”† str โ”† f64 โ”† f64 โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ Philadelphia Eagles โ”† Houston Texans โ”† williamhill_us โ”† 1.027778 โ”† 2.78 โ”‚
โ”‚ Indianapolis Colts โ”† Baltimore Ravens โ”† lowvig โ”† 1.030996 โ”† 3.1 โ”‚
โ”‚ Indianapolis Colts โ”† Baltimore Ravens โ”† betonlineag โ”† 1.030996 โ”† 3.1 โ”‚
โ”‚ Seattle Seahawks โ”† New England Patriots โ”† lowvig โ”† 1.031146 โ”† 3.11 โ”‚
โ”‚ Seattle Seahawks โ”† New England Patriots โ”† betonlineag โ”† 1.031146 โ”† 3.11 โ”‚
โ”‚ Arizona Cardinals โ”† Seattle Seahawks โ”† williamhill_us โ”† 1.031668 โ”† 3.17 โ”‚
โ”‚ Pittsburgh Steelers โ”† Atlanta Falcons โ”† betonlineag โ”† 1.031962 โ”† 3.2 โ”‚
โ”‚ Pittsburgh Steelers โ”† Atlanta Falcons โ”† lowvig โ”† 1.031962 โ”† 3.2 โ”‚
โ”‚ Las Vegas Raiders โ”† Miami Dolphins โ”† betonlineag โ”† 1.031962 โ”† 3.2 โ”‚
โ”‚ Las Vegas Raiders โ”† Miami Dolphins โ”† lowvig โ”† 1.031962 โ”† 3.2 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Recipe 5 โ€” Find the biggest favorite on the board ๐Ÿปโ€‹

Sort the moneyline outcomes by price ascending โ€” the most negative number is the heaviest chalk on the slate. A classic "find the X" one-liner.

if HAS_KEY and board is not None:
faves = (
board.filter(pl.col("market_key") == "h2h")
.sort("outcome_price")
.select(["home_team", "away_team", "outcome_name", "outcome_price", "bookmaker_key"])
.head(5)
)
out = faves
else:
out = "needs ODDS_API_KEY"
out
shape: (5, 5)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ home_team โ”† away_team โ”† outcome_name โ”† outcome_price โ”† bookmaker_key โ”‚
โ”‚ --- โ”† --- โ”† --- โ”† --- โ”† --- โ”‚
โ”‚ str โ”† str โ”† str โ”† i64 โ”† str โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ Los Angeles Rams โ”† Arizona Cardinals โ”† Los Angeles Rams โ”† -1000 โ”† williamhill_us โ”‚
โ”‚ Seattle Seahawks โ”† Arizona Cardinals โ”† Seattle Seahawks โ”† -850 โ”† draftkings โ”‚
โ”‚ Los Angeles Rams โ”† Arizona Cardinals โ”† Los Angeles Rams โ”† -800 โ”† draftkings โ”‚
โ”‚ Seattle Seahawks โ”† Arizona Cardinals โ”† Seattle Seahawks โ”† -800 โ”† williamhill_us โ”‚
โ”‚ Buffalo Bills โ”† Miami Dolphins โ”† Buffalo Bills โ”† -800 โ”† williamhill_us โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Recipe 6 โ€” Consensus over/under per game ๐Ÿ“Šโ€‹

Books disagree by a half-point here and there. Take the median total across every book to get a stable market consensus for each matchup.

if HAS_KEY:
tot = odds.toa_sports_odds(sport="americanfootball_nfl", regions="us", markets="totals")
if tot.height:
consensus = (
tot.filter(pl.col("outcome_name") == "Over")
.group_by(["home_team", "away_team"], maintain_order=True)
.agg(
pl.median("outcome_point").alias("consensus_total"),
pl.col("bookmaker_key").n_unique().alias("n_books"),
)
.sort("consensus_total", descending=True)
)
out = consensus.head(10)
else:
out = "no totals on the board right now"
else:
out = "needs ODDS_API_KEY"
out
shape: (10, 4)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ home_team โ”† away_team โ”† consensus_total โ”† n_books โ”‚
โ”‚ --- โ”† --- โ”† --- โ”† --- โ”‚
โ”‚ str โ”† str โ”† f64 โ”† u32 โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ Los Angeles Rams โ”† Buffalo Bills โ”† 54.0 โ”† 2 โ”‚
โ”‚ Dallas Cowboys โ”† San Francisco 49ers โ”† 53.0 โ”† 2 โ”‚
โ”‚ Los Angeles Rams โ”† Dallas Cowboys โ”† 53.0 โ”† 2 โ”‚
โ”‚ Dallas Cowboys โ”† Tampa Bay Buccaneers โ”† 52.5 โ”† 3 โ”‚
โ”‚ Indianapolis Colts โ”† Dallas Cowboys โ”† 52.5 โ”† 3 โ”‚
โ”‚ Washington Commanders โ”† Cincinnati Bengals โ”† 52.5 โ”† 3 โ”‚
โ”‚ Detroit Lions โ”† Chicago Bears โ”† 52.5 โ”† 3 โ”‚
โ”‚ Indianapolis Colts โ”† Cincinnati Bengals โ”† 52.5 โ”† 3 โ”‚
โ”‚ Buffalo Bills โ”† Detroit Lions โ”† 52.0 โ”† 7 โ”‚
โ”‚ Dallas Cowboys โ”† Jacksonville Jaguars โ”† 52.0 โ”† 2 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Recipe 7 โ€” Just today's slate โฐโ€‹

Narrow the pull to a time window with commence_time_from / commence_time_to (ISO-8601, UTC). Here: only games kicking off in the next 24 hours.

from datetime import datetime, timedelta, timezone

if HAS_KEY:
now = datetime.now(timezone.utc)
fmt = "%Y-%m-%dT%H:%M:%SZ"
today = odds.toa_sports_odds(
sport="americanfootball_nfl",
regions="us",
markets="h2h",
commence_time_from=now.strftime(fmt),
commence_time_to=(now + timedelta(hours=24)).strftime(fmt),
)
out = (
today.select(["commence_time", "home_team", "away_team"]).unique(maintain_order=True).head(10)
if today.height else "nothing kicks off in the next 24h"
)
else:
out = "set ODDS_API_KEY to run the commence-time filter recipe"
out
'nothing kicks off in the next 24h'

Recipe 8 โ€” Player props for one game ๐ŸŽฏโ€‹

Event-level markets (player props!) live on toa_event_odds. Grab an event_id from toa_sports_events, then ask for a prop market like player_pass_tds or player_anytime_td.

if HAS_KEY:
events = odds.toa_sports_events(sport="americanfootball_nfl", return_parsed=False)
if events:
eid = events[0]["id"]
props = odds.toa_event_odds(sport="americanfootball_nfl", event_id=eid, markets="player_pass_tds")
out = props.select([c for c in ["outcome_name", "outcome_description", "outcome_point", "outcome_price"]
if c in props.columns]).head()
else:
out = "no upcoming NFL events right now"
else:
out = "set ODDS_API_KEY to run the player-props recipe"
out
shape: (5, 4)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ outcome_name โ”† outcome_description โ”† outcome_point โ”† outcome_price โ”‚
โ”‚ --- โ”† --- โ”† --- โ”† --- โ”‚
โ”‚ str โ”† str โ”† f64 โ”† i64 โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ Over โ”† Sam Darnold โ”† 1.5 โ”† 107 โ”‚
โ”‚ Under โ”† Sam Darnold โ”† 1.5 โ”† -136 โ”‚
โ”‚ Over โ”† Drake Maye โ”† 1.5 โ”† 127 โ”‚
โ”‚ Under โ”† Drake Maye โ”† 1.5 โ”† -162 โ”‚
โ”‚ Over โ”† Drake Maye โ”† 1.5 โ”† 138 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Recipe 9 โ€” Which markets does a game offer? ๐Ÿ—ƒ๏ธโ€‹

Not sure which props are even available? toa_event_markets lists every market on offer per book โ€” and it's free. Count them up to see which sportsbook posts the deepest menu.

if HAS_KEY:
events = odds.toa_sports_events(sport="americanfootball_nfl", return_parsed=False)
if events:
eid = events[0]["id"]
mk = odds.toa_event_markets(sport="americanfootball_nfl", event_id=eid)
out = (
mk.group_by("bookmaker_key").agg(pl.col("market_key").n_unique().alias("n_markets"))
.sort("n_markets", descending=True).head(10)
if mk.height else "no markets posted for this event yet"
)
else:
out = "no upcoming NFL events right now"
else:
out = "set ODDS_API_KEY to run the event-markets recipe"
out
shape: (10, 2)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ bookmaker_key โ”† n_markets โ”‚
โ”‚ --- โ”† --- โ”‚
โ”‚ str โ”† u32 โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ draftkings โ”† 102 โ”‚
โ”‚ fanduel โ”† 59 โ”‚
โ”‚ betrivers โ”† 48 โ”‚
โ”‚ bovada โ”† 44 โ”‚
โ”‚ fanatics โ”† 32 โ”‚
โ”‚ betonlineag โ”† 30 โ”‚
โ”‚ betmgm โ”† 29 โ”‚
โ”‚ williamhill_us โ”† 23 โ”‚
โ”‚ betus โ”† 6 โ”‚
โ”‚ lowvig โ”† 3 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Recipe 10 โ€” Recent finals & margin of victory ๐Ÿโ€‹

toa_sports_scores returns live + recently completed games (days_from=1..3, free). Keep the completed ones and show the final scoreline โ€” handy for grading bets after the fact.

if HAS_KEY:
sc = odds.toa_sports_scores(sport="americanfootball_nfl", days_from=3)
keep = [c for c in ["completed", "home_team", "away_team", "scores", "last_update"] if c in sc.columns]
if sc.height and "completed" in sc.columns:
out = sc.filter(pl.col("completed")).select(keep).head(10)
else:
out = sc.select(keep).head(10) if sc.height else "no recent scores right now"
else:
out = "set ODDS_API_KEY to run: odds.toa_sports_scores(sport='americanfootball_nfl', days_from=3)"
out
shape: (0, 5)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ completed โ”† home_team โ”† away_team โ”† scores โ”† last_update โ”‚
โ”‚ --- โ”† --- โ”† --- โ”† --- โ”† --- โ”‚
โ”‚ bool โ”† str โ”† str โ”† str โ”† str โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Recipe 11 โ€” Tour several leagues at once ๐Ÿ”โ€‹

The sport= key is the only thing that changes between leagues, so one loop counts the upcoming events across a handful of them. toa_sports_events is free, so this sweep costs you nothing.

if HAS_KEY:
keys = ["americanfootball_nfl", "basketball_nba", "icehockey_nhl", "baseball_mlb"]
rows = []
for k in keys:
evs = odds.toa_sports_events(sport=k, return_parsed=False)
rows.append({"sport": k, "upcoming_events": len(evs) if isinstance(evs, list) else 0})
out = pl.DataFrame(rows).sort("upcoming_events", descending=True)
else:
out = "set ODDS_API_KEY to tour leagues with odds.toa_sports_events(sport=...)"
out
shape: (4, 2)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ sport โ”† upcoming_events โ”‚
โ”‚ --- โ”† --- โ”‚
โ”‚ str โ”† i64 โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ americanfootball_nfl โ”† 272 โ”‚
โ”‚ basketball_nba โ”† 41 โ”‚
โ”‚ icehockey_nhl โ”† 32 โ”‚
โ”‚ baseball_mlb โ”† 23 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Recipe 12 โ€” Who's in the league? (participants ๐Ÿ‘ฅ)โ€‹

toa_sports_participants lists every team / participant for a sport โ€” the lookup table you join odds against by name. Also free.

if HAS_KEY:
parts = odds.toa_sports_participants(sport="americanfootball_nfl")
keep = [c for c in ["full_name", "id", "abbreviation"] if c in parts.columns]
out = parts.select(keep if keep else parts.columns).head(10) if parts.height else "no participants listed"
else:
out = "set ODDS_API_KEY to run: odds.toa_sports_participants(sport='americanfootball_nfl')"
out
shape: (10, 2)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ full_name โ”† id โ”‚
โ”‚ --- โ”† --- โ”‚
โ”‚ str โ”† str โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ Arizona Cardinals โ”† par_01hqmkr1xsfxmrj5pdq0f23asx โ”‚
โ”‚ Atlanta Falcons โ”† par_01hqmkr1xtexkbhkq7ct921rne โ”‚
โ”‚ Baltimore Ravens โ”† par_01hqmkr1xvev9rf557fy09k2cx โ”‚
โ”‚ Buffalo Bills โ”† par_01hqmkr1xwe6prjwr3j4gpqwx8 โ”‚
โ”‚ Carolina Panthers โ”† par_01hqmkr1xxf2ebbqzb95qzxxxm โ”‚
โ”‚ Chicago Bears โ”† par_01hqmkr1xye20ahvp8fr2bvt74 โ”‚
โ”‚ Cincinnati Bengals โ”† par_01hqmkr1xze7xbceshy9tka512 โ”‚
โ”‚ Cleveland Browns โ”† par_01hqmkr1y0ez5bem3gdncd8a0d โ”‚
โ”‚ Dallas Cowboys โ”† par_01hqmkr1y1esas88pmaxe87by4 โ”‚
โ”‚ Denver Broncos โ”† par_01hqmkr1y2e15tjsz9afcsj7da โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ›ฝ Mind your quotaโ€‹

Paid calls cost credits (every 10 bookmakers ร— market โ‰ˆ 1 credit). After any call, toa_usage reads the most recent x-requests-remaining / x-requests-used headers without spending a request โ€” handy to drop at the end of a script.

odds.toa_usage() if HAS_KEY else "set ODDS_API_KEY to track quota with odds.toa_usage()"
shape: (1, 3)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ requests_remaining โ”† requests_used โ”† last_cost โ”‚
โ”‚ --- โ”† --- โ”† --- โ”‚
โ”‚ i64 โ”† i64 โ”† i64 โ”‚
โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
โ”‚ 4957742 โ”† 42258 โ”† 1 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โณ Time travel: historical oddsโ€‹

On a paid plan you can pull point-in-time snapshots โ€” perfect for closing line value studies. Pass a date= ISO-8601 timestamp; the snapshot is unwrapped to the same long format and every row is stamped with the snapshot time.

FunctionSnapshot ofโ€ฆ
toa_sports_odds_historya whole sport's odds at date
toa_sports_events_historythe events at date
toa_event_odds_historyone game's odds at date
odds.toa_sports_odds_history(sport="americanfootball_nfl", date="2023-11-29T22:45:00Z")

๐ŸŽ‰ Where to nextโ€‹

  • Pass return_as_pandas=True for a pandas frame, or return_parsed=False for raw JSON.
  • Full reference: the Betting โ†’ Odds section in the sidebar.
  • R user? The same surface lives in oddsapiR.

Happy modelling โ€” may your closing line value be ever positive! ๐Ÿ“ˆ