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.
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 |
| Player Round Results | No | No | Yes |
| Player Round Stats | No | No | Yes |
| Player Season Stats | No | No | Yes |
| Player Scorecards | 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
}
},
{
"id": 46,
"season": 2025,
"name": "Sony Open in Hawaii",
"start_date": "2025-01-08T19:00:00.000Z",
"end_date": "Jan 9 - 12",
"city": "Honolulu",
"state": "Hawaii",
"country": "United States of America",
"course_name": "Waialae Country Club",
"purse": "$8,700,000",
"status": "IN_PROGRESS",
"champion": null
}
],
"meta": {
"next_cursor": 46,
"per_page": 2
}
}
This endpoint retrieves PGA Tour tournaments.
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']
print(f"{result['position']} - {player['display_name']}: {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
},
"position": "1",
"position_numeric": 1,
"total_score": 257,
"par_relative_score": -35
},
{
"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
},
{
"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
}
],
"meta": {
"next_cursor": 809,
"per_page": 3
}
}
This endpoint retrieves tournament leaderboards and final results. 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) |
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": 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,
"hole_number": 1,
"par": 4,
"score": 4
},
{
"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": 213,
"first_name": "Nick",
"last_name": "Taylor",
"display_name": "Nick Taylor",
"country": "Canada",
"country_code": "CAN",
"active": true
},
"round_number": 1,
"hole_number": 1,
"par": 4,
"score": 4
},
{
"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": 223,
"first_name": "Jhonattan",
"last_name": "Vegas",
"display_name": "Jhonattan Vegas",
"country": "Venezuela",
"country_code": "VEN",
"active": true
},
"round_number": 1,
"hole_number": 1,
"par": 4,
"score": 4
}
],
"meta": {
"next_cursor": 316408,
"per_page": 3
}
}
This endpoint retrieves hole-by-hole player scores for specific rounds. 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) |