Access golf course data programmatically using our REST API. Base URL: https://teeradar.online/api/v1
All API requests require an API key. Include your key in the request header:
X-API-Key: tr_your_api_key_here
Or as a query parameter: ?api_key=tr_your_api_key_here
Create an account to get your free API key.
Two limits apply to every key: a per-minute burst limit and a daily limit. Daily counters reset at 00:00 UTC.
When you hit a limit, responses return 429 Too Many Requests with a Retry-After header (seconds) and a JSON body explaining whether you tripped the minute or daily limit.
All successful responses are application/json; charset=utf-8. Every response — success or error — includes a request_id field and an X-Request-Id header. Quote that ID in any support email so we can find the request in logs.
| Header | Description |
|---|---|
X-Request-Id | Unique 16-char ID for this request. Quote in support. |
X-RateLimit-Limit | Your daily request limit on the current tier. |
X-RateLimit-Remaining | Remaining daily requests after this call. |
Retry-After | On 429: seconds to wait before retrying. |
https://teeradar.online/media/courses/abc.jpg). You can use them directly in <img> tags without prefixing.
Search and filter golf courses. Results are paginated.
| Parameter | Type | Description |
|---|---|---|
q | string | Search query (name, city, country) |
country | string | Filter by country |
state | string | Filter by state/region |
min_holes | integer | Minimum number of holes |
min_rating | float | Minimum rating (1-5) |
min_length | integer | Minimum yardage |
max_length | integer | Maximum yardage |
has_reviews | boolean | Only courses with reviews |
limit | integer | Results per page (1-100, default 50) |
offset | integer | Skip first N results |
total, limit, offset, count, has_more, and next_offset. Keep calling with offset=next_offset until has_more is false.
Example Request:
curl -H "X-API-Key: YOUR_KEY" \ "https://teeradar.online/api/v1/courses.php?country=United%20States&min_rating=4&limit=10"Response:
{
"total": 459,
"limit": 10,
"offset": 0,
"count": 10,
"has_more": true,
"next_offset": 10,
"courses": [
{
"course_id": "1027616",
"slug": "pebble-beach-golf-links-pebble-beach-golf-links-course",
"name": "Pebble Beach Golf Links - Pebble Beach Golf Links Course",
"city": "Pebble Beach",
"state": "California",
"country": "United States",
"rating": 4.99,
"ratings_count": 47,
"holes": 18,
"length_yards": 6828,
"description": "...",
"tee_times_url": "https://...",
"primary_image": "https://teeradar.online/media/courses/abc123.jpg",
"difficulty_class": "Championship"
}
],
"request_id": "a1b2c3d4e5f60718"
}
Get detailed information for a single course. You can look up by either the numeric course_id or the human-readable slug — pass one of:
| Parameter | Type | Description |
|---|---|---|
slug | string | Human-readable identifier (e.g. st-andrews-links). Recommended. |
id | string | Numeric course_id (e.g. -1996). For backwards compatibility we also accept a slug here and fall back to slug lookup if the numeric ID isn't found. |
curl -H "X-API-Key: YOUR_KEY" \ "https://teeradar.online/api/v1/course.php?slug=st-andrews-links"Example (by course_id):
curl -H "X-API-Key: YOUR_KEY" \ "https://teeradar.online/api/v1/course.php?id=-1996"
First search via /api/v1/courses.php to discover valid course_id / slug values, then call this endpoint.
List all countries with course counts.
Response:{
"count": 45,
"countries": [
{"country": "United States", "count": 17421},
{"country": "England", "count": 1556}
],
"request_id": "..."
}
List states/regions for a country with course counts.
| Parameter | Type | Description |
|---|---|---|
country required | string | Country name |
Get ranked course lists.
| Parameter | Type | Description |
|---|---|---|
type | string | top_rated, most_reviewed, or longest (default: top_rated) |
limit | integer | Number of results (1-100, default 50) |
min_reviews | integer | For top_rated: minimum review count (default 5) |
The table below describes which fields you can rely on for the lifetime of API v1. We will not silently drop or rename fields marked guaranteed within v1 — see Versioning for our deprecation policy.
| Field | Type | Status | Notes |
|---|---|---|---|
course_id | string | guaranteed | Stable numeric primary key returned as a string (e.g. "-1996", "1027616"). Use this for long-term storage and lookups. |
slug | string | guaranteed | URL-safe human-readable identifier (e.g. st-andrews-links). May change if a course is renamed — prefer course_id for storage, slug for URLs. |
name | string | guaranteed | Display name. Defaults to "Unnamed course" if unknown. |
city | string | guaranteed | May be empty string ("") when unknown — never null. |
state | string | guaranteed | State / province / region. May be empty string. |
country | string | guaranteed | Country name in English. May be empty string. |
rating | float | null | nullable | Aggregate rating 1.0–5.0. null when no reviews exist. |
ratings_count | integer | guaranteed | Always present. 0 when no reviews exist. |
holes | integer | null | nullable | Typically 9 or 18. null when unknown. |
length_yards | integer | null | nullable | Total yardage from the back tees. null when unknown. |
description | string | guaranteed | May be empty string. Plain text, not HTML. |
tee_times_url | string | null | nullable | Absolute outbound URL for booking. May be null. |
primary_image | string | null | nullable | Absolute image URL. null if no image available. |
difficulty_class | string | guaranteed | One of: Beginner, Intermediate, Advanced, Championship. Defaults to Intermediate. |
/api/v1/course.php)| Field | Type | Status | Notes |
|---|---|---|---|
latitude / longitude | float | null | nullable | WGS84 coordinates. Use both or neither. |
address, postal_code, phone | string | null | nullable | Contact data. Presence varies by source. |
images | array<string> | nullable | Gallery URLs (absolute). May be empty or absent. |
par, slope, course_rating, year_built, seasonality | varies | null | nullable | Optional facts. Treat any missing key as null. |
Rule of thumb: assume any field marked nullable can be null or absent. For guaranteed fields, the key will always be present in the response.
The API returns standard HTTP status codes. Errors always return JSON with at minimum: error (human message), status (HTTP code), and request_id.
| Code | Meaning |
|---|---|
200 | Success |
400 | Bad request (missing/invalid parameters) |
401 | Unauthorized (missing or invalid API key) |
404 | Resource not found |
429 | Rate limit exceeded — see Retry-After header |
500 | Server error — retry; if persistent, contact support with request_id |
{
"error": "Per-minute rate limit exceeded.",
"status": 429,
"reason": "minute",
"daily_limit": 100,
"daily_used": 42,
"minute_limit": 10,
"minute_used": 10,
"retry_after_seconds": 60,
"reset": "midnight UTC",
"request_id": "a1b2c3d4e5f60718"
}
All endpoints live under /api/v1/. Within v1:
Deprecation response header.Use of the TeeRadar API is subject to our Terms and Conditions, with the following API-specific terms:
https://teeradar.online, unless your plan includes a white-label option.