๐ฒ Betting odds with sportsdataverse-py
This page is the executed notebook
12_odds_intro.ipynb: download it to run it yourself.
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):
| Function | What it gives you | Quota |
|---|---|---|
toa_sports | Every in-season sport/league key (the sport= value) | ๐ free |
toa_sports_odds | Current odds for a sport โ one row per outcome | ๐ณ paid |
toa_event_odds | Odds for a single game, including player props | ๐ณ paid |
toa_event_markets | Which markets a game has on offer | ๐ free |
toa_sports_scores | Live + recently-completed scores | ๐ free |
toa_sports_events | Upcoming + live event list (grab event_ids here) | ๐ free |
toa_sports_participants | Teams / participants for a sport | ๐ free |
toa_sports_odds_history | Historical odds snapshot (paid plans) | ๐ณ paid |
toa_sports_events_history | Historical event snapshot | ๐ณ paid |
toa_event_odds_history | Historical single-game odds | ๐ณ paid |
toa_usage | Your 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 โ false โ
โ aussierules_aflw โ Aussie Rules โ AFL Women's โ true โ
โ baseball_kbo โ Baseball โ KBO โ true โ
โ baseball_milb โ Baseball โ MiLB โ false โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโ
๐ฐ 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โamericanordecimal.bookmakersโ pin specific books (takes precedence overregions).
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 โ
โโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโชโโโโโโโโโโโโโชโโโโโโโโโโโโโโชโโโโโโโโโโโโโโชโโโโโโโโโโโโโโก
โ Philadelphia โ Dallas โ draftkings โ h2h โ Dallas โ null โ -218 โ
โ Eagles โ Cowboys โ โ โ Cowboys โ โ โ
โ Philadelphia โ Dallas โ draftkings โ h2h โ Philadelphi โ null โ 180 โ
โ Eagles โ Cowboys โ โ โ a Eagles โ โ โ
โ Philadelphia โ Dallas โ draftkings โ spreads โ Dallas โ -4.5 โ -108 โ
โ Eagles โ Cowboys โ โ โ Cowboys โ โ โ
โ Philadelphia โ Dallas โ draftkings โ spreads โ Philadelphi โ 4.5 โ -112 โ
โ Eagles โ Cowboys โ โ โ a Eagles โ โ โ
โ Philadelphia โ Dallas โ betus โ h2h โ Dallas โ null โ -215 โ
โ Eagles โ Cowboys โ โ โ Cowboys โ โ โ
โ Philadelphia โ Dallas โ betus โ h2h โ Philadelphi โ null โ 183 โ
โ Eagles โ Cowboys โ โ โ a Eagles โ โ โ
โ Philadelphia โ Dallas โ betus โ spreads โ Dallas โ -4.0 โ -110 โ
โ Eagles โ Cowboys โ โ โ Cowboys โ โ โ
โ Philadelphia โ Dallas โ betus โ spreads โ Philadelphi โ 4.0 โ -110 โ
โ Eagles โ Cowboys โ โ โ a Eagles โ โ โ
โ Philadelphia โ Dallas โ williamhill โ h2h โ Dallas โ null โ -230 โ
โ Eagles โ Cowboys โ _us โ โ Cowboys โ โ โ
โ Philadelphia โ Dallas โ williamhill โ h2h โ Philadelphi โ null โ 190 โ
โ Eagles โ Cowboys โ _us โ โ a Eagles โ โ โ
โโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโโโโโโโโ
๐ณ 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 โ
โโโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโก
โ Cincinnati Bengals โ Tennessee Titans โ Tennessee Titans โ 475 โ betrivers โ
โ Jacksonville Jaguars โ Indianapolis Colts โ Indianapolis Colts โ 350 โ fanduel โ
โ Miami Dolphins โ New England Patriots โ Miami Dolphins โ 330 โ fanduel โ
โ Los Angeles Rams โ Los Angeles Chargers โ Los Angeles Chargers โ 295 โ betrivers โ
โ Dallas Cowboys โ Arizona Cardinals โ Arizona Cardinals โ 240 โ betrivers โ
โ Philadelphia Eagles โ Dallas Cowboys โ Philadelphia Eagles โ 195 โ betonlineag โ
โ Green Bay Packers โ Carolina Panthers โ Carolina Panthers โ 180 โ fanduel โ
โ Pittsburgh Steelers โ Cleveland Browns โ Cleveland Browns โ 175 โ betrivers โ
โ Washington โ Philadelphia Eagles โ Philadelphia Eagles โ 170 โ betrivers โ
โ Commanders โ โ โ โ โ
โ Buffalo Bills โ Baltimore Ravens โ Baltimore Ravens โ 156 โ williamhill_us โ
โโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโ
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 โ
โโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโก
โ Philadelphia โ Dallas Cowboys โ spreads โ Dallas Cowboys โ -4.5 โ -108 โ
โ Eagles โ โ โ โ โ โ
โ Philadelphia โ Dallas Cowboys โ spreads โ Philadelphia โ 4.5 โ -112 โ
โ Eagles โ โ โ Eagles โ โ โ
โ Philadelphia โ Dallas Cowboys โ totals โ Over โ 43.5 โ -112 โ
โ Eagles โ โ โ โ โ โ
โ Philadelphia โ Dallas Cowboys โ totals โ Under โ 43.5 โ -108 โ
โ Eagles โ โ โ โ โ โ
โ Green Bay โ Carolina โ spreads โ Carolina โ 3.5 โ -105 โ
โ Packers โ Panthers โ โ Panthers โ โ โ
โ Green Bay โ Carolina โ spreads โ Green Bay โ -3.5 โ -115 โ
โ Packers โ Panthers โ โ Packers โ โ โ
โ Green Bay โ Carolina โ totals โ Over โ 47.5 โ -112 โ
โ Packers โ Panthers โ โ โ โ โ
โ Green Bay โ Carolina โ totals โ Under โ 47.5 โ -108 โ
โ Packers โ Panthers โ โ โ โ โ
โ Dallas Cowboys โ Arizona โ spreads โ Arizona โ 6.5 โ -112 โ
โ โ Cardinals โ โ Cardinals โ โ โ
โ Dallas Cowboys โ Arizona โ spreads โ Dallas Cowboys โ -6.5 โ -108 โ
โ โ Cardinals โ โ โ โ โ
โโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโ
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 โ
โโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโก
โ Philadelphia Eagles โ Dallas Cowboys โ Dallas Cowboys โ -218 โ
โ Philadelphia Eagles โ Dallas Cowboys โ Philadelphia Eagles โ 180 โ
โ Green Bay Packers โ Carolina Panthers โ Carolina Panthers โ 164 โ
โ Green Bay Packers โ Carolina Panthers โ Green Bay Packers โ -198 โ
โ Dallas Cowboys โ Arizona Cardinals โ Arizona Cardinals โ 235 โ
โโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโ
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 โ
โโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโชโโโโโโโโโโโก
โ Detroit Lions โ Minnesota Vikings โ lowvig โ 1.030759 โ 3.08 โ
โ Detroit Lions โ Minnesota Vikings โ betonlineag โ 1.030759 โ 3.08 โ
โ Pittsburgh Steelers โ Cleveland Browns โ lowvig โ 1.030947 โ 3.09 โ
โ Pittsburgh Steelers โ Cleveland Browns โ betonlineag โ 1.030947 โ 3.09 โ
โ Green Bay Packers โ Carolina Panthers โ lowvig โ 1.033142 โ 3.31 โ
โ Green Bay Packers โ Carolina Panthers โ betonlineag โ 1.033142 โ 3.31 โ
โ Pittsburgh Steelers โ Cleveland Browns โ betus โ 1.035549 โ 3.55 โ
โ Green Bay Packers โ Carolina Panthers โ betus โ 1.035768 โ 3.58 โ
โ Philadelphia Eagles โ Dallas Cowboys โ betus โ 1.035897 โ 3.59 โ
โ Detroit Lions โ Minnesota Vikings โ betus โ 1.036134 โ 3.61 โ
โโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโ
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 โ
โโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโก
โ Cincinnati Bengals โ Tennessee Titans โ Cincinnati Bengals โ -670 โ betrivers โ
โ Cincinnati Bengals โ Tennessee Titans โ Cincinnati Bengals โ -625 โ draftkings โ
โ Cincinnati Bengals โ Tennessee Titans โ Cincinnati Bengals โ -620 โ fanduel โ
โ Cincinnati Bengals โ Tennessee Titans โ Cincinnati Bengals โ -600 โ betmgm โ
โ Cincinnati Bengals โ Tennessee Titans โ Cincinnati Bengals โ -590 โ 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 โ
โโโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโชโโโโโโโโโโก
โ Dallas Cowboys โ Arizona Cardinals โ 53.5 โ 9 โ
โ Buffalo Bills โ Baltimore Ravens โ 53.5 โ 9 โ
โ Green Bay Packers โ Carolina Panthers โ 47.5 โ 11 โ
โ Cincinnati Bengals โ Tennessee Titans โ 47.0 โ 10 โ
โ Detroit Lions โ Minnesota Vikings โ 46.5 โ 9 โ
โ Jacksonville Jaguars โ Indianapolis Colts โ 46.5 โ 10 โ
โ Seattle Seahawks โ Chicago Bears โ 46.5 โ 6 โ
โ Tampa Bay Buccaneers โ Atlanta Falcons โ 45.0 โ 10 โ
โ New York Jets โ Las Vegas Raiders โ 44.5 โ 10 โ
โ Miami Dolphins โ New England Patriots โ 44.5 โ 10 โ
โโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโดโโโโโโโโโโ
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
shape: (1, 3)
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโ
โ commence_time โ home_team โ away_team โ
โ --- โ --- โ --- โ
โ str โ str โ str โ
โโโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโก
โ 2026-10-27T00:15:00Z โ Philadelphia Eagles โ Dallas Cowboys โ
โโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโ
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 โ Dak Prescott โ 1.5 โ -132 โ
โ Under โ Dak Prescott โ 1.5 โ 104 โ
โ Over โ Tanner McKee โ 1.5 โ 161 โ
โ Under โ Tanner McKee โ 1.5 โ -208 โ
โ Over โ Dak Prescott โ 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 โ 96 โ
โ fanduel โ 64 โ
โ betmgm โ 53 โ
โ betrivers โ 48 โ
โ bovada โ 43 โ
โ fanatics โ 33 โ
โ betonlineag โ 28 โ
โ williamhill_us โ 21 โ
โ betus โ 9 โ
โ mybookieag โ 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: (10, 5)
โโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโ
โ completed โ home_team โ away_team โ scores โ last_update โ
โ --- โ --- โ --- โ --- โ --- โ
โ bool โ str โ str โ str โ str โ
โโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโก
โ true โ New Orleans Saints โ Pittsburgh Steelers โ [{'name': 'New โ 2026-10-26T08:23:46 โ
โ โ โ โ Orleans Saints'โฆ โ Z โ
โ true โ Minnesota Vikings โ Indianapolis Colts โ [{'name': โ 2026-10-26T08:23:46 โ
โ โ โ โ 'Minnesota โ Z โ
โ โ โ โ Vikings',โฆ โ โ
โ true โ Baltimore Ravens โ Cincinnati Bengals โ [{'name': โ 2026-10-26T08:23:46 โ
โ โ โ โ 'Baltimore Ravens', โ Z โ
โ โ โ โ โฆ โ โ
โ true โ Atlanta Falcons โ San Francisco 49ers โ [{'name': 'Atlanta โ 2026-10-26T08:23:46 โ
โ โ โ โ Falcons', 'โฆ โ Z โ
โ true โ Carolina Panthers โ Tampa Bay โ [{'name': 'Carolina โ 2026-10-26T08:23:46 โ
โ โ โ Buccaneers โ Panthers',โฆ โ Z โ
โ true โ Houston Texans โ New York Giants โ [{'name': 'Houston โ 2026-10-26T08:23:46 โ
โ โ โ โ Texans', 'sโฆ โ Z โ
โ true โ New York Jets โ Miami Dolphins โ [{'name': 'New York โ 2026-10-26T08:23:46 โ
โ โ โ โ Jets', 'scโฆ โ Z โ
โ true โ Tennessee Titans โ Cleveland Browns โ [{'name': โ 2026-10-26T08:23:46 โ
โ โ โ โ 'Tennessee Titans', โ Z โ
โ โ โ โ โฆ โ โ
โ true โ Arizona Cardinals โ Denver Broncos โ [{'name': 'Arizona โ 2026-10-26T08:23:46 โ
โ โ โ โ Cardinals',โฆ โ Z โ
โ true โ Detroit Lions โ Green Bay Packers โ [{'name': 'Detroit โ 2026-10-26T08:23:46 โ
โ โ โ โ Lions', 'scโฆ โ Z โ
โโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโ
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 โ 15 โ
โ basketball_nba โ 14 โ
โ icehockey_nhl โ 3 โ
โ baseball_mlb โ 1 โ
โโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโ
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 โ
โโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโชโโโโโโโโโโโโก
โ 4309725 โ 690275 โ 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.
| Function | Snapshot ofโฆ |
|---|---|
toa_sports_odds_history | a whole sport's odds at date |
toa_sports_events_history | the events at date |
toa_event_odds_history | one 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=Truefor a pandas frame, orreturn_parsed=Falsefor 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! ๐