This tutorial pulls odds for the 2027 Masters from several bookmakers with Python, puts them in a pandas table, and finds the best price on each golfer. The same code works for any golf tournament on the PGA Tour, DP World Tour, LIV Golf or the majors. Every sample below was run against the live API on 7 November 2026, and the outputs are the real responses from that day.
The data comes from the Odds-API.io golf outrights endpoints. What they cover, which bookmakers price which markets and how ties are settled is on the Golf Outrights API page. This post is about using the data.
Setup
Install the Python SDK with the pandas extra, and put your API key in the ODDS_API_KEY environment variable. The golf endpoints need the Outrights add-on on a paid plan; without it the SDK raises AddOnRequiredError with a link to add it.
pip install "odds-api-io[pandas]"
export ODDS_API_KEY=your_keyFind the tournament
get_outrights lists the tournaments for a tour, sorted by start date. The majors have their own league, majors, so the Masters is one call away:
import os
from odds_api import OddsAPIClient
from odds_api.dataframes import outright_odds_to_dataframe
client = OddsAPIClient(api_key=os.environ["ODDS_API_KEY"])
majors = client.get_outrights(sport="golf", league="majors")
masters = next(t for t in majors if t["name"].startswith("Masters"))
print(masters["id"], masters["name"], masters["date"], masters["bookmakerCount"])1008 Masters Tournament 2027 2027-04-08T11:00:00Z 36bookmakerCount is how many of the bookmakers on your plan price the tournament right now. Five months out it is already 36, because futures markets for the majors open early.
Fetch prices from several bookmakers
get_outright_odds takes the tournament id and up to 30 bookmakers from your plan. outright_odds_to_dataframe flattens the response into one row per bookmaker, market and golfer:
books = ["DraftKings", "FanDuel", "BetMGM", "Bet365", "William Hill", "Betfair Exchange", "Kalshi", "Polymarket", "Paddy Power"]
odds = client.get_outright_odds(masters["id"], books)
df = outright_odds_to_dataframe(odds)
print(df.groupby("bookmaker")["market"].unique())bookmaker
Bet365 [Winner, Top 5 (Incl. Ties), Top 10 (Incl. Ties)]
BetMGM [Winner]
Betfair Exchange [Winner]
DraftKings [Winner]
FanDuel [Winner]
Kalshi [Winner]
Paddy Power [Winner]
William Hill [Winner]
Name: market, dtype: objectNot every bookmaker prices every market this early. Winner is everywhere; Top 5, 10 and 20 and Make Cut fill in closer to the tournament. Prices are decimal odds, already converted to floats by the dataframe helper. The exchange rows also carry layOdds, and Make Cut rows carry yes and no instead of odds.
Best Winner price per golfer
Each golfer has one participantId and one name across all bookmakers, so a pivot table lines the prices up without any name matching:
winner = df[df["market"] == "Winner"]
table = winner.pivot_table(index="label", columns="bookmaker", values="odds")
table["best"] = table.max(axis=1)
table["best_book"] = table.drop(columns="best").idxmax(axis=1)
table["books"] = table.drop(columns=["best", "best_book"]).count(axis=1)
print(table.sort_values("best").head(10)[["best", "best_book", "books"]])bookmaker best best_book books
label
Scottie Scheffler 5.556 Kalshi 8
Rory McIlroy 12.500 Kalshi 8
Jon Rahm 22.727 Kalshi 8
Ludvig Aberg 23.000 Betfair Exchange 8
Cameron Young 24.000 Betfair Exchange 7
Xander Schauffele 26.000 Betfair Exchange 8
Bryson DeChambeau 27.778 Kalshi 8
Tommy Fleetwood 35.714 Kalshi 8
Collin Morikawa 41.667 Kalshi 8
Matt Fitzpatrick 43.478 Kalshi 8Kalshi or the Betfair Exchange has the longest price on every one of the ten favourites. Two things to keep in mind: exchange prices are before commission and Kalshi prices are before its trading fees, and Cameron Young is listed by seven of the eight bookmakers, so check the books column before trusting a best price.
How much margin each bookmaker builds in
Turn each price into an implied probability with 1 / odds and add them up per bookmaker. A fair book over the whole field sums to 1.00; anything above that is the bookmaker's margin, which in outright markets is much larger than on a single match:
implied = 1 / winner.dropna(subset=["odds"]).groupby(["bookmaker", "label"])["odds"].first()
margin = implied.groupby("bookmaker").agg(golfers="count", total="sum").round(2)
print(margin.sort_values("golfers", ascending=False)) golfers total
bookmaker
DraftKings 98 1.70
FanDuel 88 1.58
Paddy Power 88 1.55
BetMGM 83 1.56
Betfair Exchange 83 1.20
William Hill 82 1.65
Bet365 55 1.43
Kalshi 38 0.92The sportsbooks that list most of the field sum to between 1.43 and 1.70, so a large share of every Winner price is margin. The Betfair Exchange comes in at 1.20 over 83 golfers. Kalshi totals 0.92 only because it lists 38 golfers: the longshots it leaves out would push it over 1.00. Count the golfers before comparing totals, or compare books on the same set of names.
Top 10 and Top 10 (Incl. Ties)
Top 5, 10 and 20 come in two versions. The plain market settles a tie on the boundary by dead heat rules, so part of the stake is lost. The Incl. Ties market pays ties in full and is priced shorter. Five months out, Bet365 is the only one of these bookmakers with a Top 10 market on the Masters, so this sample uses the PGA Tour event that was in play when we ran it:
pga = client.get_outrights(sport="golf", league="pga-tour")
week = next(t for t in pga if t["bookmakerCount"] > 0)
week_df = outright_odds_to_dataframe(client.get_outright_odds(week["id"], books))
top10 = week_df[week_df["market"].isin(["Top 10", "Top 10 (Incl. Ties)"])]
pair = top10.pivot_table(index=["label", "bookmaker"], columns="market", values="odds").dropna()
golfer = pair.index.get_level_values("label")[0]
print(week["name"], golfer)
print(pair.loc[golfer])World Wide Technology Championship 2026 Adam Svensson
market Top 10 Top 10 (Incl. Ties)
bookmaker
DraftKings 19.0 14.25
FanDuel 26.0 16.00The same golfer is 19.0 to finish in the top 10 at DraftKings under dead heat rules and 14.25 with ties paid in full. Comparing a Top 10 price at one bookmaker with a Top 10 (Incl. Ties) price at another would make the first look far better than it is. The dropna() keeps only bookmakers that price both versions for that golfer.
After the tournament
get_outright_results returns each golfer's final position, whether they made the cut, and the winners of every market as lists of participantIds. This is the Mexico Open, the first tournament settled through the API:
results = client.get_outright_results(1000)
print(results["name"], results["status"])
print(results["results"][:3])
print({market: len(ids) for market, ids in results["winners"].items()})Mexico Open 2026 settled
[{'label': 'Andrew Novak', 'participantId': 991570904131, 'position': 1, 'tied': False, 'madeCut': True, 'status': 'finished'}, {'label': 'Kristoffer Ventura', 'participantId': 993035649881, 'position': 2, 'tied': True, 'madeCut': True, 'status': 'finished'}, {'label': 'Steven Fisk', 'participantId': 993893124464, 'position': 2, 'tied': True, 'madeCut': True, 'status': 'finished'}]
{'Make Cut': 68, 'Top 10': 10, 'Top 10 (Incl. Ties)': 10, 'Top 20': 22, 'Top 20 (Incl. Ties)': 22, 'Top 5': 5, 'Top 5 (Incl. Ties)': 5, 'Winner': 1}Two golfers tied for second, and the Top 20 list has 22 names because of a tie on the boundary. Since the ids match the odds, settling a position is a membership check: df["participant_id"].isin(results["winners"]["Top 10"]). Dead heat reductions differ by bookmaker, so apply your bookmaker's rule to boundary ties. Until a tournament is settled, results and winners are empty.
FAQ
Can I get golf odds in Python without the SDK?
Yes. The SDK wraps three REST endpoints, /v3/outrights, /v3/outrights/odds and /v3/outrights/results, so requests or any HTTP client works the same way. The outrights guide has the raw requests and responses.
Which golf tournaments can I get odds for?
PGA Tour, DP World Tour and LIV Golf individual stroke-play events, and the four majors: the Masters, the PGA Championship, the U.S. Open and The Open. Majors are usually priced months ahead.
How do I match golfers across bookmakers?
Use participantId. It is the same for a golfer at every bookmaker and in the results, and label is the name as listed in /v3/participants, whatever spelling the bookmaker uses.
Is there historical golf odds data?
Not yet. The endpoints serve current prices only, so store the responses yourself if you want a price history.
Next steps
The Golf Outrights API page lists all 47 bookmakers with the markets each one prices and the tournaments priced now. The outrights guide has every parameter and error code.





