PGA API
Welcome to the BALLDONTLIE PGA API, your comprehensive source for PGA Tour data. This API provides access to player information, tournament results, course details, leaderboards, round-by-round statistics, strokes gained metrics, and detailed scorecards. An API key is required. You can obtain an API key by creating a free account on our website. Read the authentication section to learn how to use the API key.
Take a look at our other APIs.
Join us on discord.
AI-Powered Integration
Using the OpenAPI Specification with AI
Our complete OpenAPI specification allows AI assistants to automatically understand and interact with our API. Simply share the spec URL with your AI assistant and describe what you want to build—the AI will handle the technical implementation.
Getting Started with AI:
- Copy this URL:
https://www.balldontlie.io/openapi.yml - Share it with your preferred AI assistant (ChatGPT, Claude, Gemini, etc.)
- Tell the AI what you want to build (e.g., "Create a dashboard showing FedEx Cup standings")
- The AI will read the OpenAPI spec and write the code for you
Example prompts to try:
- "Using the OpenAPI spec at https://www.balldontlie.io/openapi.yml, show me how to get Scottie Scheffler's tournament results"
- "Read the BALLDONTLIE OpenAPI spec and create a Python script that fetches current PGA Tour leaderboards"
- "Help me understand the available PGA endpoints from this OpenAPI spec: https://www.balldontlie.io/openapi.yml"
This makes it incredibly easy for non-technical users, analysts, and researchers to leverage our PGA data without needing to learn programming from scratch.
Google Sheets Integration
Our Google Sheets integration lets you access all the same data available through our API using simple spreadsheet formulas. Perfect for fantasy sports tracking, betting analysis, and sports research.
Quick Start:
- Get your API key from app.balldontlie.io
- Copy our Google Sheets script
- Paste it into your Google Sheet (Extensions > Apps Script)
- Start using functions in your cells
Example functions:
=BDL_PGA_PLAYERS("Scheffler")- Search for players=BDL_PGA_TOURNAMENTS(2026)- Get tournaments=BDL_PGA_TOURNAMENT_RESULTS(tournamentId)- Get results=BDL_PGA_SCORECARDS(tournamentId)- Get scorecards
For full setup instructions and the complete list of 150+ functions, see our Google Sheets Integration Guide.
Account Tiers
There are three different account tiers which provide you access to different types of data. Visit our website to create an account for free.
Paid tiers do not apply across sports. The tier you purchase for PGA will not automatically be applied to other sports. You can purchase the ALL-ACCESS ($299.99/mo) tier to get access to every endpoint for every sport.
Read the table below to see the breakdown.
| Endpoint | Free | ALL-STAR | GOAT |
|---|---|---|---|
| Players | Yes | Yes | Yes |
| Tournaments | Yes | Yes | Yes |
| Courses | Yes | Yes | Yes |
| Tournament Results | No | Yes | Yes |
| Tournament Course Stats | No | Yes | Yes |
| Course Holes | No | Yes | Yes |
| Tournament Field | No | No | Yes |
| Player Round Results | No | No | Yes |
| Player Round Stats | No | No | Yes |
| Player Season Stats | No | No | Yes |
| Player Scorecards | No | No | Yes |
| Futures | No | No | Yes |
The feature breakdown per tier is shown in the table below.
| Tier | Requests / Min | $USD / mo. |
|---|---|---|
| GOAT | 600 | 39.99 |
| ALL-STAR | 60 | 9.99 |
| Free | 5 | 0 |
Authentication
To authorize, use this code:
curl "api_endpoint_here" -H "Authorization: YOUR_API_KEY"
const response = await fetch("https://api.balldontlie.io/pga/v1/players", {
headers: {
Authorization: "YOUR_API_KEY",
},
});
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/pga/v1/players',
headers={'Authorization': 'YOUR_API_KEY'}
)
if response.status_code == 200:
data = response.json()
print(data)
else:
print(f'Error: {response.status_code}')
Make sure to replace
YOUR_API_KEYwith your API key.
BALLDONTLIE uses API keys to allow access to the API. You can obtain an API key by creating a free account at our website
We expect the API key to be included in all API requests to the server in a header that looks like the following:
Authorization: YOUR_API_KEY
Pagination
This API uses cursor based pagination rather than limit/offset. Endpoints that support pagination will send back responses with a meta key that looks like what is displayed on the right.
{
"meta": {
"next_cursor": 90,
"per_page": 25
}
}
You can use per_page to specify the maximum number of results. It defaults to 25 and doesn't allow values larger than 100.
You can use next_cursor to get the next page of results. Specify it in the request parameters like this: ?cursor=NEXT_CURSOR.
Errors
The API uses the following error codes:
| Error Code | Meaning |
|---|---|
| 401 | Unauthorized - You either need an API key or your account tier does not have access to the endpoint. |
| 400 | Bad Request -- The request is invalid. The request parameters are probably incorrect. |
| 404 | Not Found -- The specified resource could not be found. |
| 406 | Not Acceptable -- You requested a format that isn't json. |
| 429 | Too Many Requests -- You're rate limited. |
| 500 | Internal Server Error -- We had a problem with our server. Try again later. |
| 503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |
Players
Get All Players
curl "https://api.balldontlie.io/pga/v1/players?per_page=2" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/pga/v1/players?per_page=2",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/pga/v1/players',
headers={'Authorization': 'YOUR_API_KEY'},
params={'per_page': 2}
)
players = response.json()['data']
for player in players:
print(f"{player['display_name']} ({player['country']})")
The above command returns JSON structured like this:
{
"data": [
{
"id": 1,
"first_name": "Ludvig",
"last_name": "Åberg",
"display_name": "Ludvig Åberg",
"country": "Sweden",
"country_code": "SWE",
"height": "6'3\"",
"weight": "190",
"birth_date": "Oct 31, 1999",
"birthplace_city": "Eslov",
"birthplace_state": null,
"birthplace_country": "Sweden",
"turned_pro": "2023",
"school": "Texas Tech University",
"residence_city": "Ponte Vedra",
"residence_state": "Florida",
"residence_country": "United States",
"owgr": 18,
"active": true
},
{
"id": 2,
"first_name": "Byeong Hun",
"last_name": "An",
"display_name": "Byeong Hun An",
"country": "Republic of Korea",
"country_code": "KOR",
"height": "6'2\"",
"weight": "240",
"birth_date": "Sep 17, 1991",
"birthplace_city": "Seoul",
"birthplace_state": null,
"birthplace_country": "South Korea",
"turned_pro": "2011",
"school": "University of California-Berkeley",
"residence_city": "Orlando",
"residence_state": "Florida",
"residence_country": "United States",
"owgr": 98,
"active": true
}
],
"meta": {
"next_cursor": 2,
"per_page": 2
}
}
This endpoint retrieves PGA Tour players.
HTTP Request
GET https://api.balldontlie.io/pga/v1/players
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| player_ids | integer[] | No | Filter by player IDs |
| search | string | No | Search players by name |
| first_name | string | No | Filter by first name |
| last_name | string | No | Filter by last name |
| country | string | No | Filter by country |
| active | boolean | No | Filter by active status |
| cursor | integer | No | Pagination cursor |
| per_page | integer | No | Results per page (max 100, default 25) |
Tournaments
Get All Tournaments
curl "https://api.balldontlie.io/pga/v1/tournaments?season=2025&per_page=2" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/pga/v1/tournaments?season=2025&per_page=2",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/pga/v1/tournaments',
headers={'Authorization': 'YOUR_API_KEY'},
params={'season': 2025, 'per_page': 2}
)
tournaments = response.json()['data']
for tournament in tournaments:
print(f"{tournament['name']} - {tournament['start_date']}")
The above command returns JSON structured like this:
{
"data": [
{
"id": 6,
"season": 2025,
"name": "The Sentry",
"start_date": "2025-01-01T19:00:00.000Z",
"end_date": "Jan 2 - 5",
"city": "Kapalua, Maui",
"state": "Hawaii",
"country": "United States of America",
"course_name": "Plantation Course at Kapalua",
"purse": "$20,000,000",
"status": "COMPLETED",
"champion": {
"id": 130,
"first_name": "Hideki",
"last_name": "Matsuyama",
"display_name": "Hideki Matsuyama",
"country": "Japan",
"country_code": "JPN",
"active": true
},
"courses": [
{
"course": {
"id": 56,
"name": "Plantation Course at Kapalua",
"city": "Kapalua, Maui",
"state": "Hawaii",
"country": "USA",
"par": 73
},
"rounds": [1, 2, 3, 4]
}
]
},
{
"id": 3,
"season": 2025,
"name": "The American Express",
"start_date": "2025-01-15T19:00:00.000Z",
"end_date": "Jan 16 - 19",
"city": "La Quinta",
"state": "California",
"country": "United States of America",
"course_name": "Pete Dye Stadium Course",
"purse": "$8,400,000",
"status": "COMPLETED",
"champion": null,
"courses": [
{
"course": {
"id": 53,
"name": "La Quinta Country Club",
"city": "La Quinta",
"state": "California",
"country": "USA",
"par": 72
},
"rounds": [1, 2, 3]
},
{
"course": {
"id": 54,
"name": "Nicklaus Tournament Course",
"city": "La Quinta",
"state": "California",
"country": "USA",
"par": 72
},
"rounds": [1, 2, 3]
},
{
"course": {
"id": 52,
"name": "Pete Dye Stadium Course",
"city": "La Quinta",
"state": "California",
"country": "USA",
"par": 72
},
"rounds": [1, 2, 3, 4]
}
]
}
],
"meta": {
"next_cursor": 46,
"per_page": 2
}
}
This endpoint retrieves PGA Tour tournaments. The courses array shows which courses are used in each tournament and which rounds they're played on. Multi-course tournaments (like The American Express) will have multiple entries where players rotate between courses during the first few rounds before converging on the final course for round 4.
HTTP Request
GET https://api.balldontlie.io/pga/v1/tournaments
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tournament_ids | integer[] | No | Filter by tournament IDs |
| season | integer | No | Filter by season year |
| status | string | No | Filter by status (COMPLETED, IN_PROGRESS, SCHEDULED) |
| cursor | integer | No | Pagination cursor |
| per_page | integer | No | Results per page (max 100, default 25) |
Courses
Get All Courses
curl "https://api.balldontlie.io/pga/v1/courses?per_page=2" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/pga/v1/courses?per_page=2",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/pga/v1/courses',
headers={'Authorization': 'YOUR_API_KEY'},
params={'per_page': 2}
)
courses = response.json()['data']
for course in courses:
print(f"{course['name']} - Par {course['par']}, {course['yardage']} yards")
The above command returns JSON structured like this:
{
"data": [
{
"id": 1,
"name": "TPC River Highlands",
"city": "Cromwell",
"state": "Connecticut",
"country": "USA",
"par": 70,
"yardage": "6,844",
"established": "1928",
"architect": "Robert J. Ross/Maurice Kearney",
"fairway_grass": "Creeping Bentgrass/Poa Annua",
"rough_grass": "Bluegrass/Ryegrass",
"green_grass": "Poa annua"
},
{
"id": 2,
"name": "Tiburón Golf Club",
"city": "Naples",
"state": "Florida",
"country": "USA",
"par": 72,
"yardage": "7,382",
"established": "1998",
"architect": "Greg Norman",
"fairway_grass": "Bermudagrass",
"rough_grass": null,
"green_grass": "Bermudagrass"
}
],
"meta": {
"next_cursor": 2,
"per_page": 2
}
}
This endpoint retrieves golf courses used in PGA Tour events.
HTTP Request
GET https://api.balldontlie.io/pga/v1/courses
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| course_ids | integer[] | No | Filter by course IDs |
| search | string | No | Search courses by name |
| cursor | integer | No | Pagination cursor |
| per_page | integer | No | Results per page (max 100, default 25) |
Tournament Results
Get Tournament Results
curl "https://api.balldontlie.io/pga/v1/tournament_results?tournament_ids[]=1201&per_page=3" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/pga/v1/tournament_results?tournament_ids[]=1201&per_page=3",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/pga/v1/tournament_results',
headers={'Authorization': 'YOUR_API_KEY'},
params={'tournament_ids[]': 1201, 'per_page': 3}
)
results = response.json()['data']
for result in results:
player = result['player']
earnings = f"${result['earnings']:,.2f}" if result['earnings'] else "N/A"
print(f"{result['position']} - {player['display_name']}: {result['par_relative_score']} ({earnings})")
The above command returns JSON structured like this:
{
"data": [
{
"tournament": {
"id": 6,
"season": 2025,
"name": "The Sentry",
"start_date": "2025-01-01T19:00:00.000Z",
"end_date": "Jan 2 - 5",
"status": "COMPLETED"
},
"player": {
"id": 130,
"first_name": "Hideki",
"last_name": "Matsuyama",
"display_name": "Hideki Matsuyama",
"country": "Japan",
"country_code": "JPN",
"active": true
},
"position": "1",
"position_numeric": 1,
"total_score": 257,
"par_relative_score": -35,
"earnings": 3600000
},
{
"tournament": {
"id": 6,
"season": 2025,
"name": "The Sentry",
"start_date": "2025-01-01T19:00:00.000Z",
"end_date": "Jan 2 - 5",
"status": "COMPLETED"
},
"player": {
"id": 142,
"first_name": "Collin",
"last_name": "Morikawa",
"display_name": "Collin Morikawa",
"country": "United States",
"country_code": "USA",
"active": true
},
"position": "2",
"position_numeric": 2,
"total_score": 260,
"par_relative_score": -32,
"earnings": 2160000
},
{
"tournament": {
"id": 6,
"season": 2025,
"name": "The Sentry",
"start_date": "2025-01-01T19:00:00.000Z",
"end_date": "Jan 2 - 5",
"status": "COMPLETED"
},
"player": {
"id": 93,
"first_name": "Sungjae",
"last_name": "Im",
"display_name": "Sungjae Im",
"country": "Republic of Korea",
"country_code": "KOR",
"active": true
},
"position": "3",
"position_numeric": 3,
"total_score": 263,
"par_relative_score": -29,
"earnings": 1360000
}
],
"meta": {
"next_cursor": 809,
"per_page": 3
}
}
This endpoint retrieves tournament leaderboards and final results, including prize money earnings in USD. Requires ALL-STAR tier or higher.
HTTP Request
GET https://api.balldontlie.io/pga/v1/tournament_results
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tournament_ids | integer[] | No | Filter by tournament IDs |
| player_ids | integer[] | No | Filter by player IDs |
| season | integer | No | Filter by season year |
| cursor | integer | No | Pagination cursor |
| per_page | integer | No | Results per page (max 100, default 25) |
Tournament Course Stats
Get Tournament Course Stats
curl "https://api.balldontlie.io/pga/v1/tournament_course_stats?tournament_ids[]=1201&per_page=3" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/pga/v1/tournament_course_stats?tournament_ids[]=1201&per_page=3",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/pga/v1/tournament_course_stats',
headers={'Authorization': 'YOUR_API_KEY'},
params={'tournament_ids[]': 1201, 'per_page': 3}
)
stats = response.json()['data']
for stat in stats:
print(f"Hole {stat['hole_number']}: Avg {stat['scoring_average']} (Difficulty Rank: {stat['difficulty_rank']})")
The above command returns JSON structured like this:
{
"data": [
{
"tournament": {
"id": 6,
"season": 2025,
"name": "The Sentry",
"start_date": "2025-01-01T19:00:00.000Z",
"end_date": "Jan 2 - 5",
"status": "COMPLETED"
},
"course": {
"id": 56,
"name": "Plantation Course at Kapalua",
"city": "Kapalua, Maui",
"state": "Hawaii",
"country": "USA",
"par": 73
},
"hole_number": 1,
"round_number": null,
"scoring_average": 4.111,
"scoring_diff": 0.111,
"difficulty_rank": 1,
"eagles": 0,
"birdies": 17,
"pars": 178,
"bogeys": 38,
"double_bogeys": 1
},
{
"tournament": {
"id": 6,
"season": 2025,
"name": "The Sentry",
"start_date": "2025-01-01T19:00:00.000Z",
"end_date": "Jan 2 - 5",
"status": "COMPLETED"
},
"course": {
"id": 56,
"name": "Plantation Course at Kapalua",
"city": "Kapalua, Maui",
"state": "Hawaii",
"country": "USA",
"par": 73
},
"hole_number": 1,
"round_number": 4,
"scoring_average": 4.103,
"scoring_diff": 0.103,
"difficulty_rank": 1,
"eagles": 0,
"birdies": 4,
"pars": 44,
"bogeys": 10,
"double_bogeys": 0
},
{
"tournament": {
"id": 6,
"season": 2025,
"name": "The Sentry",
"start_date": "2025-01-01T19:00:00.000Z",
"end_date": "Jan 2 - 5",
"status": "COMPLETED"
},
"course": {
"id": 56,
"name": "Plantation Course at Kapalua",
"city": "Kapalua, Maui",
"state": "Hawaii",
"country": "USA",
"par": 73
},
"hole_number": 1,
"round_number": 3,
"scoring_average": 4.051,
"scoring_diff": 0.051,
"difficulty_rank": 1,
"eagles": 0,
"birdies": 5,
"pars": 46,
"bogeys": 8,
"double_bogeys": 0
}
],
"meta": {
"next_cursor": 4843,
"per_page": 3
}
}
This endpoint retrieves hole-by-hole statistics for tournaments, including scoring averages, difficulty rankings, and score distribution. Requires ALL-STAR tier or higher.
HTTP Request
GET https://api.balldontlie.io/pga/v1/tournament_course_stats
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tournament_ids | integer[] | No | Filter by tournament IDs |
| course_ids | integer[] | No | Filter by course IDs |
| hole_number | integer | No | Filter by hole number (1-18) |
| round_number | integer | No | Filter by round number (1-4) |
| cursor | integer | No | Pagination cursor |
| per_page | integer | No | Results per page (max 100, default 25) |
Course Holes
Get Course Holes
curl "https://api.balldontlie.io/pga/v1/course_holes?course_ids[]=45&per_page=3" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/pga/v1/course_holes?course_ids[]=45&per_page=3",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/pga/v1/course_holes',
headers={'Authorization': 'YOUR_API_KEY'},
params={'course_ids[]': 45, 'per_page': 3}
)
holes = response.json()['data']
for hole in holes:
print(f"Hole {hole['hole_number']}: Par {hole['par']}, {hole['yardage']} yards")
The above command returns JSON structured like this:
{
"data": [
{
"course": {
"id": 1,
"name": "TPC River Highlands",
"city": "Cromwell",
"state": "Connecticut",
"country": "USA",
"par": 70
},
"hole_number": 1,
"par": 4,
"yardage": 434
},
{
"course": {
"id": 1,
"name": "TPC River Highlands",
"city": "Cromwell",
"state": "Connecticut",
"country": "USA",
"par": 70
},
"hole_number": 2,
"par": 4,
"yardage": 341
},
{
"course": {
"id": 1,
"name": "TPC River Highlands",
"city": "Cromwell",
"state": "Connecticut",
"country": "USA",
"par": 70
},
"hole_number": 3,
"par": 4,
"yardage": 431
}
],
"meta": {
"next_cursor": 3,
"per_page": 3
}
}
This endpoint retrieves hole-by-hole course information including par and yardage. Requires ALL-STAR tier or higher.
HTTP Request
GET https://api.balldontlie.io/pga/v1/course_holes
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| course_ids | integer[] | No | Filter by course IDs |
| hole_number | integer | No | Filter by hole number (1-18) |
| cursor | integer | No | Pagination cursor |
| per_page | integer | No | Results per page (max 100, default 25) |
Tournament Field
Get Tournament Field
curl "https://api.balldontlie.io/pga/v1/tournament_field?tournament_id=6&per_page=3" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/pga/v1/tournament_field?tournament_id=6&per_page=3",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/pga/v1/tournament_field',
headers={'Authorization': 'YOUR_API_KEY'},
params={'tournament_id': 6, 'per_page': 3}
)
entries = response.json()['data']
for entry in entries:
player = entry['player']
status = entry['entry_status']
qualifier = entry['qualifier'] or 'N/A'
print(f"{player['display_name']} ({status}) - {qualifier}")
The above command returns JSON structured like this:
{
"data": [
{
"id": 11245,
"tournament": {
"id": 6,
"season": 2025,
"name": "The Sentry",
"start_date": "2025-01-01T19:00:00.000Z",
"end_date": "Jan 2 - 5",
"city": "Kapalua, Maui",
"state": "Hawaii",
"country": "United States of America",
"course_name": "Plantation Course at Kapalua",
"purse": "$20,000,000",
"status": "COMPLETED",
"champion": {
"id": 130,
"first_name": "Hideki",
"last_name": "Matsuyama",
"display_name": "Hideki Matsuyama",
"country": "Japan",
"country_code": "JPN",
"active": true
}
},
"player": {
"id": 186,
"first_name": "Xander",
"last_name": "Schauffele",
"display_name": "Xander Schauffele",
"country": "United States",
"country_code": "USA",
"active": true
},
"entry_status": "IN",
"qualifier": "Current Tournament Winners",
"owgr": 2,
"is_amateur": false
},
{
"id": 11239,
"tournament": {
"id": 6,
"season": 2025,
"name": "The Sentry",
"start_date": "2025-01-01T19:00:00.000Z",
"end_date": "Jan 2 - 5",
"city": "Kapalua, Maui",
"state": "Hawaii",
"country": "United States of America",
"course_name": "Plantation Course at Kapalua",
"purse": "$20,000,000",
"status": "COMPLETED",
"champion": {
"id": 130,
"first_name": "Hideki",
"last_name": "Matsuyama",
"display_name": "Hideki Matsuyama",
"country": "Japan",
"country_code": "JPN",
"active": true
}
},
"player": {
"id": 142,
"first_name": "Collin",
"last_name": "Morikawa",
"display_name": "Collin Morikawa",
"country": "United States",
"country_code": "USA",
"active": true
},
"entry_status": "IN",
"qualifier": "Top 50 on Prior Year's FedExCup Points List",
"owgr": 4,
"is_amateur": false
},
{
"id": 11235,
"tournament": {
"id": 6,
"season": 2025,
"name": "The Sentry",
"start_date": "2025-01-01T19:00:00.000Z",
"end_date": "Jan 2 - 5",
"city": "Kapalua, Maui",
"state": "Hawaii",
"country": "United States of America",
"course_name": "Plantation Course at Kapalua",
"purse": "$20,000,000",
"status": "COMPLETED",
"champion": {
"id": 130,
"first_name": "Hideki",
"last_name": "Matsuyama",
"display_name": "Hideki Matsuyama",
"country": "Japan",
"country_code": "JPN",
"active": true
}
},
"player": {
"id": 130,
"first_name": "Hideki",
"last_name": "Matsuyama",
"display_name": "Hideki Matsuyama",
"country": "Japan",
"country_code": "JPN",
"active": true
},
"entry_status": "IN",
"qualifier": "Current Tournament Winners",
"owgr": 5,
"is_amateur": false
}
],
"meta": {
"next_cursor": 11235,
"per_page": 3
}
}
This endpoint retrieves the tournament field (player entries) for a specific tournament. Use this to see who is playing in upcoming or current tournaments, including their entry status and qualification method. Results are sorted by Official World Golf Ranking (OWGR). Requires GOAT tier.
HTTP Request
GET https://api.balldontlie.io/pga/v1/tournament_field
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tournament_id | integer | Yes | Tournament ID to get field for |
| entry_status | string | No | Filter by status: IN, WITHDRAWN, ALTERNATE |
| cursor | integer | No | Pagination cursor |
| per_page | integer | No | Results per page (max 100, default 25) |
Entry Status Values
| Status | Description |
|---|---|
| IN | Player is confirmed to play |
| WITHDRAWN | Player has withdrawn from the tournament |
| ALTERNATE | Player is on the alternate list |
Player Round Results
Get Player Round Results
curl "https://api.balldontlie.io/pga/v1/player_round_results?tournament_ids[]=1201&player_ids[]=5467" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/pga/v1/player_round_results?tournament_ids[]=1201&player_ids[]=5467",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/pga/v1/player_round_results',
headers={'Authorization': 'YOUR_API_KEY'},
params={'tournament_ids[]': 1201, 'player_ids[]': 5467}
)
results = response.json()['data']
for result in results:
print(f"Round {result['round_number']}: {result['score']} ({result['par_relative_score']})")
The above command returns JSON structured like this:
{
"data": [
{
"tournament": {
"id": 6,
"season": 2025,
"name": "The Sentry",
"start_date": "2025-01-01T19:00:00.000Z",
"end_date": "Jan 2 - 5",
"status": "COMPLETED"
},
"player": {
"id": 130,
"first_name": "Hideki",
"last_name": "Matsuyama",
"display_name": "Hideki Matsuyama",
"country": "Japan",
"country_code": "JPN",
"active": true
},
"round_number": 1,
"score": 65,
"par_relative_score": -8
},
{
"tournament": {
"id": 6,
"season": 2025,
"name": "The Sentry",
"start_date": "2025-01-01T19:00:00.000Z",
"end_date": "Jan 2 - 5",
"status": "COMPLETED"
},
"player": {
"id": 142,
"first_name": "Collin",
"last_name": "Morikawa",
"display_name": "Collin Morikawa",
"country": "United States",
"country_code": "USA",
"active": true
},
"round_number": 1,
"score": 66,
"par_relative_score": -7
},
{
"tournament": {
"id": 6,
"season": 2025,
"name": "The Sentry",
"start_date": "2025-01-01T19:00:00.000Z",
"end_date": "Jan 2 - 5",
"status": "COMPLETED"
},
"player": {
"id": 93,
"first_name": "Sungjae",
"last_name": "Im",
"display_name": "Sungjae Im",
"country": "Republic of Korea",
"country_code": "KOR",
"active": true
},
"round_number": 1,
"score": 69,
"par_relative_score": -4
}
],
"meta": {
"next_cursor": 11698,
"per_page": 3
}
}
This endpoint retrieves round-by-round player scores. Requires GOAT tier.
HTTP Request
GET https://api.balldontlie.io/pga/v1/player_round_results
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tournament_ids | integer[] | No | Filter by tournament IDs |
| player_ids | integer[] | No | Filter by player IDs |
| round_number | integer | No | Filter by round number (1-4) |
| season | integer | No | Filter by season year |
| cursor | integer | No | Pagination cursor |
| per_page | integer | No | Results per page (max 100, default 25) |
Player Round Stats
Get Player Round Stats
curl "https://api.balldontlie.io/pga/v1/player_round_stats?tournament_ids[]=1201&player_ids[]=5467&round_number=-1" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/pga/v1/player_round_stats?tournament_ids[]=1201&player_ids[]=5467&round_number=-1",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/pga/v1/player_round_stats',
headers={'Authorization': 'YOUR_API_KEY'},
params={'tournament_ids[]': 1201, 'player_ids[]': 5467, 'round_number': -1}
)
stats = response.json()['data']
for stat in stats:
print(f"SG Total: {stat['sg_total']}")
print(f"SG Off Tee: {stat['sg_off_tee']}")
print(f"SG Approach: {stat['sg_approach']}")
print(f"SG Putting: {stat['sg_putting']}")
The above command returns JSON structured like this:
{
"data": [
{
"tournament": {
"id": 6,
"season": 2025,
"name": "The Sentry",
"start_date": "2025-01-01T19:00:00.000Z",
"end_date": "Jan 2 - 5",
"status": "COMPLETED"
},
"player": {
"id": 189,
"first_name": "Adam",
"last_name": "Scott",
"display_name": "Adam Scott",
"country": "Australia",
"country_code": "AUS",
"active": true
},
"round_number": -1,
"sg_off_tee": -1.26,
"sg_off_tee_rank": 46,
"sg_approach": 3.792,
"sg_approach_rank": 9,
"sg_around_green": 1.427,
"sg_around_green_rank": 10,
"sg_putting": 0.019,
"sg_putting_rank": 28,
"sg_total": 3.978,
"sg_total_rank": 15,
"driving_accuracy": 60,
"driving_accuracy_rank": 46,
"driving_distance": 282.4,
"driving_distance_rank": 27,
"longest_drive": 375,
"longest_drive_rank": 54,
"greens_in_regulation": 81.94,
"greens_in_regulation_rank": 27,
"sand_saves": 33.33,
"sand_saves_rank": 24,
"scrambling": 46.15,
"scrambling_rank": 48,
"putts_per_gir": 1.64,
"putts_per_gir_rank": 10,
"eagles": null,
"birdies": 29,
"pars": 35,
"bogeys": 8,
"double_bogeys": null
}
],
"meta": {
"next_cursor": 33023,
"per_page": 1
}
}
This endpoint retrieves detailed player round statistics including strokes gained metrics, driving accuracy, greens in regulation, and more. Use round_number=-1 for tournament totals. Requires GOAT tier.
HTTP Request
GET https://api.balldontlie.io/pga/v1/player_round_stats
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tournament_ids | integer[] | No | Filter by tournament IDs |
| player_ids | integer[] | No | Filter by player IDs |
| round_number | integer | No | Filter by round number (1-4, -1 for tournament total) |
| season | integer | No | Filter by season year |
| cursor | integer | No | Pagination cursor |
| per_page | integer | No | Results per page (max 100, default 25) |
Player Season Stats
Get Player Season Stats
curl "https://api.balldontlie.io/pga/v1/player_season_stats?player_ids[]=5467&season=2024&per_page=5" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/pga/v1/player_season_stats?player_ids[]=5467&season=2024&per_page=5",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/pga/v1/player_season_stats',
headers={'Authorization': 'YOUR_API_KEY'},
params={'player_ids[]': 5467, 'season': 2024, 'per_page': 5}
)
stats = response.json()['data']
for stat in stats:
print(f"{stat['stat_name']}: Rank {stat['rank']}")
The above command returns JSON structured like this:
{
"data": [
{
"player": {
"id": 185,
"first_name": "Scottie",
"last_name": "Scheffler",
"display_name": "Scottie Scheffler",
"country": "United States",
"country_code": "USA",
"active": true
},
"stat_id": 8,
"stat_name": "SG: Total",
"stat_category": "STROKES_GAINED",
"season": 2025,
"rank": 1,
"stat_value": [
{ "statName": "Avg", "statValue": "2.743" },
{ "statName": "Total SG:T", "statValue": "197.507" },
{ "statName": "Total SG:T2G", "statValue": "169.995" },
{ "statName": "Total SG:P", "statValue": "27.512" },
{ "statName": "Measured Rounds", "statValue": "72" }
]
},
{
"player": {
"id": 185,
"first_name": "Scottie",
"last_name": "Scheffler",
"display_name": "Scottie Scheffler",
"country": "United States",
"country_code": "USA",
"active": true
},
"stat_id": 9,
"stat_name": "SG: Tee-to-Green",
"stat_category": "STROKES_GAINED",
"season": 2025,
"rank": 1,
"stat_value": [
{ "statName": "Avg", "statValue": "2.361" },
{ "statName": "SG:OTT", "statValue": "0.748" },
{ "statName": "SG:APR", "statValue": "1.291" },
{ "statName": "SG:ARG", "statValue": "0.322" },
{ "statName": "Measured Rounds", "statValue": "72" }
]
},
{
"player": {
"id": 31,
"first_name": "Pierceson",
"last_name": "Coody",
"display_name": "Pierceson Coody",
"country": "United States",
"country_code": "USA",
"active": true
},
"stat_id": 10,
"stat_name": "SG: Off-the-Tee",
"stat_category": "STROKES_GAINED",
"season": 2025,
"rank": 1,
"stat_value": [
{ "statName": "Avg", "statValue": "0.789" },
{ "statName": "Total SG:OTT", "statValue": "26.812" },
{ "statName": "Measured Rounds", "statValue": "34" }
]
}
],
"meta": {
"next_cursor": 20770,
"per_page": 3
}
}
This endpoint retrieves player season-level statistics across various categories. Requires GOAT tier.
HTTP Request
GET https://api.balldontlie.io/pga/v1/player_season_stats
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| player_ids | integer[] | No | Filter by player IDs |
| season | integer | No | Filter by season year |
| stat_ids | integer[] | No | Filter by stat IDs |
| cursor | integer | No | Pagination cursor |
| per_page | integer | No | Results per page (max 100, default 25) |
Available Stat Categories
There are 493 different statistics available, organized into the following categories:
| Category | Description | Example Stats |
|---|---|---|
| STROKES_GAINED | Strokes gained metrics | SG: Total, SG: Tee-to-Green, SG: Off-the-Tee, SG: Approach the Green, SG: Around-the-Green, SG: Putting |
| OFF_TEE | Driving statistics | Driving Distance, Driving Accuracy Percentage, Club Head Speed, Ball Speed, Launch Angle |
| APPROACH_GREEN | Approach shot metrics | Approach from various distances (50-275+ yards), Greens in Regulation |
| AROUND_GREEN | Short game statistics | Sand Save Percentage, Scrambling, Up and Down Percentage |
| PUTTING | Putting metrics | Putts per Round, 3-Putt Avoidance, Putting from various distances |
| SCORING | Scoring statistics | Scoring Average, Birdie Average, Par Breakers, Final Round Scoring |
| MONEY_FINISHES | Earnings and finishes | Official Money, Top 10 Finishes, Wins |
| POINTS_RANKINGS | Rankings and points | FedEx Cup Points, World Golf Ranking |
| STREAKS | Consecutive statistics | Consecutive Cuts Made, Consecutive Birdies |
Player Scorecards
Get Player Scorecards
curl "https://api.balldontlie.io/pga/v1/player_scorecards?tournament_ids[]=1201&player_ids[]=5467&round_number=1&per_page=3" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/pga/v1/player_scorecards?tournament_ids[]=1201&player_ids[]=5467&round_number=1&per_page=3",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/pga/v1/player_scorecards',
headers={'Authorization': 'YOUR_API_KEY'},
params={'tournament_ids[]': 1201, 'player_ids[]': 5467, 'round_number': 1, 'per_page': 3}
)
scorecard = response.json()['data']
for hole in scorecard:
print(f"Hole {hole['hole_number']}: {hole['score']} (Par {hole['par']})")
The above command returns JSON structured like this:
{
"data": [
{
"tournament": {
"id": 8,
"season": 2026,
"name": "The American Express",
"start_date": "2026-01-22T00:00:00.000Z",
"end_date": "Jan 22 - 25",
"status": "COMPLETED",
"courses": [
{
"course": { "id": 53, "name": "La Quinta Country Club" },
"rounds": [1, 2, 3]
},
{
"course": { "id": 54, "name": "Nicklaus Tournament Course" },
"rounds": [1, 2, 3]
},
{
"course": { "id": 52, "name": "Pete Dye Stadium Course" },
"rounds": [1, 2, 3, 4]
}
]
},
"player": {
"id": 65,
"first_name": "Emiliano",
"last_name": "Grillo",
"display_name": "Emiliano Grillo",
"country": "Argentina",
"country_code": "ARG",
"active": true
},
"course": {
"id": 54,
"name": "Nicklaus Tournament Course",
"city": "La Quinta",
"state": "California",
"country": "USA",
"par": 72
},
"round_number": 1,
"hole_number": 1,
"par": 4,
"score": 5
},
{
"tournament": {
"id": 8,
"season": 2026,
"name": "The American Express",
"start_date": "2026-01-22T00:00:00.000Z",
"end_date": "Jan 22 - 25",
"status": "COMPLETED"
},
"player": {
"id": 23,
"first_name": "Bud",
"last_name": "Cauley",
"display_name": "Bud Cauley",
"country": "United States",
"country_code": "USA",
"active": true
},
"course": {
"id": 53,
"name": "La Quinta Country Club",
"city": "La Quinta",
"state": "California",
"country": "USA",
"par": 72
},
"round_number": 1,
"hole_number": 1,
"par": 4,
"score": 4
}
],
"meta": {
"next_cursor": 36868975,
"per_page": 2
}
}
This endpoint retrieves hole-by-hole player scores for specific rounds. The course field indicates which course the player played for that round—this is especially useful for multi-course tournaments (like The American Express) where different players play different courses on the same day. Requires GOAT tier.
HTTP Request
GET https://api.balldontlie.io/pga/v1/player_scorecards
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| tournament_ids | integer[] | No | Filter by tournament IDs |
| player_ids | integer[] | No | Filter by player IDs |
| round_number | integer | No | Filter by round number (1-4) |
| hole_number | integer | No | Filter by hole number (1-18) |
| cursor | integer | No | Pagination cursor |
| per_page | integer | No | Results per page (max 100, default 25) |
Futures
Get Futures Odds
curl "https://api.balldontlie.io/pga/v1/futures?vendors[]=fanduel&per_page=2" \
-H "Authorization: YOUR_API_KEY"
const response = await fetch(
"https://api.balldontlie.io/pga/v1/futures?vendors[]=fanduel&per_page=2",
{
headers: {
Authorization: "YOUR_API_KEY",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.balldontlie.io/pga/v1/futures',
headers={'Authorization': 'YOUR_API_KEY'},
params={'vendors[]': 'fanduel', 'per_page': 2}
)
futures = response.json()['data']
for f in futures:
player = f['player']
tournament = f['tournament']
print(f"{player['display_name']} - {tournament['name']}: {f['american_odds']} ({f['vendor']})")
The above command returns JSON structured like this:
{
"data": [
{
"id": 98747717,
"market_type": "tournament_winner",
"market_name": "2026 Masters Tournament",
"player": {
"id": 185,
"first_name": "Scottie",
"last_name": "Scheffler",
"display_name": "Scottie Scheffler",
"country": "United States",
"country_code": "USA",
"height": "6'3\"",
"weight": "200",
"birth_date": "Jun 21, 1996",
"birthplace_city": "Ridgewood",
"birthplace_state": "New Jersey",
"birthplace_country": "United States",
"turned_pro": "2018",
"school": "University of Texas",
"residence_city": "Dallas",
"residence_state": "Texas",
"residence_country": "United States",
"owgr": 1,
"active": true
},
"tournament": {
"id": 20,
"season": 2026,
"name": "Masters Tournament",
"start_date": "2026-04-09T00:00:00.000Z",
"end_date": "Apr 9 - 12",
"city": "Augusta",
"state": "Georgia",
"country": "United States of America",
"course_name": "Augusta National Golf Club",
"purse": "$0",
"status": "NOT_STARTED",
"champion": null,
"courses": []
},
"vendor": "fanduel",
"american_odds": 280,
"updated_at": "2026-02-19T10:19:02.827Z"
},
{
"id": 98747718,
"market_type": "tournament_winner",
"market_name": "2026 Masters Tournament",
"player": {
"id": 134,
"first_name": "Rory",
"last_name": "McIlroy",
"display_name": "Rory McIlroy",
"country": "Northern Ireland",
"country_code": "NIR",
"height": "5'10\"",
"weight": "160",
"birth_date": "May 4, 1989",
"birthplace_city": "Holywood",
"birthplace_state": null,
"birthplace_country": "Northern Ireland",
"turned_pro": "2007",
"school": null,
"residence_city": "Holywood",
"residence_state": null,
"residence_country": "Northern Ireland",
"owgr": 2,
"active": true
},
"tournament": {
"id": 20,
"season": 2026,
"name": "Masters Tournament",
"start_date": "2026-04-09T00:00:00.000Z",
"end_date": "Apr 9 - 12",
"city": "Augusta",
"state": "Georgia",
"country": "United States of America",
"course_name": "Augusta National Golf Club",
"purse": "$0",
"status": "NOT_STARTED",
"champion": null,
"courses": []
},
"vendor": "fanduel",
"american_odds": 700,
"updated_at": "2026-02-19T10:19:02.827Z"
}
],
"meta": {
"next_cursor": 98747718,
"per_page": 2
}
}
This endpoint retrieves futures betting odds for PGA tournaments. Currently includes tournament winner odds from multiple sportsbooks. Requires GOAT tier.
HTTP Request
GET https://api.balldontlie.io/pga/v1/futures
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| player_ids | integer[] | No | Filter by player IDs |
| tournament_ids | integer[] | No | Filter by tournament IDs |
| vendors | string[] | No | Filter by sportsbook vendors (e.g., fanduel, draftkings) |
| cursor | integer | No | Pagination cursor |
| per_page | integer | No | Results per page (max 100, default 25) |
Available Vendors
| Vendor | Description |
|---|---|
| fanduel | FanDuel |
| draftkings | DraftKings |
| betmgm | BetMGM |
| betrivers | BetRivers |
| bovada | Bovada |