WHS Handicap Integration
Use slope rating and course rating from UK Golf API scorecards to calculate WHS handicap differentials for any round played at a UK course.
How WHS handicaps work
The World Handicap System (WHS) uses two course-specific numbers to make scores comparable across different courses and tee sets:
Course Rating
The expected score for a scratch golfer on that course. Typically 68–76 depending on difficulty.
tee_set.course_ratingSlope Rating
How much harder the course is for a bogey golfer vs a scratch golfer. Scale 55–155, standard is 113.
tee_set.slope_ratingThe formula
WHS Handicap Differential:
113 is the standard slope rating (par for the formula)
Example
Gross: 85 · Course Rating: 71.2 · Slope: 126
Differential = (85 − 71.2) × 113 ÷ 126 = 12.4
Data availability
Not all courses in the UK Golf API have slope/course rating data — this requires official measurement by the national golf union. Coverage breakdown:
GolfCourseAPI source
Slope: High (directly from GCA)
CR: High
LLM-extracted courses
Slope: Medium (scraped from websites)
CR: Medium
Always check tee_set.slope_rating != null before calculating. Fall back to the club's website or the WHS API for official values.
Single round differential
// Combine UK Golf API scorecard data with WHS handicap calculation
// The WHS formula uses: Handicap Differential = (Adjusted Gross Score - Course Rating) × 113 / Slope Rating
async function calculateHandicapDifferential({
grossScore,
courseId,
teeColour = 'white',
}) {
const headers = {
'X-RapidAPI-Key': process.env.RAPIDAPI_KEY,
'X-RapidAPI-Host': 'uk-golf-course-data-api.p.rapidapi.com',
};
// Fetch scorecard to get course rating and slope
const res = await fetch(
`https://uk-golf-api.vercel.app/courses/${courseId}/scorecard`,
{ headers }
);
const { data } = await res.json();
// Find the right tee set
const teeSet = data.tee_sets.find(
t => t.name.toLowerCase() === teeColour.toLowerCase()
);
if (!teeSet) {
throw new Error(`No ${teeColour} tee set found`);
}
const { course_rating, slope_rating, par } = teeSet;
if (!course_rating || !slope_rating) {
return {
teeSet,
par,
message: 'Course/slope rating not available for this tee set',
differential: null,
};
}
// WHS Handicap Differential formula
const differential = ((grossScore - course_rating) * 113) / slope_rating;
return {
teeSet,
par,
grossScore,
courseRating: course_rating,
slopeRating: slope_rating,
differential: Math.round(differential * 10) / 10,
};
}
const result = await calculateHandicapDifferential({
grossScore: 85,
courseId: 'YOUR_COURSE_ID',
teeColour: 'white',
});
console.log(`Course: ${result.teeSet.name} tees`);
console.log(`Par: ${result.par}, Course Rating: ${result.courseRating}, Slope: ${result.slopeRating}`);
console.log(`Gross: ${result.grossScore}, Differential: ${result.differential}`);import requests
import math
API_KEY = "YOUR_API_KEY"
HEADERS = {
"X-RapidAPI-Key": API_KEY,
"X-RapidAPI-Host": "uk-golf-course-data-api.p.rapidapi.com",
}
def calculate_handicap_differential(
gross_score: int,
course_id: str,
tee_colour: str = "white",
) -> dict:
"""Calculate WHS handicap differential using UK Golf API scorecard data."""
# Fetch scorecard
res = requests.get(
f"https://uk-golf-api.vercel.app/courses/{course_id}/scorecard",
headers=HEADERS,
)
scorecard = res.json()["data"]
# Find tee set by colour
tee_set = next(
(t for t in scorecard["tee_sets"]
if t["name"].lower() == tee_colour.lower()),
None
)
if not tee_set:
raise ValueError(f"No {tee_colour} tee set found")
course_rating = tee_set.get("course_rating")
slope_rating = tee_set.get("slope_rating")
par = tee_set["par"]
if not course_rating or not slope_rating:
return {
"par": par,
"message": "Course/slope rating not available",
"differential": None,
}
# WHS formula: (Adjusted Gross - Course Rating) × 113 / Slope
differential = ((gross_score - course_rating) * 113) / slope_rating
return {
"tee_colour": tee_colour,
"par": par,
"gross_score": gross_score,
"course_rating": course_rating,
"slope_rating": slope_rating,
"differential": round(differential, 1),
"net_score": gross_score - (par - 72), # simple net score
}
result = calculate_handicap_differential(85, "YOUR_COURSE_ID", "white")
print(f"Gross: {result['gross_score']}, Par: {result['par']}")
print(f"Course Rating: {result['course_rating']}, Slope: {result['slope_rating']}")
print(f"Handicap Differential: {result['differential']}")Calculate handicap index from multiple rounds
The WHS handicap index uses the best differentials from recent rounds. Here's how to calculate it from an array of differentials:
// Calculate handicap index from last 20 rounds (WHS method)
// Best 8 of last 20 differentials, multiplied by 0.96
function calculateHandicapIndex(differentials) {
if (differentials.length < 3) {
return { error: 'Need at least 3 rounds' };
}
// Sort ascending, take best 8 of last 20
const sorted = [...differentials].sort((a, b) => a - b);
const count = differentials.length;
// WHS adjustment table
const useBest = count >= 20 ? 8
: count >= 17 ? 7
: count >= 14 ? 6
: count >= 11 ? 5
: count >= 9 ? 4
: count >= 7 ? 3
: count >= 5 ? 2
: 1;
const best = sorted.slice(0, useBest);
const avg = best.reduce((a, b) => a + b, 0) / best.length;
const index = Math.round(avg * 0.96 * 10) / 10;
return { handicapIndex: index, usedRounds: useBest, differentials: best };
}Important note
This tutorial implements the handicap differential formula for educational purposes. For official WHS handicap records, use the WHS system or your national golf union's official platform. The UK Golf API provides the course/slope data needed as inputs to WHS calculations.
Next steps
- → Build a club profile page to display the slope/course rating data
- → Find courses near the user to let them pick which course to score at