4 min read

Build a driver comparison page with stable club IDs

Save the drivers a user picks by clb_ id, fetch them by id, compare variants instead of lofts_deg and hands, and keep a saved club that returns 404.

Two cards, each showing an angle, sit side by side, connected by their stable IDs.

If you build a club comparison, save each club's id and compare its variants. Names and slugs can change, and lofts_deg and hands don't tell you which loft comes in which hand. The responses below come from a test key, which reads a fixed sample of drivers.

List drivers for the user to choose from

Ask the drivers list for the fields a picker shows. id is always returned:

Shell
curl 'https://api.golfapi.dev/drivers?fields=id,name,manufacturer,lofts_deg,hands&limit=4' \
  -H "Authorization: Bearer $GOLFDEV_API_KEY"

Run export GOLFDEV_API_KEY='sk_test_…' with your key in the same terminal first. Leave $GOLFDEV_API_KEY as written; the shell replaces it with your key. How to set your key

Response with a test key on 3 November 2026. The three Srixon records have no published lofts or hands yet, so a picker shows those columns as Not published:

JSON
{
  "data": [
    {
      "id": "clb_01M5CT01FAVETRE90QN4TMTKQG",
      "name": "ZXi RKT LS Driver",
      "manufacturer": { "slug": "srixon", "name": "Srixon" }
    },
    {
      "id": "clb_01M5CT01FAK1D58Y0453W8332H",
      "name": "ZXi RKT Max Driver",
      "manufacturer": { "slug": "srixon", "name": "Srixon" }
    },
    {
      "id": "clb_01M5CT01F9R5SE2Q3ADS9TZBR1",
      "name": "ZXi RKT Driver",
      "manufacturer": { "slug": "srixon", "name": "Srixon" }
    },
    {
      "id": "clb_01M5CT01EDR83NWM5TFT9DZRXF",
      "name": "JPX ONE SELECT Driver",
      "manufacturer": { "slug": "mizuno", "name": "Mizuno" },
      "lofts_deg": [9, 10.5],
      "hands": ["rh", "lh"]
    }
  ],
  "page": { "limit": 4, "has_more": true, "catalog_complete": false, "next": "cur_eyJ5IjoyMDI2…" }
}

Do not build an identifier from the name the user types.

Save the driver id

When the user adds a driver to a comparison, store its id (clb_…). The id never changes. The slug can change when a name is corrected, and two drivers can have similar names. The test sample and the live catalog use different ids, so pick clubs again after you switch to a live key.

Fetch a saved driver by id; that request never redirects:

Shell
curl 'https://api.golfapi.dev/drivers/clb_01M21M6KHQSKX3MQ0SA1HYNGSZ?fields=id,slug,name,lofts_deg,hands,adjustable_hosel' \
  -H "Authorization: Bearer $GOLFDEV_API_KEY"
JSON
{
  "id": "clb_01M21M6KHQSKX3MQ0SA1HYNGSZ",
  "slug": "gt1-driver",
  "name": "GT1 Driver",
  "lofts_deg": [9, 10, 12],
  "hands": ["rh", "lh"],
  "adjustable_hosel": true
}

Compare driver variants

lofts_deg and hands are summaries across a driver's variants. Combining them can describe a club that is not sold. The Qi4D Driver lists lofts 8, 9, 10.5 and 12 and hands rh and lh, but its variants show that the 8° head is right-handed only:

Shell
curl 'https://api.golfapi.dev/drivers/clb_01M21M6ZEF7DKNPK28F4ZC79ZX?fields=id,name,variants' \
  -H "Authorization: Bearer $GOLFDEV_API_KEY"
JSON
{
  "id": "clb_01M21M6ZEF7DKNPK28F4ZC79ZX",
  "name": "Qi4D Driver",
  "variants": [
    { "id": "var_01M21M6ZM5RB7JDJ0BV3FHYBQR", "hand": "rh", "market": "US", "loft_deg": 8 },
    { "id": "var_01M21M6ZMPMYWZJEYAJ3QWTJMA", "hand": "rh", "market": "US", "loft_deg": 9 },
    { "id": "var_01M21M6ZN7CPK9BV39FN55DDEQ", "hand": "rh", "market": "US", "loft_deg": 10.5 },
    { "id": "var_01M21M6ZNQS6ZFECM34TNT3K16", "hand": "rh", "market": "US", "loft_deg": 12 },
    { "id": "var_01M21M6ZRZFD7AM155NDDCHHSZ", "hand": "lh", "market": "US", "loft_deg": 9 },
    { "id": "var_01M21M6ZSF1FVVBQ6ZEY37H9EC", "hand": "lh", "market": "US", "loft_deg": 10.5 },
    { "id": "var_01M21M6ZT056BX9AHVQXFF5R9W", "hand": "lh", "market": "US", "loft_deg": 12 }
  ]
}

Three drivers from the sample, compared by variant:

DriverRight-handed loftsLeft-handed lofts
Qi4D Driver8, 9, 10.5, 129, 10.5, 12
GT1 Driver9, 10, 129, 10, 12
G440 Max Driver9, 10.5, 129, 10.5, 12

A driver variant identifies one hand, loft_deg and market. When a comparison needs a specific head, store the variant id (var_…) as well as the driver id.

A coding agent connected to the MCP server can read the same records while it builds the page. Ask it to "Read the Qi4D Driver and the GT1 Driver and list the lofts each sells in each hand", and it calls get_club once per driver. A Free account's test key answers it, because the sample holds every 2025 and 2026 driver.

Show a missing value as Not published

A field with no published value is absent from the record; show the cell as Not published and keep real false and 0 values. Handle missing specifications covers the three states in code.

Keep a saved driver that no longer resolves

A request for a record the catalog does not carry answers 404:

Shell
curl 'https://api.golfapi.dev/drivers/not-a-driver' \
  -H "Authorization: Bearer $GOLFDEV_API_KEY"
JSON
{
  "error": {
    "type": "not_found",
    "message": "No driver with slug 'not-a-driver'. GET /coverage names every manufacturer and model year the published build carries, and reports `catalog_complete: false`. It counts published records, so it cannot tell a head that was never released from one not yet published.",
    "status": 404,
    "request_id": "req_01M6H0TFG8B8QT6Q58HAJPB7PA"
  }
}

If a saved id starts answering 404, keep it in the user's comparison and mark it unavailable. Do not replace it with a driver that has a similar name. GET /changes lists saved ids that changed or were removed.

More posts

All posts