Skip to main content

yardage-hub-python

A Python client for yardage-hub, an open, crowdsourced database of golf courses: where they are, and their scorecards (holes, par, handicaps, tees, ratings, slopes, yardages). It starts from OpenStreetMap, and golfers fill in the rest.

This README is a quick start. The full API documentation is at lukeheide.com/sports/yardage-hub/docs.

Install

pip install yardage-hub

Python 3.9+, no dependencies.

Get a key

Every call needs a key. Sign in at lukeheide.com, open your profile page, and generate one. It's shown once, so copy it somewhere safe; if you lose it, regenerate it. Free keys allow 1,000 calls a day and 30 a minute.

from yardage_hub import YardageHub

hub = YardageHub("yh_...")   # or set YARDAGE_HUB_KEY and call YardageHub()

Quick start

# Find a course
found = hub.search_courses("pebble beach", state="CA")
course = hub.get_course(found["courses"][0]["id"])

print(course["course_name"], course["par"])
for tee in course["tee_sets"]:
    print(tee["tee_name"], tee["yardage"], [(r["gender"], r["course_rating"], r["slope"]) for r in tee["ratings"]])
for hole in course["holes_data"]:
    print(hole["number"], hole["par"], hole["handicap_index"], hole["yardages"])

# Courses near a point (km)
near = hub.search_courses(lat=42.28, lon=-83.74, radius_km=10)

# Courses that need help from contributors near you
help = hub.courses_needing_help(lat=42.28, lon=-83.74, radius_km=25)
for c in help["courses"]:
    print(c["course_name"], [n["need"] for n in c["needs"]])

Name search forgives abbreviations, punctuation, and typos: "st johns", "mt pleasant", and "pebel beach" all find what you mean.

Methods

Method What it does
search_courses(q, state, lat, lon, radius_km, kinds, page, page_size) Search by name, state, or distance. kinds defaults to ["course", "par3"]; also practice, disc, mini
get_course(course_id) One course: holes, tees and ratings, links, completeness. None for an unknown id
course_edits(course_id, page_size, contributor_ref) A course's edit history, newest first
courses_needing_help(state, lat, lon, radius_km, needs, page, page_size) Courses missing something a contributor can add, by state or near a point
submit_edit(course_id, payload, note, evidence_url, contributor_ref, contributor_name) Propose a change (contact details, holes, tees, ratings, yardages, scorecard link)
vote_edit(edit_id, vote, reason, contributor_ref, contributor_name) Back (1) or doubt (-1) a pending edit, or remove your vote (0)
report_link(course_id, field, url, works, contributor_ref, contributor_name) Confirm a website or scorecard_url works, or report it dead
report_course(course_id, kind, note, evidence_url, contributor_ref, contributor_name) Report a scorecard as scorecard_changed, numbers_wrong, or other

Each method returns the API's JSON as Python dicts and lists. The fields are described in the docs.

Writing: apply for write access

Every key can read. The last four methods send data to a review queue, and a person reviews every edit, so they need a key with write access. New keys don't have it; a key without it gets a 403.

  1. Contribute on the site first. Suggest edits on course pages at lukeheide.com/sports/yardage-hub.
  2. Once 5 of your edits are approved, apply on your profile page. Say what you'll write, e.g. "building an app that lets people suggest edits".
  3. The maintainer reviews the application. Once it's granted, your key can call the write methods.

Write access can be taken back. After a denial or revocation, you can apply again in 30 days.

An edit looks like this:

hub.submit_edit(course_id, {
    "course": {"phone": "(415) 561-4661", "scorecard_url": "https://example.com/scorecard.pdf"},
    "holes": [{"number": 1, "par": 4, "handicap": 7}],
    "tees": [{"name": "Blue", "color": "blue", "gender": "M", "rating": 70.8, "slope": 132,
              "yardages": {"1": 512, "2": 410}}],
}, note="From the 2026 scorecard")

It's validated right away (a bad payload raises a 400) and waits as pending until it's reviewed.

Errors

A failed call raises YardageHubError, with status, message, and retry_after (seconds, after a 429):

from yardage_hub import YardageHubError

try:
    hub.submit_edit(course_id, {"course": {"phone": "555-0100"}})
except YardageHubError as e:
    if e.status == 403:
        print("This key is read-only: apply for write access on your profile page")
    elif e.status == 429:
        print(f"Over a limit; retry in {e.retry_after} s")
    else:
        raise
Status Meaning
400 Invalid input; the message says what
401 Missing, wrong, or revoked key
403 A read-only key tried to write
404 Unknown course or edit
429 Over the daily or per-minute limit

Data and license

The data contains information from OpenStreetMap, © OpenStreetMap contributors, and is available under the ODbL. Credit it wherever you show it: "© OpenStreetMap contributors, yardage-hub". For the whole dataset, download the weekly snapshots from lukhed/yardage-hub-data; please don't harvest it through the API.

This client is MIT licensed.

Metadata

Release files for yardage-hub 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for yardage-hub 0.1.0
File Size Uploaded
yardage_hub-0.1.0.tar.gz 8.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for yardage-hub 0.1.0
File Interpreter ABI Platform
yardage_hub-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 15.2 kB

Release files / yardage_hub-0.1.0.tar.gz

Download URL yardage_hub-0.1.0.tar.gz
Size 8.1 kB
Tags Source
SHA-256 checksum
How to use checksums
47c6ef3a47e5c6f1701434d62374ad2273adf083f2fe7a1c01d442ad1e2bef83
BLAKE2b-256 checksum
How to use checksums
45ec5c0de8e658d4625c9b0629adef6627d4ef25eab2991e7ce7b8f5004291f8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.2

Release files / yardage_hub-0.1.0-py3-none-any.whl

Download URL yardage_hub-0.1.0-py3-none-any.whl
Size 7.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
29519a5145ec672813adb08900a5ccc964e34446f88f27e71933e62f0aa3137f
BLAKE2b-256 checksum
How to use checksums
b6ada403677252deb06fde7dc3ae40d447a66d575b0122cca831e44dc5570867
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.2

Release history Release notifications | RSS feed

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page