{"openapi":"3.1.0","info":{"title":"GolfAPI.dev club catalog","version":"0.41.0.0","description":"Read-only catalog of golf clubs and the components they are built from. Every endpoint is a GET. Authentication is a bearer key whose entitlements decide which resources and which document depth it may read. `Golfapi-Version` names the response shape by date. One version is served, it is every Golfapi-Version default in this document, and any other date is 400. `info.version` is this document's own release number and is not a shape date -- the two never need to agree. Requests are rate-limited to 60 per key per 60-second wall-clock window by default; `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` are set after a key enters an authenticated resource chain, including its 403 and 429 responses; a key's own cap can differ, a 304 and any other 4xx except 429 are refunded and report the refunded budget, and `GET /` names the default under `rate_limit` without carrying those headers. This document defines the current response contract. Free reads sandbox data. Hobby reads specs (view=core) for every club. Pro adds launch prices (view=market). Club-builder (view=expanded) is available on Enterprise."},"servers":[{"url":"https://api.golfapi.dev","description":"Production. A live-mode key (sk_live_) reads the published catalog; a test-mode key (sk_test_) reads the sandbox branch through the same URLs."}],"security":[{"bearerAuth":[]}],"paths":{"/":{"get":{"operationId":"getIndex","summary":"Discovery index","description":"Public discovery of resource paths, publication, authentication and the supported response version. An accepted bearer key can also supply account access details; discovery does not require a key.","security":[],"parameters":[],"responses":{"200":{"description":"The index.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Index"}}}}},"x-fern-sdk-group-name":"service","x-fern-sdk-method-name":"index","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsIndex","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/health":{"get":{"operationId":"getHealth","summary":"Service health","description":"Database reachability and catalog presence. Unauthenticated. 503 names what an operator must do: `missing` is a migration to apply, `unservable` is a build to publish.","security":[],"parameters":[],"responses":{"200":{"description":"Every registered resource can be served.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}},"503":{"description":"The database is unreachable or unconfigured, or a registered resource cannot be served.","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}}},"x-fern-sdk-group-name":"service","x-fern-sdk-method-name":"health","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsHealth","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/openapi.json":{"get":{"operationId":"getOpenapi","summary":"This document","description":"The machine-readable API contract. Public; no API key is required.","security":[],"parameters":[],"responses":{"200":{"description":"This OpenAPI document.","content":{"application/json":{"schema":{"type":"object"}}}}},"x-fern-sdk-group-name":"service","x-fern-sdk-method-name":"openapi","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsOpenapiJson","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/.well-known/openapi.json":{"get":{"operationId":"getOpenapiWellKnown","summary":"OpenAPI discovery alias","description":"Alias of /openapi.json with the same public API contract. No API key is required.","security":[],"parameters":[],"responses":{"200":{"description":"This OpenAPI document.","content":{"application/json":{"schema":{"type":"object"}}}}},"x-fern-sdk-group-name":"service","x-fern-sdk-method-name":"openapi-well-known","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsWellKnownOpenapiJson","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/docs":{"get":{"operationId":"getDocs","summary":"Rendered reference","description":"HTML rendering of the OpenAPI contract. Public; no API key is required. Read the response as text or open it in a browser.","security":[],"parameters":[],"responses":{"200":{"description":"An HTML page.","content":{"text/html":{"schema":{"type":"string"}}}}},"x-fern-sdk-group-name":"service","x-fern-sdk-method-name":"docs","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsDocs","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/drivers":{"get":{"operationId":"listDrivers","summary":"List drivers","description":"Filters combine with AND. No matches returns data: []. Unknown or repeated query parameters return 400. Results are ordered by release_year descending, then club ID descending; q orders by relevance first. Core is the default unless view or fields selects another permitted document.","parameters":[{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core, expanded or market. Core is the default unless fields selects another document. The legacy token basic is accepted as core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). Missing access returns 403. Read Golfapi-View for the document served.","schema":{"type":"string","enum":["core","expanded","market"],"default":"core"}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields from one response document. id is always returned. Without an explicit view, a Club-builder field selects expanded and intro_price selects market. Missing club-builder or market access returns 403; market (intro_price) needs the Pro plan. An unknown field, a field outside an explicit view, or a selection mixing Club-builder and Market fields returns 400.","schema":{"type":"string","minLength":1}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"Opaque pagination token from page.next. Send it unchanged on the same resource, with the same filters, served version and key access. Page size may change between requests. On a cursor 400, restart the scan.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}},{"name":"manufacturer","in":"query","required":false,"description":"Manufacturer slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"family","in":"query","required":false,"description":"Family slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"hand","in":"query","required":false,"description":"Offered hand.","schema":{"type":"string","enum":["rh","lh"]}},{"name":"designation","in":"query","required":false,"description":"Heads whose designations includes this value. Each model is returned once. An empty result means no matching published record; an omitted designations field has no published classification.","schema":{"type":"string","enum":["womens","junior"]}},{"name":"loft","in":"query","required":false,"description":"Nominal loft in degrees. The value must occur in the requested collection; otherwise the API returns 400 with that collection’s published lofts. A loft available only in another collection is invalid here. With hand, both must match the same variant: hand=lh&loft=10.5 returns clubs sold left-handed at 10.5 degrees.","schema":{"type":"string","pattern":"^\\d{1,2}(\\.\\d)?$"}},{"name":"adjustable_hosel","in":"query","required":false,"description":"Whether the hosel adjusts.","schema":{"type":"string","enum":["true","false"]}},{"name":"release_year","in":"query","required":false,"description":"Release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"release_year_after","in":"query","required":false,"description":"Inclusive earliest release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"release_year_before","in":"query","required":false,"description":"Inclusive latest release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"released_after","in":"query","required":false,"description":"Inclusive earliest exact retail date. Matches only records with an exact `released` date; a record that carries only `release_year` never matches. A window whose start is later than released_before is 400: the two parameters contradict each other, which is not the same answer as a window that merely matches nothing.","schema":{"type":"string","format":"date"}},{"name":"released_before","in":"query","required":false,"description":"Inclusive latest exact retail date. Matches only records with an exact `released` date. Equal bounds are a legal one-day window.","schema":{"type":"string","format":"date"}},{"name":"msrp_min","in":"query","required":false,"description":"Inclusive lowest launch MSRP in the market `msrp_market` names (US when absent), in that currency's minor units: 50000 is $500 in the US and Y50,000 in JP, since JPY has no minor unit. A club with no launch price in that market never matches. Pro plan: needs the 'market' entitlement (403 without it), on any view. Greater than msrp_max is 400.","schema":{"type":"integer","minimum":0,"maximum":999999999}},{"name":"msrp_max","in":"query","required":false,"description":"Inclusive highest launch MSRP in the market `msrp_market` names (US when absent), in that currency's minor units: 50000 is $500 in the US and Y50,000 in JP. A club with no launch price in that market never matches. Pro plan: needs the 'market' entitlement (403 without it), on any view.","schema":{"type":"integer","minimum":0,"maximum":999999999}},{"name":"msrp_market","in":"query","required":false,"description":"ISO 3166-1 alpha-2 market whose `intro_price` entry msrp_min and msrp_max compare, in its own currency; US when absent. Prices are never converted between currencies. Alone, it keeps the clubs with a launch price in that market. A market the published catalog has no price in is 400, naming the markets it prices. Pro plan: needs the 'market' entitlement (403 without it).","schema":{"type":"string","pattern":"^[A-Z]{2}$"}},{"name":"q","in":"query","required":false,"description":"Search names, manufacturers, families, and generated aliases. Case and accents are folded. The full-text branch combines tokens with AND, while prefix, alias, and similarity matches can add rows that do not contain every token. A non-empty page does not identify a club; fetch a chosen hit with GET /{resource}/{id-or-slug}. Control characters are invalid.","schema":{"type":"string","minLength":1,"maxLength":200}}],"responses":{"200":{"description":"A page of clubs.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CoreClubList"},{"$ref":"#/components/schemas/ExpandedClubList"},{"$ref":"#/components/schemas/MarketClubList"}]}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"drivers","x-fern-sdk-method-name":"list","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsDrivers","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/drivers/{ref}":{"get":{"operationId":"getDriver","summary":"Fetch one driver","description":"Fetch by stable club ID or slug. A historical slug redirects to the current slug with 301. Core is the default unless view or fields selects another permitted document. Read Golfapi-View for the document served.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned clb_ id or a current or historical driver slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core, expanded or market. Core is the default unless fields selects another document. The legacy token basic is accepted as core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). Missing access returns 403. Read Golfapi-View for the document served.","schema":{"type":"string","enum":["core","expanded","market"]}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields from one response document. id is always returned. Without an explicit view, a Club-builder field selects expanded and intro_price selects market. Missing club-builder or market access returns 403; market (intro_price) needs the Pro plan. An unknown field, a field outside an explicit view, or a selection mixing Club-builder and Market fields returns 400.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}},{"name":"variants","in":"query","required":false,"description":"Filter `variants` by hand or nominal loft in Core or Club-builder documents. Market carries no variants.","schema":{"type":"string","pattern":"^(all|rh|lh|\\d{1,2}(\\.\\d)?)$","default":"all"}}],"responses":{"200":{"description":"One club.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CoreClub"},{"$ref":"#/components/schemas/ExpandedClub"},{"$ref":"#/components/schemas/MarketClub"}]}}}},"301":{"description":"A historical slug redirects to the canonical URL. Retain the query string and the same-origin auth and version headers. Live example: GET /drivers/g440-max-2025-driver redirects to /drivers/g440-max-driver.","headers":{"Location":{"schema":{"type":"string","format":"uri","pattern":"^https?://"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"410":{"description":"The club was published and then removed from the catalog. Ids are never reused; GET /changes lists removals.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"drivers","x-fern-sdk-method-name":"get","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsDriversRef","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/drivers/{ref}/hosel":{"get":{"operationId":"getDriverHosel","summary":"Fetch a driver's hosel context","description":"Read the club’s hosel connection and applicable setting charts. Requires the club resource and club-builder entitlements. Returns 503 when no hosel context or signed hosel catalog is published. Unknown query parameters are ignored on this route.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned clb_ id or a current or historical driver slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"hand","in":"query","required":false,"description":"Narrow to one hand.","schema":{"type":"string","enum":["rh","lh"]}},{"name":"market","in":"query","required":false,"description":"Narrow scopes to one market.","schema":{"type":"string","pattern":"^[A-Z]{2}$"}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"The club's hosel context, narrowed to the requested scope.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HoselContext"}}}},"301":{"description":"A historical slug redirects to the canonical URL. Retain the query string and the same-origin auth and version headers. Live example: GET /drivers/g440-max-2025-driver redirects to /drivers/g440-max-driver.","headers":{"Location":{"schema":{"type":"string","format":"uri","pattern":"^https?://"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"drivers","x-fern-sdk-method-name":"hosel","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsDriversRefHosel","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/mini-drivers":{"get":{"operationId":"listMiniDrivers","summary":"List mini drivers","description":"Filters combine with AND. No matches returns data: []. Unknown or repeated query parameters return 400. Results are ordered by release_year descending, then club ID descending; q orders by relevance first. Core is the default unless view or fields selects another permitted document.","parameters":[{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core, expanded or market. Core is the default unless fields selects another document. The legacy token basic is accepted as core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). Missing access returns 403. Read Golfapi-View for the document served.","schema":{"type":"string","enum":["core","expanded","market"],"default":"core"}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields from one response document. id is always returned. Without an explicit view, a Club-builder field selects expanded and intro_price selects market. Missing club-builder or market access returns 403; market (intro_price) needs the Pro plan. An unknown field, a field outside an explicit view, or a selection mixing Club-builder and Market fields returns 400.","schema":{"type":"string","minLength":1}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"Opaque pagination token from page.next. Send it unchanged on the same resource, with the same filters, served version and key access. Page size may change between requests. On a cursor 400, restart the scan.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}},{"name":"manufacturer","in":"query","required":false,"description":"Manufacturer slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"family","in":"query","required":false,"description":"Family slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"hand","in":"query","required":false,"description":"Offered hand.","schema":{"type":"string","enum":["rh","lh"]}},{"name":"designation","in":"query","required":false,"description":"Heads whose designations includes this value. Each model is returned once. An empty result means no matching published record; an omitted designations field has no published classification.","schema":{"type":"string","enum":["womens","junior"]}},{"name":"loft","in":"query","required":false,"description":"Nominal loft in degrees. The value must occur in the requested collection; otherwise the API returns 400 with that collection’s published lofts. A loft available only in another collection is invalid here. With hand, both must match the same variant: hand=lh&loft=10.5 returns clubs sold left-handed at 10.5 degrees.","schema":{"type":"string","pattern":"^\\d{1,2}(\\.\\d)?$"}},{"name":"adjustable_hosel","in":"query","required":false,"description":"Whether the hosel adjusts.","schema":{"type":"string","enum":["true","false"]}},{"name":"release_year","in":"query","required":false,"description":"Release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"release_year_after","in":"query","required":false,"description":"Inclusive earliest release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"release_year_before","in":"query","required":false,"description":"Inclusive latest release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"released_after","in":"query","required":false,"description":"Inclusive earliest exact retail date. Matches only records with an exact `released` date; a record that carries only `release_year` never matches. A window whose start is later than released_before is 400: the two parameters contradict each other, which is not the same answer as a window that merely matches nothing.","schema":{"type":"string","format":"date"}},{"name":"released_before","in":"query","required":false,"description":"Inclusive latest exact retail date. Matches only records with an exact `released` date. Equal bounds are a legal one-day window.","schema":{"type":"string","format":"date"}},{"name":"msrp_min","in":"query","required":false,"description":"Inclusive lowest launch MSRP in the market `msrp_market` names (US when absent), in that currency's minor units: 50000 is $500 in the US and Y50,000 in JP, since JPY has no minor unit. A club with no launch price in that market never matches. Pro plan: needs the 'market' entitlement (403 without it), on any view. Greater than msrp_max is 400.","schema":{"type":"integer","minimum":0,"maximum":999999999}},{"name":"msrp_max","in":"query","required":false,"description":"Inclusive highest launch MSRP in the market `msrp_market` names (US when absent), in that currency's minor units: 50000 is $500 in the US and Y50,000 in JP. A club with no launch price in that market never matches. Pro plan: needs the 'market' entitlement (403 without it), on any view.","schema":{"type":"integer","minimum":0,"maximum":999999999}},{"name":"msrp_market","in":"query","required":false,"description":"ISO 3166-1 alpha-2 market whose `intro_price` entry msrp_min and msrp_max compare, in its own currency; US when absent. Prices are never converted between currencies. Alone, it keeps the clubs with a launch price in that market. A market the published catalog has no price in is 400, naming the markets it prices. Pro plan: needs the 'market' entitlement (403 without it).","schema":{"type":"string","pattern":"^[A-Z]{2}$"}},{"name":"q","in":"query","required":false,"description":"Search names, manufacturers, families, and generated aliases. Case and accents are folded. The full-text branch combines tokens with AND, while prefix, alias, and similarity matches can add rows that do not contain every token. A non-empty page does not identify a club; fetch a chosen hit with GET /{resource}/{id-or-slug}. Control characters are invalid.","schema":{"type":"string","minLength":1,"maxLength":200}}],"responses":{"200":{"description":"A page of clubs.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CoreClubList"},{"$ref":"#/components/schemas/ExpandedClubList"},{"$ref":"#/components/schemas/MarketClubList"}]}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"mini-drivers","x-fern-sdk-method-name":"list","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsMiniDrivers","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/mini-drivers/{ref}":{"get":{"operationId":"getMiniDriver","summary":"Fetch one mini driver","description":"Fetch by stable club ID or slug. A historical slug redirects to the current slug with 301. Core is the default unless view or fields selects another permitted document. Read Golfapi-View for the document served.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned clb_ id or a current or historical mini driver slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core, expanded or market. Core is the default unless fields selects another document. The legacy token basic is accepted as core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). Missing access returns 403. Read Golfapi-View for the document served.","schema":{"type":"string","enum":["core","expanded","market"]}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields from one response document. id is always returned. Without an explicit view, a Club-builder field selects expanded and intro_price selects market. Missing club-builder or market access returns 403; market (intro_price) needs the Pro plan. An unknown field, a field outside an explicit view, or a selection mixing Club-builder and Market fields returns 400.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}},{"name":"variants","in":"query","required":false,"description":"Filter `variants` by hand or nominal loft in Core or Club-builder documents. Market carries no variants.","schema":{"type":"string","pattern":"^(all|rh|lh|\\d{1,2}(\\.\\d)?)$","default":"all"}}],"responses":{"200":{"description":"One club.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CoreClub"},{"$ref":"#/components/schemas/ExpandedClub"},{"$ref":"#/components/schemas/MarketClub"}]}}}},"301":{"description":"A historical slug redirects to the canonical URL. Retain the query string and the same-origin auth and version headers. Live example: GET /drivers/g440-max-2025-driver redirects to /drivers/g440-max-driver.","headers":{"Location":{"schema":{"type":"string","format":"uri","pattern":"^https?://"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"410":{"description":"The club was published and then removed from the catalog. Ids are never reused; GET /changes lists removals.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"mini-drivers","x-fern-sdk-method-name":"get","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsMiniDriversRef","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/mini-drivers/{ref}/hosel":{"get":{"operationId":"getMiniDriverHosel","summary":"Fetch a mini driver's hosel context","description":"Read the club’s hosel connection and applicable setting charts. Requires the club resource and club-builder entitlements. Returns 503 when no hosel context or signed hosel catalog is published. Unknown query parameters are ignored on this route.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned clb_ id or a current or historical mini driver slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"hand","in":"query","required":false,"description":"Narrow to one hand.","schema":{"type":"string","enum":["rh","lh"]}},{"name":"market","in":"query","required":false,"description":"Narrow scopes to one market.","schema":{"type":"string","pattern":"^[A-Z]{2}$"}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"The club's hosel context, narrowed to the requested scope.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HoselContext"}}}},"301":{"description":"A historical slug redirects to the canonical URL. Retain the query string and the same-origin auth and version headers. Live example: GET /drivers/g440-max-2025-driver redirects to /drivers/g440-max-driver.","headers":{"Location":{"schema":{"type":"string","format":"uri","pattern":"^https?://"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"mini-drivers","x-fern-sdk-method-name":"hosel","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsMiniDriversRefHosel","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/fairway-woods":{"get":{"operationId":"listFairwayWoods","summary":"List fairway woods","description":"Filters combine with AND. No matches returns data: []. Unknown or repeated query parameters return 400. Results are ordered by release_year descending, then club ID descending; q orders by relevance first. Core is the default unless view or fields selects another permitted document.","parameters":[{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core, expanded or market. Core is the default unless fields selects another document. The legacy token basic is accepted as core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). Missing access returns 403. Read Golfapi-View for the document served.","schema":{"type":"string","enum":["core","expanded","market"],"default":"core"}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields from one response document. id is always returned. Without an explicit view, a Club-builder field selects expanded and intro_price selects market. Missing club-builder or market access returns 403; market (intro_price) needs the Pro plan. An unknown field, a field outside an explicit view, or a selection mixing Club-builder and Market fields returns 400.","schema":{"type":"string","minLength":1}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"Opaque pagination token from page.next. Send it unchanged on the same resource, with the same filters, served version and key access. Page size may change between requests. On a cursor 400, restart the scan.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}},{"name":"manufacturer","in":"query","required":false,"description":"Manufacturer slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"family","in":"query","required":false,"description":"Family slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"hand","in":"query","required":false,"description":"Offered hand.","schema":{"type":"string","enum":["rh","lh"]}},{"name":"designation","in":"query","required":false,"description":"Heads whose designations includes this value. Each model is returned once. An empty result means no matching published record; an omitted designations field has no published classification.","schema":{"type":"string","enum":["womens","junior"]}},{"name":"loft","in":"query","required":false,"description":"Nominal loft in degrees. The value must occur in the requested collection; otherwise the API returns 400 with that collection’s published lofts. A loft available only in another collection is invalid here. With hand, both must match the same variant: hand=lh&loft=10.5 returns clubs sold left-handed at 10.5 degrees.","schema":{"type":"string","pattern":"^\\d{1,2}(\\.\\d)?$"}},{"name":"adjustable_hosel","in":"query","required":false,"description":"Whether the hosel adjusts.","schema":{"type":"string","enum":["true","false"]}},{"name":"release_year","in":"query","required":false,"description":"Release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"release_year_after","in":"query","required":false,"description":"Inclusive earliest release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"release_year_before","in":"query","required":false,"description":"Inclusive latest release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"released_after","in":"query","required":false,"description":"Inclusive earliest exact retail date. Matches only records with an exact `released` date; a record that carries only `release_year` never matches. A window whose start is later than released_before is 400: the two parameters contradict each other, which is not the same answer as a window that merely matches nothing.","schema":{"type":"string","format":"date"}},{"name":"released_before","in":"query","required":false,"description":"Inclusive latest exact retail date. Matches only records with an exact `released` date. Equal bounds are a legal one-day window.","schema":{"type":"string","format":"date"}},{"name":"msrp_min","in":"query","required":false,"description":"Inclusive lowest launch MSRP in the market `msrp_market` names (US when absent), in that currency's minor units: 50000 is $500 in the US and Y50,000 in JP, since JPY has no minor unit. A club with no launch price in that market never matches. Pro plan: needs the 'market' entitlement (403 without it), on any view. Greater than msrp_max is 400.","schema":{"type":"integer","minimum":0,"maximum":999999999}},{"name":"msrp_max","in":"query","required":false,"description":"Inclusive highest launch MSRP in the market `msrp_market` names (US when absent), in that currency's minor units: 50000 is $500 in the US and Y50,000 in JP. A club with no launch price in that market never matches. Pro plan: needs the 'market' entitlement (403 without it), on any view.","schema":{"type":"integer","minimum":0,"maximum":999999999}},{"name":"msrp_market","in":"query","required":false,"description":"ISO 3166-1 alpha-2 market whose `intro_price` entry msrp_min and msrp_max compare, in its own currency; US when absent. Prices are never converted between currencies. Alone, it keeps the clubs with a launch price in that market. A market the published catalog has no price in is 400, naming the markets it prices. Pro plan: needs the 'market' entitlement (403 without it).","schema":{"type":"string","pattern":"^[A-Z]{2}$"}},{"name":"q","in":"query","required":false,"description":"Search names, manufacturers, families, and generated aliases. Case and accents are folded. The full-text branch combines tokens with AND, while prefix, alias, and similarity matches can add rows that do not contain every token. A non-empty page does not identify a club; fetch a chosen hit with GET /{resource}/{id-or-slug}. Control characters are invalid.","schema":{"type":"string","minLength":1,"maxLength":200}}],"responses":{"200":{"description":"A page of clubs.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CoreClubList"},{"$ref":"#/components/schemas/ExpandedClubList"},{"$ref":"#/components/schemas/MarketClubList"}]}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"fairway-woods","x-fern-sdk-method-name":"list","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsFairwayWoods","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/fairway-woods/{ref}":{"get":{"operationId":"getFairwayWood","summary":"Fetch one fairway wood","description":"Fetch by stable club ID or slug. A historical slug redirects to the current slug with 301. Core is the default unless view or fields selects another permitted document. Read Golfapi-View for the document served.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned clb_ id or a current or historical fairway wood slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core, expanded or market. Core is the default unless fields selects another document. The legacy token basic is accepted as core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). Missing access returns 403. Read Golfapi-View for the document served.","schema":{"type":"string","enum":["core","expanded","market"]}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields from one response document. id is always returned. Without an explicit view, a Club-builder field selects expanded and intro_price selects market. Missing club-builder or market access returns 403; market (intro_price) needs the Pro plan. An unknown field, a field outside an explicit view, or a selection mixing Club-builder and Market fields returns 400.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}},{"name":"variants","in":"query","required":false,"description":"Filter `variants` by hand or nominal loft in Core or Club-builder documents. Market carries no variants.","schema":{"type":"string","pattern":"^(all|rh|lh|\\d{1,2}(\\.\\d)?)$","default":"all"}}],"responses":{"200":{"description":"One club.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CoreClub"},{"$ref":"#/components/schemas/ExpandedClub"},{"$ref":"#/components/schemas/MarketClub"}]}}}},"301":{"description":"A historical slug redirects to the canonical URL. Retain the query string and the same-origin auth and version headers. Live example: GET /drivers/g440-max-2025-driver redirects to /drivers/g440-max-driver.","headers":{"Location":{"schema":{"type":"string","format":"uri","pattern":"^https?://"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"410":{"description":"The club was published and then removed from the catalog. Ids are never reused; GET /changes lists removals.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"fairway-woods","x-fern-sdk-method-name":"get","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsFairwayWoodsRef","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/fairway-woods/{ref}/hosel":{"get":{"operationId":"getFairwayWoodHosel","summary":"Fetch a fairway wood's hosel context","description":"Read the club’s hosel connection and applicable setting charts. Requires the club resource and club-builder entitlements. Returns 503 when no hosel context or signed hosel catalog is published. Unknown query parameters are ignored on this route.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned clb_ id or a current or historical fairway wood slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"hand","in":"query","required":false,"description":"Narrow to one hand.","schema":{"type":"string","enum":["rh","lh"]}},{"name":"market","in":"query","required":false,"description":"Narrow scopes to one market.","schema":{"type":"string","pattern":"^[A-Z]{2}$"}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"The club's hosel context, narrowed to the requested scope.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HoselContext"}}}},"301":{"description":"A historical slug redirects to the canonical URL. Retain the query string and the same-origin auth and version headers. Live example: GET /drivers/g440-max-2025-driver redirects to /drivers/g440-max-driver.","headers":{"Location":{"schema":{"type":"string","format":"uri","pattern":"^https?://"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"fairway-woods","x-fern-sdk-method-name":"hosel","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsFairwayWoodsRefHosel","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/hybrids":{"get":{"operationId":"listHybrids","summary":"List hybrids","description":"Filters combine with AND. No matches returns data: []. Unknown or repeated query parameters return 400. Results are ordered by release_year descending, then club ID descending; q orders by relevance first. Core is the default unless view or fields selects another permitted document.","parameters":[{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core, expanded or market. Core is the default unless fields selects another document. The legacy token basic is accepted as core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). Missing access returns 403. Read Golfapi-View for the document served.","schema":{"type":"string","enum":["core","expanded","market"],"default":"core"}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields from one response document. id is always returned. Without an explicit view, a Club-builder field selects expanded and intro_price selects market. Missing club-builder or market access returns 403; market (intro_price) needs the Pro plan. An unknown field, a field outside an explicit view, or a selection mixing Club-builder and Market fields returns 400.","schema":{"type":"string","minLength":1}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"Opaque pagination token from page.next. Send it unchanged on the same resource, with the same filters, served version and key access. Page size may change between requests. On a cursor 400, restart the scan.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}},{"name":"manufacturer","in":"query","required":false,"description":"Manufacturer slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"family","in":"query","required":false,"description":"Family slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"hand","in":"query","required":false,"description":"Offered hand.","schema":{"type":"string","enum":["rh","lh"]}},{"name":"designation","in":"query","required":false,"description":"Heads whose designations includes this value. Each model is returned once. An empty result means no matching published record; an omitted designations field has no published classification.","schema":{"type":"string","enum":["womens","junior"]}},{"name":"loft","in":"query","required":false,"description":"Nominal loft in degrees. The value must occur in the requested collection; otherwise the API returns 400 with that collection’s published lofts. A loft available only in another collection is invalid here. With hand, both must match the same variant: hand=lh&loft=10.5 returns clubs sold left-handed at 10.5 degrees.","schema":{"type":"string","pattern":"^\\d{1,2}(\\.\\d)?$"}},{"name":"adjustable_hosel","in":"query","required":false,"description":"Whether the hosel adjusts.","schema":{"type":"string","enum":["true","false"]}},{"name":"release_year","in":"query","required":false,"description":"Release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"release_year_after","in":"query","required":false,"description":"Inclusive earliest release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"release_year_before","in":"query","required":false,"description":"Inclusive latest release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"released_after","in":"query","required":false,"description":"Inclusive earliest exact retail date. Matches only records with an exact `released` date; a record that carries only `release_year` never matches. A window whose start is later than released_before is 400: the two parameters contradict each other, which is not the same answer as a window that merely matches nothing.","schema":{"type":"string","format":"date"}},{"name":"released_before","in":"query","required":false,"description":"Inclusive latest exact retail date. Matches only records with an exact `released` date. Equal bounds are a legal one-day window.","schema":{"type":"string","format":"date"}},{"name":"msrp_min","in":"query","required":false,"description":"Inclusive lowest launch MSRP in the market `msrp_market` names (US when absent), in that currency's minor units: 50000 is $500 in the US and Y50,000 in JP, since JPY has no minor unit. A club with no launch price in that market never matches. Pro plan: needs the 'market' entitlement (403 without it), on any view. Greater than msrp_max is 400.","schema":{"type":"integer","minimum":0,"maximum":999999999}},{"name":"msrp_max","in":"query","required":false,"description":"Inclusive highest launch MSRP in the market `msrp_market` names (US when absent), in that currency's minor units: 50000 is $500 in the US and Y50,000 in JP. A club with no launch price in that market never matches. Pro plan: needs the 'market' entitlement (403 without it), on any view.","schema":{"type":"integer","minimum":0,"maximum":999999999}},{"name":"msrp_market","in":"query","required":false,"description":"ISO 3166-1 alpha-2 market whose `intro_price` entry msrp_min and msrp_max compare, in its own currency; US when absent. Prices are never converted between currencies. Alone, it keeps the clubs with a launch price in that market. A market the published catalog has no price in is 400, naming the markets it prices. Pro plan: needs the 'market' entitlement (403 without it).","schema":{"type":"string","pattern":"^[A-Z]{2}$"}},{"name":"q","in":"query","required":false,"description":"Search names, manufacturers, families, and generated aliases. Case and accents are folded. The full-text branch combines tokens with AND, while prefix, alias, and similarity matches can add rows that do not contain every token. A non-empty page does not identify a club; fetch a chosen hit with GET /{resource}/{id-or-slug}. Control characters are invalid.","schema":{"type":"string","minLength":1,"maxLength":200}}],"responses":{"200":{"description":"A page of clubs.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CoreClubList"},{"$ref":"#/components/schemas/ExpandedClubList"},{"$ref":"#/components/schemas/MarketClubList"}]}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"hybrids","x-fern-sdk-method-name":"list","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsHybrids","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/hybrids/{ref}":{"get":{"operationId":"getHybrid","summary":"Fetch one hybrid","description":"Fetch by stable club ID or slug. A historical slug redirects to the current slug with 301. Core is the default unless view or fields selects another permitted document. Read Golfapi-View for the document served.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned clb_ id or a current or historical hybrid slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core, expanded or market. Core is the default unless fields selects another document. The legacy token basic is accepted as core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). Missing access returns 403. Read Golfapi-View for the document served.","schema":{"type":"string","enum":["core","expanded","market"]}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields from one response document. id is always returned. Without an explicit view, a Club-builder field selects expanded and intro_price selects market. Missing club-builder or market access returns 403; market (intro_price) needs the Pro plan. An unknown field, a field outside an explicit view, or a selection mixing Club-builder and Market fields returns 400.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}},{"name":"variants","in":"query","required":false,"description":"Filter `variants` by hand or nominal loft in Core or Club-builder documents. Market carries no variants.","schema":{"type":"string","pattern":"^(all|rh|lh|\\d{1,2}(\\.\\d)?)$","default":"all"}}],"responses":{"200":{"description":"One club.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CoreClub"},{"$ref":"#/components/schemas/ExpandedClub"},{"$ref":"#/components/schemas/MarketClub"}]}}}},"301":{"description":"A historical slug redirects to the canonical URL. Retain the query string and the same-origin auth and version headers. Live example: GET /drivers/g440-max-2025-driver redirects to /drivers/g440-max-driver.","headers":{"Location":{"schema":{"type":"string","format":"uri","pattern":"^https?://"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"410":{"description":"The club was published and then removed from the catalog. Ids are never reused; GET /changes lists removals.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"hybrids","x-fern-sdk-method-name":"get","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsHybridsRef","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/hybrids/{ref}/hosel":{"get":{"operationId":"getHybridHosel","summary":"Fetch a hybrid's hosel context","description":"Read the club’s hosel connection and applicable setting charts. Requires the club resource and club-builder entitlements. Returns 503 when no hosel context or signed hosel catalog is published. Unknown query parameters are ignored on this route.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned clb_ id or a current or historical hybrid slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"hand","in":"query","required":false,"description":"Narrow to one hand.","schema":{"type":"string","enum":["rh","lh"]}},{"name":"market","in":"query","required":false,"description":"Narrow scopes to one market.","schema":{"type":"string","pattern":"^[A-Z]{2}$"}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"The club's hosel context, narrowed to the requested scope.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HoselContext"}}}},"301":{"description":"A historical slug redirects to the canonical URL. Retain the query string and the same-origin auth and version headers. Live example: GET /drivers/g440-max-2025-driver redirects to /drivers/g440-max-driver.","headers":{"Location":{"schema":{"type":"string","format":"uri","pattern":"^https?://"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"hybrids","x-fern-sdk-method-name":"hosel","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsHybridsRefHosel","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/irons":{"get":{"operationId":"listIrons","summary":"List irons","description":"Filters combine with AND. No matches returns data: []. Unknown or repeated query parameters return 400. Results are ordered by release_year descending, then club ID descending; q orders by relevance first. Core is the default unless view or fields selects another permitted document.","parameters":[{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core, expanded or market. Core is the default unless fields selects another document. The legacy token basic is accepted as core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). Missing access returns 403. Read Golfapi-View for the document served.","schema":{"type":"string","enum":["core","expanded","market"],"default":"core"}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields from one response document. id is always returned. Without an explicit view, a Club-builder field selects expanded and intro_price selects market. Missing club-builder or market access returns 403; market (intro_price) needs the Pro plan. An unknown field, a field outside an explicit view, or a selection mixing Club-builder and Market fields returns 400.","schema":{"type":"string","minLength":1}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"Opaque pagination token from page.next. Send it unchanged on the same resource, with the same filters, served version and key access. Page size may change between requests. On a cursor 400, restart the scan.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}},{"name":"manufacturer","in":"query","required":false,"description":"Manufacturer slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"family","in":"query","required":false,"description":"Family slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"hand","in":"query","required":false,"description":"Offered hand.","schema":{"type":"string","enum":["rh","lh"]}},{"name":"designation","in":"query","required":false,"description":"Heads whose designations includes this value. Each model is returned once. An empty result means no matching published record; an omitted designations field has no published classification.","schema":{"type":"string","enum":["womens","junior"]}},{"name":"loft","in":"query","required":false,"description":"Nominal loft in degrees. The value must occur in the requested collection; otherwise the API returns 400 with that collection’s published lofts. A loft available only in another collection is invalid here. With hand, both must match the same variant: hand=lh&loft=10.5 returns clubs sold left-handed at 10.5 degrees.","schema":{"type":"string","pattern":"^\\d{1,2}(\\.\\d)?$"}},{"name":"adjustable_hosel","in":"query","required":false,"description":"Whether the hosel adjusts.","schema":{"type":"string","enum":["true","false"]}},{"name":"release_year","in":"query","required":false,"description":"Release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"release_year_after","in":"query","required":false,"description":"Inclusive earliest release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"release_year_before","in":"query","required":false,"description":"Inclusive latest release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"released_after","in":"query","required":false,"description":"Inclusive earliest exact retail date. Matches only records with an exact `released` date; a record that carries only `release_year` never matches. A window whose start is later than released_before is 400: the two parameters contradict each other, which is not the same answer as a window that merely matches nothing.","schema":{"type":"string","format":"date"}},{"name":"released_before","in":"query","required":false,"description":"Inclusive latest exact retail date. Matches only records with an exact `released` date. Equal bounds are a legal one-day window.","schema":{"type":"string","format":"date"}},{"name":"msrp_min","in":"query","required":false,"description":"Inclusive lowest launch MSRP in the market `msrp_market` names (US when absent), in that currency's minor units: 50000 is $500 in the US and Y50,000 in JP, since JPY has no minor unit. A club with no launch price in that market never matches. Pro plan: needs the 'market' entitlement (403 without it), on any view. Greater than msrp_max is 400.","schema":{"type":"integer","minimum":0,"maximum":999999999}},{"name":"msrp_max","in":"query","required":false,"description":"Inclusive highest launch MSRP in the market `msrp_market` names (US when absent), in that currency's minor units: 50000 is $500 in the US and Y50,000 in JP. A club with no launch price in that market never matches. Pro plan: needs the 'market' entitlement (403 without it), on any view.","schema":{"type":"integer","minimum":0,"maximum":999999999}},{"name":"msrp_market","in":"query","required":false,"description":"ISO 3166-1 alpha-2 market whose `intro_price` entry msrp_min and msrp_max compare, in its own currency; US when absent. Prices are never converted between currencies. Alone, it keeps the clubs with a launch price in that market. A market the published catalog has no price in is 400, naming the markets it prices. Pro plan: needs the 'market' entitlement (403 without it).","schema":{"type":"string","pattern":"^[A-Z]{2}$"}},{"name":"q","in":"query","required":false,"description":"Search names, manufacturers, families, and generated aliases. Case and accents are folded. The full-text branch combines tokens with AND, while prefix, alias, and similarity matches can add rows that do not contain every token. A non-empty page does not identify a club; fetch a chosen hit with GET /{resource}/{id-or-slug}. Control characters are invalid.","schema":{"type":"string","minLength":1,"maxLength":200}}],"responses":{"200":{"description":"A page of irons.","headers":{"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/IronCoreList"},{"$ref":"#/components/schemas/IronExpandedList"},{"$ref":"#/components/schemas/MarketClubList"}]}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"irons","x-fern-sdk-method-name":"list","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsIrons","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/irons/{ref}":{"get":{"operationId":"getIron","summary":"Fetch one iron","description":"Fetch by stable club ID or slug. A historical slug redirects to the current slug with 301. Core is the default unless view or fields selects another permitted document. Read Golfapi-View for the document served.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned clb_ id or a current or historical iron slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core, expanded or market. Core is the default unless fields selects another document. The legacy token basic is accepted as core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). Missing access returns 403. Read Golfapi-View for the document served.","schema":{"type":"string","enum":["core","expanded","market"]}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields from one response document. id is always returned. Without an explicit view, a Club-builder field selects expanded and intro_price selects market. Missing club-builder or market access returns 403; market (intro_price) needs the Pro plan. An unknown field, a field outside an explicit view, or a selection mixing Club-builder and Market fields returns 400.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}},{"name":"variants","in":"query","required":false,"description":"Filter `variants` by hand or nominal loft in Core or Club-builder documents. Market carries no variants.","schema":{"type":"string","pattern":"^(all|rh|lh|\\d{1,2}(\\.\\d)?)$","default":"all"}}],"responses":{"200":{"description":"One iron.","headers":{"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/IronCore"},{"$ref":"#/components/schemas/IronExpanded"},{"$ref":"#/components/schemas/MarketClub"}]}}}},"301":{"description":"A historical slug redirects to the canonical URL. Retain the query string and the same-origin auth and version headers. Live example: GET /drivers/g440-max-2025-driver redirects to /drivers/g440-max-driver.","headers":{"Location":{"schema":{"type":"string","format":"uri","pattern":"^https?://"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"irons","x-fern-sdk-method-name":"get","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsIronsRef","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/wedges":{"get":{"operationId":"listWedges","summary":"List wedges","description":"Filters combine with AND. No matches returns data: []. Unknown or repeated query parameters return 400. Results are ordered by release_year descending, then club ID descending; q orders by relevance first. Core is the default unless view or fields selects another permitted document.","parameters":[{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core, expanded or market. Core is the default unless fields selects another document. The legacy token basic is accepted as core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). Missing access returns 403. Read Golfapi-View for the document served.","schema":{"type":"string","enum":["core","expanded","market"],"default":"core"}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields from one response document. id is always returned. Without an explicit view, a Club-builder field selects expanded and intro_price selects market. Missing club-builder or market access returns 403; market (intro_price) needs the Pro plan. An unknown field, a field outside an explicit view, or a selection mixing Club-builder and Market fields returns 400.","schema":{"type":"string","minLength":1}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"Opaque pagination token from page.next. Send it unchanged on the same resource, with the same filters, served version and key access. Page size may change between requests. On a cursor 400, restart the scan.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}},{"name":"manufacturer","in":"query","required":false,"description":"Manufacturer slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"family","in":"query","required":false,"description":"Family slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"hand","in":"query","required":false,"description":"Offered hand.","schema":{"type":"string","enum":["rh","lh"]}},{"name":"designation","in":"query","required":false,"description":"Heads whose designations includes this value. Each model is returned once. An empty result means no matching published record; an omitted designations field has no published classification.","schema":{"type":"string","enum":["womens","junior"]}},{"name":"loft","in":"query","required":false,"description":"Nominal loft in degrees. The value must occur in the requested collection; otherwise the API returns 400 with that collection’s published lofts. A loft available only in another collection is invalid here. With hand, both must match the same variant: hand=lh&loft=10.5 returns clubs sold left-handed at 10.5 degrees.","schema":{"type":"string","pattern":"^\\d{1,2}(\\.\\d)?$"}},{"name":"adjustable_hosel","in":"query","required":false,"description":"Whether the hosel adjusts.","schema":{"type":"string","enum":["true","false"]}},{"name":"release_year","in":"query","required":false,"description":"Release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"release_year_after","in":"query","required":false,"description":"Inclusive earliest release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"release_year_before","in":"query","required":false,"description":"Inclusive latest release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"released_after","in":"query","required":false,"description":"Inclusive earliest exact retail date. Matches only records with an exact `released` date; a record that carries only `release_year` never matches. A window whose start is later than released_before is 400: the two parameters contradict each other, which is not the same answer as a window that merely matches nothing.","schema":{"type":"string","format":"date"}},{"name":"released_before","in":"query","required":false,"description":"Inclusive latest exact retail date. Matches only records with an exact `released` date. Equal bounds are a legal one-day window.","schema":{"type":"string","format":"date"}},{"name":"msrp_min","in":"query","required":false,"description":"Inclusive lowest launch MSRP in the market `msrp_market` names (US when absent), in that currency's minor units: 50000 is $500 in the US and Y50,000 in JP, since JPY has no minor unit. A club with no launch price in that market never matches. Pro plan: needs the 'market' entitlement (403 without it), on any view. Greater than msrp_max is 400.","schema":{"type":"integer","minimum":0,"maximum":999999999}},{"name":"msrp_max","in":"query","required":false,"description":"Inclusive highest launch MSRP in the market `msrp_market` names (US when absent), in that currency's minor units: 50000 is $500 in the US and Y50,000 in JP. A club with no launch price in that market never matches. Pro plan: needs the 'market' entitlement (403 without it), on any view.","schema":{"type":"integer","minimum":0,"maximum":999999999}},{"name":"msrp_market","in":"query","required":false,"description":"ISO 3166-1 alpha-2 market whose `intro_price` entry msrp_min and msrp_max compare, in its own currency; US when absent. Prices are never converted between currencies. Alone, it keeps the clubs with a launch price in that market. A market the published catalog has no price in is 400, naming the markets it prices. Pro plan: needs the 'market' entitlement (403 without it).","schema":{"type":"string","pattern":"^[A-Z]{2}$"}},{"name":"q","in":"query","required":false,"description":"Search names, manufacturers, families, and generated aliases. Case and accents are folded. The full-text branch combines tokens with AND, while prefix, alias, and similarity matches can add rows that do not contain every token. A non-empty page does not identify a club; fetch a chosen hit with GET /{resource}/{id-or-slug}. Control characters are invalid.","schema":{"type":"string","minLength":1,"maxLength":200}}],"responses":{"200":{"description":"A page of wedges.","headers":{"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/WedgeCoreList"},{"$ref":"#/components/schemas/WedgeExpandedList"},{"$ref":"#/components/schemas/MarketClubList"}]}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"wedges","x-fern-sdk-method-name":"list","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsWedges","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/wedges/{ref}":{"get":{"operationId":"getWedge","summary":"Fetch one wedge","description":"Fetch by stable club ID or slug. A historical slug redirects to the current slug with 301. Core is the default unless view or fields selects another permitted document. Read Golfapi-View for the document served.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned clb_ id or a current or historical wedge slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core, expanded or market. Core is the default unless fields selects another document. The legacy token basic is accepted as core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). Missing access returns 403. Read Golfapi-View for the document served.","schema":{"type":"string","enum":["core","expanded","market"]}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields from one response document. id is always returned. Without an explicit view, a Club-builder field selects expanded and intro_price selects market. Missing club-builder or market access returns 403; market (intro_price) needs the Pro plan. An unknown field, a field outside an explicit view, or a selection mixing Club-builder and Market fields returns 400.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}},{"name":"variants","in":"query","required":false,"description":"Filter `variants` by hand or nominal loft in Core or Club-builder documents. Market carries no variants.","schema":{"type":"string","pattern":"^(all|rh|lh|\\d{1,2}(\\.\\d)?)$","default":"all"}}],"responses":{"200":{"description":"One wedge.","headers":{"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/WedgeCore"},{"$ref":"#/components/schemas/WedgeExpanded"},{"$ref":"#/components/schemas/MarketClub"}]}}}},"301":{"description":"A historical slug redirects to the canonical URL. Retain the query string and the same-origin auth and version headers. Live example: GET /drivers/g440-max-2025-driver redirects to /drivers/g440-max-driver.","headers":{"Location":{"schema":{"type":"string","format":"uri","pattern":"^https?://"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"wedges","x-fern-sdk-method-name":"get","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsWedgesRef","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/putters":{"get":{"operationId":"listPutters","summary":"List putters","description":"Filters combine with AND. No matches returns data: []. Unknown or repeated query parameters return 400. Results are ordered by release_year descending, then club ID descending; q orders by relevance first. Core is the default unless view or fields selects another permitted document.","parameters":[{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core, expanded or market. Core is the default unless fields selects another document. The legacy token basic is accepted as core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). Missing access returns 403. Read Golfapi-View for the document served.","schema":{"type":"string","enum":["core","expanded","market"],"default":"core"}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields from one response document. id is always returned. Without an explicit view, a Club-builder field selects expanded and intro_price selects market. Missing club-builder or market access returns 403; market (intro_price) needs the Pro plan. An unknown field, a field outside an explicit view, or a selection mixing Club-builder and Market fields returns 400.","schema":{"type":"string","minLength":1}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"Opaque pagination token from page.next. Send it unchanged on the same resource, with the same filters, served version and key access. Page size may change between requests. On a cursor 400, restart the scan.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}},{"name":"manufacturer","in":"query","required":false,"description":"Manufacturer slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"family","in":"query","required":false,"description":"Family slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"hand","in":"query","required":false,"description":"Offered hand.","schema":{"type":"string","enum":["rh","lh"]}},{"name":"designation","in":"query","required":false,"description":"Heads whose designations includes this value. Each model is returned once. An empty result means no matching published record; an omitted designations field has no published classification.","schema":{"type":"string","enum":["womens","junior"]}},{"name":"loft","in":"query","required":false,"description":"Nominal loft in degrees. The value must occur in the requested collection; otherwise the API returns 400 with that collection’s published lofts. A loft available only in another collection is invalid here. With hand, both must match the same variant: hand=lh&loft=10.5 returns clubs sold left-handed at 10.5 degrees.","schema":{"type":"string","pattern":"^\\d{1,2}(\\.\\d)?$"}},{"name":"adjustable_hosel","in":"query","required":false,"description":"Whether the hosel adjusts.","schema":{"type":"string","enum":["true","false"]}},{"name":"release_year","in":"query","required":false,"description":"Release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"release_year_after","in":"query","required":false,"description":"Inclusive earliest release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"release_year_before","in":"query","required":false,"description":"Inclusive latest release year, four digits.","schema":{"type":"integer","minimum":1900,"maximum":2100}},{"name":"released_after","in":"query","required":false,"description":"Inclusive earliest exact retail date. Matches only records with an exact `released` date; a record that carries only `release_year` never matches. A window whose start is later than released_before is 400: the two parameters contradict each other, which is not the same answer as a window that merely matches nothing.","schema":{"type":"string","format":"date"}},{"name":"released_before","in":"query","required":false,"description":"Inclusive latest exact retail date. Matches only records with an exact `released` date. Equal bounds are a legal one-day window.","schema":{"type":"string","format":"date"}},{"name":"msrp_min","in":"query","required":false,"description":"Inclusive lowest launch MSRP in the market `msrp_market` names (US when absent), in that currency's minor units: 50000 is $500 in the US and Y50,000 in JP, since JPY has no minor unit. A club with no launch price in that market never matches. Pro plan: needs the 'market' entitlement (403 without it), on any view. Greater than msrp_max is 400.","schema":{"type":"integer","minimum":0,"maximum":999999999}},{"name":"msrp_max","in":"query","required":false,"description":"Inclusive highest launch MSRP in the market `msrp_market` names (US when absent), in that currency's minor units: 50000 is $500 in the US and Y50,000 in JP. A club with no launch price in that market never matches. Pro plan: needs the 'market' entitlement (403 without it), on any view.","schema":{"type":"integer","minimum":0,"maximum":999999999}},{"name":"msrp_market","in":"query","required":false,"description":"ISO 3166-1 alpha-2 market whose `intro_price` entry msrp_min and msrp_max compare, in its own currency; US when absent. Prices are never converted between currencies. Alone, it keeps the clubs with a launch price in that market. A market the published catalog has no price in is 400, naming the markets it prices. Pro plan: needs the 'market' entitlement (403 without it).","schema":{"type":"string","pattern":"^[A-Z]{2}$"}},{"name":"q","in":"query","required":false,"description":"Search names, manufacturers, families, and generated aliases. Case and accents are folded. The full-text branch combines tokens with AND, while prefix, alias, and similarity matches can add rows that do not contain every token. A non-empty page does not identify a club; fetch a chosen hit with GET /{resource}/{id-or-slug}. Control characters are invalid.","schema":{"type":"string","minLength":1,"maxLength":200}}],"responses":{"200":{"description":"A page of putters.","headers":{"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/PutterCoreList"},{"$ref":"#/components/schemas/PutterExpandedList"},{"$ref":"#/components/schemas/MarketClubList"}]}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"putters","x-fern-sdk-method-name":"list","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsPutters","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/putters/{ref}":{"get":{"operationId":"getPutter","summary":"Fetch one putter","description":"Fetch by stable club ID or slug. A historical slug redirects to the current slug with 301. Core is the default unless view or fields selects another permitted document. Read Golfapi-View for the document served.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned clb_ id or a current or historical putter slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core, expanded or market. Core is the default unless fields selects another document. The legacy token basic is accepted as core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). Missing access returns 403. Read Golfapi-View for the document served.","schema":{"type":"string","enum":["core","expanded","market"]}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields from one response document. id is always returned. Without an explicit view, a Club-builder field selects expanded and intro_price selects market. Missing club-builder or market access returns 403; market (intro_price) needs the Pro plan. An unknown field, a field outside an explicit view, or a selection mixing Club-builder and Market fields returns 400.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}},{"name":"variants","in":"query","required":false,"description":"Filter `variants` by hand or nominal loft in Core or Club-builder documents. Market carries no variants.","schema":{"type":"string","pattern":"^(all|rh|lh|\\d{1,2}(\\.\\d)?)$","default":"all"}}],"responses":{"200":{"description":"One putter.","headers":{"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/PutterCore"},{"$ref":"#/components/schemas/PutterExpanded"},{"$ref":"#/components/schemas/MarketClub"}]}}}},"301":{"description":"A historical slug redirects to the canonical URL. Retain the query string and the same-origin auth and version headers. Live example: GET /drivers/g440-max-2025-driver redirects to /drivers/g440-max-driver.","headers":{"Location":{"schema":{"type":"string","format":"uri","pattern":"^https?://"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"Golfapi-View":{"schema":{"type":"string","enum":["core","expanded","market"]},"description":"The document served: core, expanded or market. Without view or fields that select another document, club requests return core. Expanded requires club-builder (Enterprise); Market requires market (Pro plan). A request without the required entitlement returns 403."}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"putters","x-fern-sdk-method-name":"get","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsPuttersRef","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/hosel-systems":{"get":{"x-golfapi-published":false,"operationId":"listHoselSystems","summary":"List hosel systems","description":"This resource is not published. Check API discovery for publication before requesting it. Requires 'club-builder' and an entitlement to at least one club resource. Sorted by id. Unlike the catalog lists, this response carries no ETag.","parameters":[{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core or expanded. The legacy token basic is accepted as core. Read Golfapi-View for the document served. Equipment and hosel routes have their own defaults and require club-builder.","schema":{"type":"string","enum":["core","expanded"],"default":"core"}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields. id is always returned; an unknown field for the effective view is 400.","schema":{"type":"string","minLength":1}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"Opaque pagination token from page.next. Send it unchanged on the same resource, with the same filters, served version and key access. Page size may change between requests. On a cursor 400, restart the scan.","schema":{"type":"string","minLength":1}},{"name":"manufacturer","in":"query","required":false,"description":"Manufacturer slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"q","in":"query","required":false,"description":"Search names and manufacturers.","schema":{"type":"string","minLength":1,"maxLength":200}},{"name":"club_type","in":"query","required":false,"description":"Narrow to one club type. Naming a club type this key is not entitled to is 403.","schema":{"type":"string","enum":["driver","mini-driver","fairway-wood","hybrid"]}}],"responses":{"200":{"description":"A page of hosel systems.","headers":{"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/HoselSystemList"},{"$ref":"#/components/schemas/ExpandedHoselSystemList"}]}}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"hosel-systems","x-fern-sdk-method-name":"list","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsHoselSystems","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/hosel-systems/{ref}":{"get":{"x-golfapi-published":false,"operationId":"getHoselSystem","summary":"Fetch one hosel system","description":"This resource is not published. Check API discovery for publication before requesting it. The full published setting charts for the system. Omit `view` and read `Golfapi-View` for the depth served. Unknown query parameters are ignored on this route.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned hos_ id or a current or historical system slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core or expanded. The legacy token basic is accepted as core. Read Golfapi-View for the document served. Equipment and hosel routes have their own defaults and require club-builder.","schema":{"type":"string","enum":["core","expanded"]}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields. id is always returned; an unknown field for the effective view is 400.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"One hosel system.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CoreHoselSystem"},{"$ref":"#/components/schemas/HoselSystem"}]}}}},"301":{"description":"A historical slug redirects to the canonical URL. Retain the query string and the same-origin auth and version headers. Live example: GET /drivers/g440-max-2025-driver redirects to /drivers/g440-max-driver.","headers":{"Location":{"schema":{"type":"string","format":"uri","pattern":"^https?://"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"hosel-systems","x-fern-sdk-method-name":"get","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsHoselSystemsRef","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/hosel-systems/{ref}/clubs":{"get":{"x-golfapi-published":false,"operationId":"listHoselSystemClubs","summary":"List the clubs fitted with a hosel system","description":"This resource is not published. Check API discovery for publication before requesting it. Each club appears once, with the scopes that connect it to this system. Results are limited to the club resources this key is entitled to; naming an unentitled club_type is 403. Unknown query parameters are ignored on this route.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned hos_ id or a current or historical system slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"hand","in":"query","required":false,"description":"Narrow to one hand.","schema":{"type":"string","enum":["rh","lh"]}},{"name":"market","in":"query","required":false,"description":"Narrow scopes to one market.","schema":{"type":"string","pattern":"^[A-Z]{2}$"}},{"name":"club_type","in":"query","required":false,"description":"Narrow to one club type. Naming a club type this key is not entitled to is 403.","schema":{"type":"string","enum":["driver","mini-driver","fairway-wood","hybrid"]}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"Opaque pagination token from page.next. Send it unchanged on the same resource, with the same filters, served version and key access. Page size may change between requests. On a cursor 400, restart the scan.","schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"A page of clubs.","headers":{"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SystemClubList"}}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"hosel-systems","x-fern-sdk-method-name":"clubs","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsHoselSystemsRefClubs","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/changes":{"get":{"operationId":"listChanges","summary":"Catalog changes since a release","description":"Catalog releases published after `after`, oldest first, each with the club ids it added, updated or removed per club resource. Lists only the club resources the key can access; requires any club resource entitlement. Store the Golfapi-Catalog-Release header from any catalog response, call this with it, and refetch the listed ids. A release the change history does not cover returns 400 naming the oldest release it can answer from; rescan the catalog then.","parameters":[{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"after","in":"query","required":true,"description":"A Golfapi-Catalog-Release value you stored.","schema":{"type":"string","pattern":"^bld_[0-9A-Z]{26}$"}},{"name":"limit","in":"query","required":false,"description":"Releases per page.","schema":{"type":"integer","minimum":1,"maximum":50,"default":10}},{"name":"cursor","in":"query","required":false,"description":"Opaque pagination token from page.next. Send it unchanged on the same resource, with the same filters, served version and key access. Page size may change between requests. On a cursor 400, restart the scan.","schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Releases after the given one.","headers":{"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeList"}}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"changes","x-fern-sdk-method-name":"list","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsChanges","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/coverage":{"get":{"operationId":"getCoverage","summary":"Catalog coverage","description":"Published record counts by resource, manufacturer, release year and field presence, limited to the club resources the key can access. Requires any club resource entitlement. Query parameters return 400. Returns 503 when no build is published. Supports ETag revalidation.","parameters":[{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Published catalog counts.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Coverage"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"coverage","x-fern-sdk-method-name":"get","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsCoverage","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/weight-systems":{"get":{"x-golfapi-published":false,"operationId":"listWeightSystems","summary":"List weight systems","description":"This resource is not published. Check API discovery for publication before requesting it. Requires the 'weight-systems' and 'club-builder' entitlements. Sorted by id. This response carries no ETag.","parameters":[{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core or expanded. The legacy token basic is accepted as core. Read Golfapi-View for the document served. Equipment and hosel routes have their own defaults and require club-builder.","schema":{"type":"string","enum":["core","expanded"],"default":"core"}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields. id is always returned; an unknown field for the effective view is 400.","schema":{"type":"string","minLength":1}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"Opaque pagination token from page.next. Send it unchanged on the same resource, with the same filters, served version and key access. Page size may change between requests. On a cursor 400, restart the scan.","schema":{"type":"string","minLength":1}},{"name":"manufacturer","in":"query","required":false,"description":"Manufacturer slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"q","in":"query","required":false,"description":"Search names and manufacturers.","schema":{"type":"string","minLength":1,"maxLength":200}}],"responses":{"200":{"description":"A page of weight systems.","headers":{"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/EquipmentList"},{"$ref":"#/components/schemas/WeightSystemList"}]}}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"weight-systems","x-fern-sdk-method-name":"list","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsWeightSystems","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/weight-systems/{ref}":{"get":{"x-golfapi-published":false,"operationId":"getWeightSystem","summary":"Fetch one weight system","description":"This resource is not published. Check API discovery for publication before requesting it. Omit `view` and read `Golfapi-View` for the depth served. Unknown query parameters are ignored on this route.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned id or a current or historical weight system slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core or expanded. The legacy token basic is accepted as core. Read Golfapi-View for the document served. Equipment and hosel routes have their own defaults and require club-builder.","schema":{"type":"string","enum":["core","expanded"]}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields. id is always returned; an unknown field for the effective view is 400.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"One weight system.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CoreEquipment"},{"$ref":"#/components/schemas/WeightSystem"}]}}}},"301":{"description":"A historical slug redirects to the canonical URL. Retain the query string and the same-origin auth and version headers. Live example: GET /drivers/g440-max-2025-driver redirects to /drivers/g440-max-driver.","headers":{"Location":{"schema":{"type":"string","format":"uri","pattern":"^https?://"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"weight-systems","x-fern-sdk-method-name":"get","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsWeightSystemsRef","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/shafts":{"get":{"x-golfapi-published":false,"operationId":"listShafts","summary":"List shafts","description":"This resource is not published. Check API discovery for publication before requesting it. Requires the 'shafts' and 'club-builder' entitlements. Sorted by id. This response carries no ETag.","parameters":[{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core or expanded. The legacy token basic is accepted as core. Read Golfapi-View for the document served. Equipment and hosel routes have their own defaults and require club-builder.","schema":{"type":"string","enum":["core","expanded"],"default":"core"}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields. id is always returned; an unknown field for the effective view is 400.","schema":{"type":"string","minLength":1}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"Opaque pagination token from page.next. Send it unchanged on the same resource, with the same filters, served version and key access. Page size may change between requests. On a cursor 400, restart the scan.","schema":{"type":"string","minLength":1}},{"name":"manufacturer","in":"query","required":false,"description":"Manufacturer slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"q","in":"query","required":false,"description":"Search names and manufacturers.","schema":{"type":"string","minLength":1,"maxLength":200}}],"responses":{"200":{"description":"A page of shafts.","headers":{"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/EquipmentList"},{"$ref":"#/components/schemas/ShaftList"}]}}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"shafts","x-fern-sdk-method-name":"list","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsShafts","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/shafts/{ref}":{"get":{"x-golfapi-published":false,"operationId":"getShaft","summary":"Fetch one shaft","description":"This resource is not published. Check API discovery for publication before requesting it. Omit `view` and read `Golfapi-View` for the depth served. Unknown query parameters are ignored on this route.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned id or a current or historical shaft slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core or expanded. The legacy token basic is accepted as core. Read Golfapi-View for the document served. Equipment and hosel routes have their own defaults and require club-builder.","schema":{"type":"string","enum":["core","expanded"]}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields. id is always returned; an unknown field for the effective view is 400.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"One shaft.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CoreEquipment"},{"$ref":"#/components/schemas/Shaft"}]}}}},"301":{"description":"A historical slug redirects to the canonical URL. Retain the query string and the same-origin auth and version headers. Live example: GET /drivers/g440-max-2025-driver redirects to /drivers/g440-max-driver.","headers":{"Location":{"schema":{"type":"string","format":"uri","pattern":"^https?://"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"shafts","x-fern-sdk-method-name":"get","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsShaftsRef","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/grips":{"get":{"x-golfapi-published":false,"operationId":"listGrips","summary":"List grips","description":"This resource is not published. Check API discovery for publication before requesting it. Requires the 'grips' and 'club-builder' entitlements. Sorted by id. This response carries no ETag.","parameters":[{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core or expanded. The legacy token basic is accepted as core. Read Golfapi-View for the document served. Equipment and hosel routes have their own defaults and require club-builder.","schema":{"type":"string","enum":["core","expanded"],"default":"core"}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields. id is always returned; an unknown field for the effective view is 400.","schema":{"type":"string","minLength":1}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"Opaque pagination token from page.next. Send it unchanged on the same resource, with the same filters, served version and key access. Page size may change between requests. On a cursor 400, restart the scan.","schema":{"type":"string","minLength":1}},{"name":"manufacturer","in":"query","required":false,"description":"Manufacturer slug.","schema":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},{"name":"q","in":"query","required":false,"description":"Search names and manufacturers.","schema":{"type":"string","minLength":1,"maxLength":200}}],"responses":{"200":{"description":"A page of grips.","headers":{"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/EquipmentList"},{"$ref":"#/components/schemas/GripList"}]}}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"grips","x-fern-sdk-method-name":"list","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsGrips","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}},"/grips/{ref}":{"get":{"x-golfapi-published":false,"operationId":"getGrip","summary":"Fetch one grip","description":"This resource is not published. Check API discovery for publication before requesting it. Omit `view` and read `Golfapi-View` for the depth served. Unknown query parameters are ignored on this route.","parameters":[{"name":"ref","in":"path","required":true,"description":"A returned id or a current or historical grip slug.","schema":{"type":"string","minLength":1}},{"name":"Golfapi-Version","in":"header","required":false,"description":"API version. 2026-10-02 is the only version served, and the default when the header is omitted. Any other date is 400, including the retired versions `GET /` lists under `version.retired`. A malformed date is 400.","schema":{"type":"string","format":"date","default":"2026-10-02"}},{"name":"view","in":"query","required":false,"description":"Response document: core or expanded. The legacy token basic is accepted as core. Read Golfapi-View for the document served. Equipment and hosel routes have their own defaults and require club-builder.","schema":{"type":"string","enum":["core","expanded"]}},{"name":"fields","in":"query","required":false,"description":"Comma-separated top-level fields. id is always returned; an unknown field for the effective view is 400.","schema":{"type":"string","minLength":1}},{"name":"If-None-Match","in":"header","required":false,"description":"ETag retained for this exact representation URL and version. A 304 is not charged against the rate limit, and its RateLimit-Remaining names the budget after that refund.","schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"One grip.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CoreEquipment"},{"$ref":"#/components/schemas/Grip"}]}}}},"301":{"description":"A historical slug redirects to the canonical URL. Retain the query string and the same-origin auth and version headers. Live example: GET /drivers/g440-max-2025-driver redirects to /drivers/g440-max-driver.","headers":{"Location":{"schema":{"type":"string","format":"uri","pattern":"^https?://"}}}},"304":{"description":"Unchanged representation, no response body. Quota refunded after response.","headers":{"Golfapi-Catalog-Release":{"schema":{"type":"string","pattern":"^bld_"},"description":"The catalog release this key's data comes from, on every successful authenticated response including 304. Store it and call GET /changes?after= with it to learn which clubs changed since."},"Golfapi-Catalog-Published":{"schema":{"type":"string","format":"date-time"},"description":"When that release was published, RFC 3339 UTC."},"ETag":{"schema":{"type":"string","minLength":1},"description":"Opaque representation tag; store per exact URL and version. It covers the representation, not only the record, so a tag from one view is never accepted for another."},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"400":{"description":"Invalid recognized input or projected field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, malformed, unknown, or revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"schema":{"type":"string","minLength":1},"description":"`Bearer` when Authorization is absent; `Bearer error=\"invalid_token\"` when a credential was sent."}}},"403":{"description":"Resource/capability not granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Referenced record not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"A routed path reached by a method other than GET or OPTIONS.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Allow":{"schema":{"type":"string","minLength":1},"description":"Always `GET, OPTIONS`."}}},"429":{"description":"Rate limit reached. 60 requests per 60-second wall-clock window by default; RateLimit-Limit carries this key's actual cap. Honor Retry-After, which equals RateLimit-Reset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"Golfapi-Request-Id":{"schema":{"type":"string","pattern":"^req_"},"description":"This request's id, on every response including 200 and 304. The same value an error body carries; quote it in a report."},"Golfapi-Version":{"schema":{"type":"string","format":"date"},"description":"The version served. One version is served, so this is always the Golfapi-Version default."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Server fault.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Required representation or schema unavailable; honor Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"A hint, and a coarse one. A 503 here clears when an operator applies a migration or publishes a build, not on a timer, so it sends an hour rather than a minute. GET /health is the signal worth polling; cap your own backoff."}}}},"x-fern-sdk-group-name":"grips","x-fern-sdk-method-name":"get","x-fern-availability":"generally-available","x-fern-ignore":false,"x-forge-hidden":false},"options":{"operationId":"optionsGripsRef","summary":"CORS preflight","description":"Answered before authentication, for every path: a preflight carries no Authorization header, so answering it from inside the auth chain would 401 every browser request before the real one was sent. No credential is required and no data is named.","security":[],"parameters":[{"name":"Origin","in":"header","required":false,"description":"The requesting origin. Echoed as `*`; this API is public and sends no Access-Control-Allow-Credentials, so a browser cannot be tricked into attaching ambient authority.","schema":{"type":"string","minLength":1}},{"name":"Access-Control-Request-Method","in":"header","required":false,"description":"The method the browser intends to send. Only GET is allowed.","schema":{"type":"string","minLength":1}}],"responses":{"204":{"description":"Preflight accepted. No body.","headers":{"Access-Control-Allow-Origin":{"schema":{"type":"string","const":"*"}},"Access-Control-Allow-Methods":{"schema":{"type":"string","const":"GET, OPTIONS"}},"Access-Control-Allow-Headers":{"schema":{"type":"string","minLength":1}},"Access-Control-Max-Age":{"schema":{"type":"integer"}},"Allow":{"schema":{"type":"string","const":"GET, OPTIONS"}}}}},"x-fern-ignore":true}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"`Authorization: Bearer sk_live_<32 hex>` or `sk_test_<32 hex>` -- the secret shown once at creation, not the `key_…` key id. Never include credentials in URLs or public artifacts."}},"schemas":{"NamedEntity":{"type":"object","additionalProperties":false,"properties":{"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1}},"required":["slug","name"]},"CoreClub":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^clb_[0-9A-HJKMNP-TV-Z]{26}$"},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"club_type":{"type":"string","enum":["driver","mini-driver","fairway-wood","hybrid","iron","wedge","putter"],"description":"The resource this club belongs to: driver, mini-driver, fairway-wood, hybrid, iron (a set), wedge or putter."},"summary":{"type":"string","minLength":1,"maxLength":160,"description":"One sentence naming the club, its maker, introduction year, club type and family. Built from this document's fields at each catalog build. Contains no specifications and no performance or suitability claims."},"manufacturer":{"$ref":"#/components/schemas/NamedEntity"},"family":{"$ref":"#/components/schemas/NamedEntity"},"release_year":{"type":"integer","minimum":1900,"maximum":2100,"description":"The year the manufacturer released this head. Present on every club."},"released":{"type":"string","format":"date","description":"Exact first retail availability date for the recorded launch market. Omitted when only release_year is published."},"lofts_deg":{"type":"array","items":{"type":"number","exclusiveMinimum":0},"minItems":1,"uniqueItems":true,"description":"Sorted union of offered nominal lofts."},"hands":{"type":"array","items":{"type":"string","enum":["rh","lh"]},"minItems":1,"uniqueItems":true,"maxItems":2,"enum":[["rh"],["lh"],["rh","lh"]],"description":"Available hands, ordered rh then lh."},"volume_cc":{"type":"number","exclusiveMinimum":0,"description":"Head volume in cc. Mirrors `head.volume_cc`. Present on every driver, mini-driver and hybrid. A fairway wood omits it when its manufacturer states no model head volume."},"adjustable_hosel":{"type":"boolean"},"head":{"$ref":"#/components/schemas/ClubHead"},"hosel_summary":{"type":"object","additionalProperties":false,"properties":{"adjustable":{"type":"boolean"}},"required":["adjustable"],"description":"Consumer-facing hosel summary. `adjustable` is present whenever the object is. The named hosel system is Club-builder (`view=expanded`)."},"variants":{"type":"array","items":{"$ref":"#/components/schemas/CoreVariant"},"minItems":1,"description":"One entry per loft, hand and market combination."},"designations":{"type":"array","items":{"type":"string","enum":["womens","junior"]},"minItems":1,"uniqueItems":true,"maxItems":2,"enum":[["womens"],["junior"],["womens","junior"]],"description":"The manufacturer's labels on this head and its builds: the union of the head's own designation and every build's, ordered womens then junior. Absent when empty. Absent `designations` means no label is published, not \"not a women's club\": a head without the field may still be sold in a women's or junior build that no published record names yet. `womens` is the manufacturer's label, not a statement about who should play the club."},"url":{"type":"string","format":"uri","pattern":"^https://","description":"Canonical club URL."},"updated_at":{"type":"string","format":"date-time","pattern":"Z$","description":"When this response document last changed. Compare within the same view when refreshing a stored catalog; there is no updated_after filter."}},"required":["id"],"description":"The default club document, served when neither `view` nor `fields` selects another document. Only `id` is guaranteed, because `fields=` may project any subset; an unprojected response carries every field listed in `x-required-unprojected`. Every other field is absent when unknown, never null, empty or a default.","x-required-unprojected":["id","slug","name","manufacturer","release_year","url","updated_at"]},"Error":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"object","additionalProperties":false,"properties":{"type":{"type":"string","enum":["invalid_request","invalid_auth","forbidden","not_found","rate_limited","method_not_allowed","server_error","service_unavailable","account_inactive","quota_exceeded"]},"message":{"type":"string","minLength":1},"status":{"type":"integer","enum":[400,401,403,404,405,429,500,503]},"request_id":{"type":"string","pattern":"^req_"},"param":{"type":"string","minLength":1}},"required":["type","message","status","request_id"]}},"required":["error"]},"Page":{"type":"object","additionalProperties":false,"properties":{"limit":{"type":"integer","minimum":1,"maximum":100},"has_more":{"type":"boolean"},"catalog_complete":{"type":"boolean","const":false,"description":"False for this published catalog. An empty page means no match in this build; it does not establish that a club does not exist."},"next":{"type":"string","minLength":1}},"required":["limit","has_more","catalog_complete"],"allOf":[{"if":{"properties":{"has_more":{"const":true}}},"then":{"required":["next"]},"else":{"not":{"required":["next"]}}}]},"IntroPrice":{"type":"object","additionalProperties":false,"properties":{"market":{"type":"string","pattern":"^[A-Z]{2}$","description":"ISO 3166-1 alpha-2 market the price was stated for."},"msrp_minor":{"type":"integer","minimum":1,"description":"The launch MSRP in the minor units of `currency` (ISO 4217), exactly as stated: $649 is 64900, and Y41,800 is 41800 because JPY has no minor unit. Never converted, so prices in different currencies are not comparable."},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"tax_included":{"type":"boolean","description":"Whether the price includes sales tax or VAT, as the source states it. Always false for US; Japanese, UK and EU retail prices usually include it."}},"required":["market","msrp_minor","currency","tax_included"]},"MarketClub":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^clb_[0-9A-HJKMNP-TV-Z]{26}$"},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"club_type":{"type":"string","enum":["driver","mini-driver","fairway-wood","hybrid","iron","wedge","putter"],"description":"The resource this club belongs to: driver, mini-driver, fairway-wood, hybrid, iron (a set), wedge or putter."},"manufacturer":{"$ref":"#/components/schemas/NamedEntity"},"family":{"$ref":"#/components/schemas/NamedEntity"},"release_year":{"type":"integer","minimum":1900,"maximum":2100,"description":"The year the manufacturer released this head. Present on every club."},"released":{"type":"string","format":"date","description":"Exact first retail availability date for the recorded launch market. Omitted when only release_year is published."},"intro_price":{"type":"array","items":{"$ref":"#/components/schemas/IntroPrice"},"minItems":1,"description":"Pro. The launch MSRP, one entry per market. Absent when no launch price is published."},"url":{"type":"string","format":"uri","pattern":"^https://","description":"Canonical club URL."},"updated_at":{"type":"string","format":"date-time","pattern":"Z$","description":"When this response document last changed. Compare within the same view when refreshing a stored catalog; there is no updated_after filter."}},"required":["id"],"description":"The Market document, served by `view=market` to a key holding the 'market' entitlement (Pro plan), on every club type: the club's identity and its Market fields, with no specifications. Join it to a spec document on `id`. Only `id` is guaranteed, because `fields=` may project any subset; `intro_price` is absent when no launch price is published, never empty. `updated_at` moves when this document changes, independently of the spec documents.","x-required-unprojected":["id","slug","name","manufacturer","release_year","url","updated_at"]},"MarketClubList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MarketClub"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]},"CoreClubList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CoreClub"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]},"ClubHead":{"type":"object","additionalProperties":false,"properties":{"volume_cc":{"type":"number","exclusiveMinimum":0}},"required":[],"minProperties":1,"description":"`volume_cc` is omitted when the manufacturer states no model head volume, and `head` is omitted when no head value is known. On fairway woods and hybrids it is the lowest-loft head's volume when the manufacturer states only per-head volumes."},"ClubHosel":{"type":"object","additionalProperties":false,"properties":{"interface":{"type":"string","minLength":1},"shaft_tip_in":{"type":"number","exclusiveMinimum":0},"adjustable":{"type":"boolean"},"positions":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string","minLength":1},"loft_delta_deg":{"type":"number"},"lie_delta_deg":{"type":"number"}},"required":["code","loft_delta_deg","lie_delta_deg"]}}},"required":["adjustable"],"description":"The club's hosel on the Club-builder document: interface slug, tip diameter, adjustability and the discrete positions of an adjustable hosel. A fixed hosel has no positions."},"SystemHosel":{"type":"object","additionalProperties":false,"properties":{"system_id":{"type":"string","pattern":"^hos_[0-9A-HJKMNP-TV-Z]{26}$"},"standard_setting":{"type":"object","additionalProperties":false,"properties":{"rh":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"lh":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},"required":[]}},"required":["system_id"],"description":"A reference to the hosel system, with the club's standard setting per hand. The full setting chart is at /{resource}/{ref}/hosel and /hosel-systems/{ref}."},"WeightPort":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"label":{"type":"string","minLength":1},"type":{"type":"string","enum":["sliding","screw","swap"]}},"required":["code","label"]},"ClubWeights":{"type":"object","additionalProperties":false,"properties":{"adjustable":{"type":"boolean"},"system":{"type":"string","enum":["fixed","movable","interchangeable","reversible"]},"supplied_g":{"type":"array","items":{"type":"number","exclusiveMinimum":0}},"ports":{"type":"array","items":{"$ref":"#/components/schemas/WeightPort"}},"component_id":{"type":"string","pattern":"^wgt_[0-9A-HJKMNP-TV-Z]{26}$"}},"required":["adjustable","system"]},"CoreVariant":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^var_[0-9A-HJKMNP-TV-Z]{26}$"},"hand":{"type":"string","enum":["rh","lh"]},"market":{"type":"string","pattern":"^[A-Z]{2}$"},"loft_deg":{"type":"number","exclusiveMinimum":0},"lie_deg":{"type":"number","description":"Lie angle as the manufacturer publishes it. `lie_basis` says on what basis. Omitted when no lie is published for this variant."},"lie_basis":{"type":"string","enum":["standard_position","band_min","band_max","average_of_positions"],"description":"What `lie_deg` measures. Absent when no basis is published."},"head_label":{"type":"string","minLength":1,"description":"The maker's name for this head, such as 3W or 4H. Fairway woods and hybrids only. Absent when the maker's label for this head is not recorded."}},"required":["id","hand","market","loft_deg"]},"Variant":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^var_[0-9A-HJKMNP-TV-Z]{26}$"},"hand":{"type":"string","enum":["rh","lh"]},"market":{"type":"string","pattern":"^[A-Z]{2}$"},"loft_deg":{"type":"number","exclusiveMinimum":0},"lie_deg":{"type":"number"},"lie_basis":{"type":"string","enum":["standard_position","band_min","band_max","average_of_positions"]},"head_label":{"type":"string","minLength":1,"description":"The maker's name for this head, such as 3W or 4H. Fairway woods and hybrids only. Absent when the maker's label for this head is not recorded."},"lie_min_deg":{"type":"number"},"lie_max_deg":{"type":"number"},"length_in":{"type":"number","exclusiveMinimum":0},"swing_weight":{"type":"string","pattern":"^[A-G][0-9]$"},"volume_cc":{"type":"number","exclusiveMinimum":0,"description":"This head's volume in cc, as the maker states it per head. Fairway woods and hybrids only. Absent when unstated; the model-level `head.volume_cc` is the lowest-loft head's."}},"required":["id","hand","market","loft_deg"]},"MeasurementBasis":{"type":"object","additionalProperties":false,"properties":{"weight":{"type":"string","minLength":1},"torque":{"type":"string","minLength":1}},"required":[]},"ShaftSpecOption":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"flex_label":{"type":"string","minLength":1},"flex":{"type":"string","enum":["l","a","sr","r","s","x","tx"]},"weight_g":{"type":"number","exclusiveMinimum":0},"torque_deg":{"type":"number","minimum":0},"measurement_basis":{"$ref":"#/components/schemas/MeasurementBasis"},"part_number":{"type":"string","minLength":1}},"required":["code","flex_label"]},"GripSpecOption":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"size":{"type":"string","minLength":1},"core_designation":{"type":"string","minLength":1},"core_diameter_in":{"type":"number","exclusiveMinimum":0},"weight_g":{"type":"number","exclusiveMinimum":0},"part_number":{"type":"string","minLength":1}},"required":["code"]},"StockShaft":{"type":"object","additionalProperties":false,"properties":{"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"model":{"type":"string","minLength":1},"launch":{"type":"string","enum":["low","low-mid","mid","mid-high","high"]},"options":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"flex":{"type":"string","minLength":1},"label":{"type":"string","minLength":1}},"required":[]}},"component_id":{"type":"string","pattern":"^shf_[0-9A-HJKMNP-TV-Z]{26}$"},"spec_options":{"type":"array","items":{"$ref":"#/components/schemas/ShaftSpecOption"}}},"required":["slug","model","options"],"description":"component_id and spec_options appear only for a club covered by a signed equipment package, and spec_options carries only the options explicitly selected for this club."},"StockGrip":{"type":"object","additionalProperties":false,"properties":{"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"model":{"type":"string","minLength":1},"weight_g":{"type":"number","exclusiveMinimum":0},"size":{"type":"string","minLength":1},"component_id":{"type":"string","pattern":"^grp_[0-9A-HJKMNP-TV-Z]{26}$"},"spec_options":{"type":"array","items":{"$ref":"#/components/schemas/GripSpecOption"}}},"required":["slug","model"]},"BuildComponentRef":{"type":"object","additionalProperties":false,"properties":{"component_id":{"type":"string","minLength":1},"option_code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"configuration_code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},"required":["component_id"]},"VariantSelector":{"type":"object","additionalProperties":false,"properties":{"hand":{"type":"string","enum":["rh","lh"]},"loft_deg":{"type":"number","exclusiveMinimum":0},"market":{"type":"string","pattern":"^[A-Z]{2}$"}},"required":["hand","loft_deg","market"]},"Build":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"market":{"type":"string","pattern":"^[A-Z]{2}$"},"variant_ids":{"type":"array","items":{"type":"string","pattern":"^var_[0-9A-HJKMNP-TV-Z]{26}$"}},"variants":{"type":"array","items":{"$ref":"#/components/schemas/VariantSelector"}},"shaft":{"$ref":"#/components/schemas/BuildComponentRef"},"grip":{"$ref":"#/components/schemas/BuildComponentRef"},"weight":{"$ref":"#/components/schemas/BuildComponentRef"},"length_in":{"type":"number","exclusiveMinimum":0},"swing_weight":{"type":"string","pattern":"^[A-G][0-9]$"},"designation":{"type":"string","enum":["womens","junior"],"description":"The manufacturer's label for this build. Absent when none is stated."}},"required":["code","market"],"description":"A named factory configuration. Exactly one of variant_ids or variants is present."},"ClubLinks":{"type":"object","additionalProperties":false,"properties":{"self":{"type":"string","format":"uri","pattern":"^https?://"},"hosel":{"type":"string","format":"uri","pattern":"^https?://"}},"required":["self"],"description":"hosel is present for a club with a hosel context."},"ExpandedClub":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^clb_[0-9A-HJKMNP-TV-Z]{26}$"},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"club_type":{"type":"string","enum":["driver","mini-driver","fairway-wood","hybrid","iron","wedge","putter"],"description":"The resource this club belongs to: driver, mini-driver, fairway-wood, hybrid, iron (a set), wedge or putter."},"summary":{"type":"string","minLength":1,"maxLength":160,"description":"One sentence naming the club, its maker, introduction year, club type and family. Built from this document's fields at each catalog build. Contains no specifications and no performance or suitability claims."},"manufacturer":{"$ref":"#/components/schemas/NamedEntity"},"family":{"$ref":"#/components/schemas/NamedEntity"},"release_year":{"type":"integer","minimum":1900,"maximum":2100,"description":"The year the manufacturer released this head. Present on every club."},"released":{"type":"string","format":"date","description":"Exact first retail availability date for the recorded launch market. Omitted when only release_year is published."},"lofts_deg":{"type":"array","items":{"type":"number","exclusiveMinimum":0},"minItems":1,"uniqueItems":true,"description":"Sorted union of offered nominal lofts."},"hands":{"type":"array","items":{"type":"string","enum":["rh","lh"]},"minItems":1,"uniqueItems":true,"maxItems":2,"enum":[["rh"],["lh"],["rh","lh"]],"description":"Available hands, ordered rh then lh."},"volume_cc":{"type":"number","exclusiveMinimum":0,"description":"Head volume in cc. Mirrors `head.volume_cc`. Present on every driver, mini-driver and hybrid. A fairway wood omits it when its manufacturer states no model head volume."},"adjustable_hosel":{"type":"boolean"},"head":{"$ref":"#/components/schemas/ClubHead"},"hosel_summary":{"type":"object","additionalProperties":false,"properties":{"adjustable":{"type":"boolean"},"system_name":{"type":"string","minLength":1},"loft_adjustment_deg":{"type":"array","items":{"type":"number"},"minItems":1,"uniqueItems":true}},"required":["adjustable"],"description":"Consumer-facing hosel summary. `adjustable` is present whenever the object is. The optional children come from approved input and are never inferred from a detailed setting chart."},"variants":{"type":"array","items":{"$ref":"#/components/schemas/Variant"},"minItems":1,"description":"One entry per loft, hand and market combination, with the lie, length and swing weight the manufacturer states."},"designations":{"type":"array","items":{"type":"string","enum":["womens","junior"]},"minItems":1,"uniqueItems":true,"maxItems":2,"enum":[["womens"],["junior"],["womens","junior"]],"description":"The manufacturer's labels on this head and its builds: the union of the head's own designation and every build's, ordered womens then junior. Absent when empty. Absent `designations` means no label is published, not \"not a women's club\": a head without the field may still be sold in a women's or junior build that no published record names yet. `womens` is the manufacturer's label, not a statement about who should play the club."},"url":{"type":"string","format":"uri","pattern":"^https://","description":"Canonical club URL."},"updated_at":{"type":"string","format":"date-time","pattern":"Z$","description":"When this response document last changed. Compare within the same view when refreshing a stored catalog; there is no updated_after filter."},"adjustable_weight":{"type":"boolean"},"weight_system":{"type":"string","enum":["fixed","movable","interchangeable","reversible"]},"hosel":{"$ref":"#/components/schemas/ClubHosel","description":"Absent when no hosel value is published."},"weights":{"$ref":"#/components/schemas/ClubWeights"},"stock_shafts":{"type":"array","items":{"$ref":"#/components/schemas/StockShaft"}},"stock_grips":{"type":"array","items":{"$ref":"#/components/schemas/StockGrip"}},"builds":{"type":"array","items":{"$ref":"#/components/schemas/Build"}},"equipment":{"type":"object","additionalProperties":false,"properties":{"weight_systems":{"type":"array","items":{"$ref":"#/components/schemas/WeightSystem"}},"shafts":{"type":"array","items":{"$ref":"#/components/schemas/Shaft"}},"grips":{"type":"array","items":{"$ref":"#/components/schemas/Grip"}}},"required":[],"description":"Full documents for every component this club references. Their presence is not a claim that every listed option is offered on this club; only builds and stock spec_options state that."},"_links":{"$ref":"#/components/schemas/ClubLinks"}},"required":["id"],"description":"The Club-builder document, served for `view=expanded` to a key with the 'club-builder' entitlement. The Core fields first, then the build fields; `hosel_summary` adds `loft_adjustment_deg` and each variant adds its lie, length and swing weight. Only `id` is guaranteed, because `fields=` may project any subset; an unprojected response carries every field listed in `x-required-unprojected`. `weights`, `hosel` and per-field optional values are omitted when no value is published, never nulled or defaulted. `builds` and `equipment` appear only for a club covered by a signed equipment package. A Core document is not an ExpandedClub: the Club-builder keys are absent and `additionalProperties: false` on CoreClub tells the two apart.","allOf":[{"if":{"properties":{"weight_system":{"const":"fixed"}}},"then":{"properties":{"adjustable_weight":{"const":false}}},"else":{"properties":{"adjustable_weight":{"const":true}}}}],"x-required-unprojected":["id","slug","name","manufacturer","release_year","url","updated_at","adjustable_weight","weight_system","stock_shafts","stock_grips","_links"]},"ExpandedClubList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExpandedClub"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]},"HoselSetting":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"label":{"type":"string","minLength":1},"loft_delta_deg":{"type":"number"},"lie_delta_deg":{"type":"number"},"face_angle_delta_deg":{"type":"number"}},"required":["code","label"]},"ReferenceBasis":{"type":"object","additionalProperties":false,"properties":{"loft":{"type":"string","minLength":1},"lie":{"type":"string","minLength":1},"face_angle":{"type":"string","minLength":1}},"required":[]},"HoselChart":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"hands":{"type":"array","items":{"type":"string","enum":["rh","lh"]}},"family_slugs":{"type":"array","items":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"minItems":1},"settings":{"type":"array","items":{"$ref":"#/components/schemas/HoselSetting"},"minItems":1},"complete":{"type":"boolean"},"applicability_note":{"type":"string","minLength":1},"reference_basis":{"$ref":"#/components/schemas/ReferenceBasis"}},"required":["code","name","family_slugs","settings","complete"],"description":"complete=false means the published chart does not cover every setting the system offers; it is never extrapolated."},"CoreHoselSystem":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^hos_[0-9A-HJKMNP-TV-Z]{26}$"},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"manufacturer":{"$ref":"#/components/schemas/NamedEntity"},"adjustable":{"type":"boolean"},"club_types":{"type":"array","items":{"type":"string","enum":["driver","mini-driver","fairway-wood","hybrid"]},"minItems":1},"url":{"type":"string","format":"uri","pattern":"^https?://"}},"required":["id"],"x-required-unprojected":["id","slug","name","manufacturer","adjustable","club_types","url"]},"HoselSystem":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^hos_[0-9A-HJKMNP-TV-Z]{26}$"},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"manufacturer":{"$ref":"#/components/schemas/NamedEntity"},"adjustable":{"type":"boolean"},"club_types":{"type":"array","items":{"type":"string","enum":["driver","mini-driver","fairway-wood","hybrid"]},"minItems":1},"url":{"type":"string","format":"uri","pattern":"^https?://"},"part_numbers":{"type":"array","items":{"type":"string","minLength":1},"minItems":1},"shaft_tip_in":{"type":"number","exclusiveMinimum":0},"limitations":{"type":"array","items":{"type":"string","minLength":1},"minItems":1},"charts":{"type":"array","items":{"$ref":"#/components/schemas/HoselChart"},"minItems":1},"updated_at":{"type":"string","format":"date-time","pattern":"Z$"},"_links":{"type":"object","additionalProperties":false,"properties":{"self":{"type":"string","format":"uri","pattern":"^https?://"},"clubs":{"type":"string","format":"uri","pattern":"^https?://"}},"required":["self","clubs"]}},"required":["id"],"x-required-unprojected":["id","slug","name","manufacturer","adjustable","club_types","url","updated_at","_links"]},"HoselScope":{"type":"object","additionalProperties":false,"properties":{"hands":{"type":"array","items":{"type":"string","enum":["rh","lh"]},"minItems":1},"markets":{"type":"array","items":{"type":"string","pattern":"^[A-Z]{2}$"},"minItems":1},"chart_codes":{"type":"array","items":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"minItems":1},"limitations":{"type":"array","items":{"type":"string","minLength":1},"minItems":1}},"required":["hands","markets"],"description":"One block of applicability. A request narrowed by hand or market returns scopes already narrowed to it."},"HoselContext":{"type":"object","additionalProperties":false,"properties":{"club_id":{"type":"string","pattern":"^clb_[0-9A-HJKMNP-TV-Z]{26}$"},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"resource":{"type":"string","enum":["drivers","mini-drivers","fairway-woods","hybrids"]},"connection_type":{"type":"string","enum":["adapter","bonded"]},"scopes":{"type":"array","items":{"$ref":"#/components/schemas/HoselScope"},"minItems":1},"url":{"type":"string","format":"uri","pattern":"^https?://"},"_links":{"type":"object","additionalProperties":false,"properties":{"self":{"type":"string","format":"uri","pattern":"^https?://"},"club":{"type":"string","format":"uri","pattern":"^https?://"},"system":{"type":"string","format":"uri","pattern":"^https?://"}},"required":["self","club"]},"system_id":{"type":"string","pattern":"^hos_[0-9A-HJKMNP-TV-Z]{26}$"},"adjustable":{"type":"boolean"},"charts":{"type":"array","items":{"$ref":"#/components/schemas/HoselChart"},"minItems":1},"standard_setting":{"type":"object","additionalProperties":false,"properties":{"rh":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"lh":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},"required":[]}},"required":["club_id","slug","resource","connection_type","scopes","url","_links"],"description":"A club's hosel applicability. system_id, adjustable, charts, standard_setting and _links.system are present for connection_type 'adapter' and absent for 'bonded'. charts carries only the charts the selected scopes name."},"SystemClub":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^clb_[0-9A-HJKMNP-TV-Z]{26}$"},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"resource":{"type":"string","enum":["drivers","mini-drivers","fairway-woods","hybrids"]},"url":{"type":"string","format":"uri","pattern":"^https?://"},"scopes":{"type":"array","items":{"$ref":"#/components/schemas/HoselScope"},"minItems":1}},"required":["id","slug","name","resource","url","scopes"]},"HoselSystemList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CoreHoselSystem"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]},"ExpandedHoselSystemList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/HoselSystem"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]},"SystemClubList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SystemClub"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]},"CoreEquipment":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","minLength":1},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"manufacturer":{"$ref":"#/components/schemas/NamedEntity"},"url":{"type":"string","format":"uri","pattern":"^https?://"}},"required":["id"],"x-required-unprojected":["id","slug","name","manufacturer","url"],"description":"The list shape shared by weight-systems, shafts and grips. id carries the resource's prefix: wgt_, shf_ or grp_."},"WeightPosition":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"label":{"type":"string","minLength":1}},"required":["code","label"]},"EquipmentPort":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"label":{"type":"string","minLength":1},"type":{"type":"string","enum":["sliding","screw","swap"]},"positions":{"type":"array","items":{"$ref":"#/components/schemas/WeightPosition"},"minItems":1}},"required":["code","label"]},"WeightOption":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"label":{"type":"string","minLength":1},"mass_g":{"type":"number","exclusiveMinimum":0},"part_number":{"type":"string","minLength":1}},"required":["code","mass_g"]},"WeightKit":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"weight_option_codes":{"type":"array","items":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"minItems":1}},"required":["code","name","weight_option_codes"]},"InstalledWeight":{"type":"object","additionalProperties":false,"properties":{"port_code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"position_code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"weight_option_code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"mass_g":{"type":"number","exclusiveMinimum":0}},"required":["port_code","mass_g"]},"WeightConfiguration":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"installed":{"type":"array","items":{"$ref":"#/components/schemas/InstalledWeight"},"minItems":1}},"required":["code","installed"]},"WeightSystem":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","minLength":1},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"manufacturer":{"$ref":"#/components/schemas/NamedEntity"},"url":{"type":"string","format":"uri","pattern":"^https?://"},"ports":{"type":"array","items":{"$ref":"#/components/schemas/EquipmentPort"},"minItems":1},"weight_options":{"type":"array","items":{"$ref":"#/components/schemas/WeightOption"},"minItems":1},"kits":{"type":"array","items":{"$ref":"#/components/schemas/WeightKit"},"minItems":1},"configurations":{"type":"array","items":{"$ref":"#/components/schemas/WeightConfiguration"},"minItems":1},"updated_at":{"type":"string","format":"date-time","pattern":"Z$"},"_links":{"type":"object","additionalProperties":false,"properties":{"self":{"type":"string","format":"uri","pattern":"^https?://"}},"required":["self"]}},"required":["id"],"x-required-unprojected":["id","slug","name","manufacturer","url","updated_at","_links"],"description":"Only the collections the manufacturer publishes are present; an absent collection is not published; it does not establish an empty collection."},"Shaft":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","minLength":1},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"manufacturer":{"$ref":"#/components/schemas/NamedEntity"},"url":{"type":"string","format":"uri","pattern":"^https?://"},"spec_options":{"type":"array","items":{"$ref":"#/components/schemas/ShaftSpecOption"},"minItems":1},"updated_at":{"type":"string","format":"date-time","pattern":"Z$"},"_links":{"type":"object","additionalProperties":false,"properties":{"self":{"type":"string","format":"uri","pattern":"^https?://"}},"required":["self"]}},"required":["id"],"x-required-unprojected":["id","slug","name","manufacturer","url","spec_options","updated_at","_links"]},"Grip":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","minLength":1},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"manufacturer":{"$ref":"#/components/schemas/NamedEntity"},"url":{"type":"string","format":"uri","pattern":"^https?://"},"spec_options":{"type":"array","items":{"$ref":"#/components/schemas/GripSpecOption"},"minItems":1},"updated_at":{"type":"string","format":"date-time","pattern":"Z$"},"_links":{"type":"object","additionalProperties":false,"properties":{"self":{"type":"string","format":"uri","pattern":"^https?://"}},"required":["self"]}},"required":["id"],"x-required-unprojected":["id","slug","name","manufacturer","url","spec_options","updated_at","_links"]},"EquipmentList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CoreEquipment"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]},"WeightSystemList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WeightSystem"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]},"ShaftList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Shaft"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]},"GripList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Grip"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]},"ManufacturerCoverage":{"type":"object","additionalProperties":false,"properties":{"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"records":{"type":"integer","minimum":1},"years":{"type":"object","additionalProperties":{"type":"integer","minimum":0},"description":"Records this manufacturer published, by `release_year`. A year with none is absent from this map."},"fields":{"type":"object","additionalProperties":{"type":"integer","minimum":0},"description":"How many of this manufacturer's records carry each field. The keys are the Core document's top-level fields plus `hosel_summary.adjustable`, counted from the Core document; fields defined but carried by nothing appear at 0."}},"required":["slug","name","records","years","fields"],"description":"One manufacturer's row of the grid."},"ResourceCoverage":{"type":"object","additionalProperties":false,"properties":{"resource":{"type":"string","enum":["drivers","mini-drivers","fairway-woods","hybrids","irons","wedges","putters"]},"version":{"type":"string","format":"date"},"complete":{"type":"boolean","description":"Whether every eligible head in this club type's launch scope is published. False, and never computed from the counts below: a populated cell is not evidence that its eligible head set is exhaustive. It turns true only on a separate owner decision that establishes an exhaustive denominator."},"records":{"type":"integer","minimum":0},"years":{"type":"object","additionalProperties":{"type":"integer","minimum":0},"description":"Counts keyed by name. Every key the served shape defines for this club type is present, including the ones at 0: a field that is defined and carried by nothing is exactly what a caller needs to know before building on it, and omitting the key would make that indistinguishable from 'not a field'. A field the club type does not define is absent rather than 0."},"fields":{"type":"object","additionalProperties":{"type":"integer","minimum":0},"description":"Counts keyed by name. Every key the served shape defines for this club type is present, including the ones at 0: a field that is defined and carried by nothing is exactly what a caller needs to know before building on it, and omitting the key would make that indistinguishable from 'not a field'. A field the club type does not define is absent rather than 0."},"manufacturers":{"type":"array","items":{"$ref":"#/components/schemas/ManufacturerCoverage"},"description":"Largest first, ties broken on slug, so the order is stable between builds."}},"required":["resource","version","complete","records","years","fields","manufacturers"],"description":"Published counts for one club type. The years map is keyed by release_year. Counts cover the resources accessible to the key."},"ResourceChanges":{"type":"object","additionalProperties":false,"required":["added","updated","removed"],"properties":{"added":{"type":"array","items":{"type":"string","pattern":"^clb_"}},"updated":{"type":"array","description":"Clubs whose Core, Club-builder or Market document changed.","items":{"type":"string","pattern":"^clb_"}},"removed":{"type":"array","description":"Clubs no longer published. Their ids answer 410.","items":{"type":"string","pattern":"^clb_"}}}},"CatalogRelease":{"type":"object","additionalProperties":false,"required":["release","published_at","changes"],"properties":{"release":{"type":"string","pattern":"^bld_"},"published_at":{"type":"string","format":"date-time"},"changes":{"type":"object","description":"Keyed by club resource. A resource with no change is absent.","additionalProperties":{"$ref":"#/components/schemas/ResourceChanges"}}}},"ChangeList":{"type":"object","additionalProperties":false,"required":["after","data","page"],"properties":{"after":{"type":"string","pattern":"^bld_"},"data":{"type":"array","items":{"$ref":"#/components/schemas/CatalogRelease"}},"page":{"type":"object","additionalProperties":false,"required":["limit","has_more"],"properties":{"limit":{"type":"integer"},"has_more":{"type":"boolean"},"next":{"type":"string","description":"Pass as cursor, with the same after, for the next page."}}}}},"Coverage":{"type":"object","additionalProperties":false,"properties":{"build":{"type":"string","pattern":"^bld_"},"published_at":{"type":"string","format":"date-time","pattern":"Z$"},"catalog_complete":{"type":"boolean","description":"Whether the catalog covers its launch scope. False. Every count in this response describes published records, so a search miss, an empty page and a 404 are statements about this build and not about what exists."},"note":{"type":"string","minLength":1,"description":"Plain-language restatement of what the counts do and do not establish."},"resources":{"type":"array","items":{"$ref":"#/components/schemas/ResourceCoverage"},"description":"Only club types accessible to this key."}},"required":["build","published_at","catalog_complete","resources"],"description":"Published record counts by resource, manufacturer, release year and field presence. Counts describe the published build; an empty result does not establish that a product does not exist."},"Index":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string","minLength":1},"description":{"type":"string","minLength":1},"documentation":{"type":"string","format":"uri","pattern":"^https?://"},"openapi":{"type":"string","format":"uri","pattern":"^https?://"},"openapi_well_known":{"type":"string","format":"uri","pattern":"^https?://"},"docs":{"type":"string","format":"uri","pattern":"^https?://"},"mcp":{"type":"object","additionalProperties":false,"properties":{"url":{"type":"string","format":"uri","pattern":"^https?://","description":"The MCP server's address."},"transport":{"type":"string","minLength":1},"oauth":{"type":"string","format":"uri","pattern":"^https?://","description":"The server's OAuth protected-resource metadata."},"guide":{"type":"string","format":"uri","pattern":"^https?://"},"note":{"type":"string","minLength":1}},"required":["url","transport","oauth","guide","note"],"description":"The read-only MCP server. Each tool sends one GET to this API with the caller's key."},"entitlements":{"type":"array","items":{"type":"string","minLength":1},"description":"Resources the sent key can read. Present only when the request carries a known key."},"pinned_version":{"type":"string","minLength":1,"description":"The response version the sent key is pinned to. Present only when the request carries a known key."},"catalog_release":{"type":"string","pattern":"^bld_[0-9A-Z]{26}$","description":"The build the sent key reads now. Pass it to /changes as after. Present only when the request carries a known key and the live build was read."},"catalog_published":{"type":"string","format":"date-time","description":"When catalog_release was published. Present with catalog_release."},"version":{"type":"object","additionalProperties":false,"properties":{"current":{"type":"string","format":"date","description":"The one version served, and the default when Golfapi-Version is omitted."},"header":{"type":"string","const":"Golfapi-Version"},"retired":{"type":"array","items":{"type":"string","format":"date"},"description":"Versions no longer served. A request naming one is 400."},"deprecated":{"type":"array","description":"Replaced versions still served until their sunset date, at least 90 days after the replacement shipped. Responses in one carry Deprecation, Sunset and a Link to the notice.","items":{"type":"object","additionalProperties":false,"required":["version","deprecated_on","sunset","notice"],"properties":{"version":{"type":"string","format":"date"},"deprecated_on":{"type":"string","format":"date"},"sunset":{"type":"string","format":"date"},"notice":{"type":"string","format":"uri"}}}},"note":{"type":"string","minLength":1,"description":"Plain-language restatement of the version rule. `current` is not the API's release number, which this index does not carry."}},"required":["current","header","retired","note"]},"authentication":{"type":"object","additionalProperties":false,"properties":{"scheme":{"type":"string","const":"Bearer"},"header":{"type":"string","const":"Authorization"},"format":{"type":"string","minLength":1},"note":{"type":"string","minLength":1}},"required":["scheme","header","format","note"]},"rate_limit":{"type":"object","additionalProperties":false,"properties":{"limit":{"type":"integer"},"window_seconds":{"type":"integer"},"headers":{"type":"array","items":{"type":"string","minLength":1},"minItems":1},"note":{"type":"string","minLength":1}},"required":["limit","window_seconds"],"description":"The default cap and the window it applies over, stated before the first request rather than only on the RateLimit-* headers of the response to it. A key's own cap can differ and is always on RateLimit-Limit."},"resources":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string","minLength":1},"entitlement":{"type":"string","minLength":1},"serving":{"type":"string","format":"date","description":"The version this resource answers at, which is `version.current`. It does not indicate whether the resource has been published."},"published":{"type":"boolean","description":"Whether the resource has a published catalog. An entitled request to an unpublished resource returns 503."},"list":{"type":"string","format":"uri","pattern":"^https?://"},"detail":{"type":"string","minLength":1},"sub_resources":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string","minLength":1},"entitlement":{"type":"string","minLength":1},"path":{"type":"string","minLength":1}},"required":["name","entitlement","path"]},"minItems":1,"description":"Routes hanging off this resource's detail path. Present only on resources that have them."}},"required":["name","entitlement","serving","published","list","detail"]},"minItems":1},"conventions":{"type":"object","additionalProperties":false,"properties":{"ordering":{"type":"string","minLength":1},"absent_fields":{"type":"string","minLength":1},"view":{"type":"string","minLength":1},"prices":{"type":"string","minLength":1}},"required":["ordering","absent_fields","view"],"description":"Shared rules for list order, absent fields and served document depth."},"coverage":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string","const":"coverage"},"entitlement":{"type":"string","minLength":1},"path":{"type":"string","format":"uri","pattern":"^https?://"},"note":{"type":"string","minLength":1}},"required":["name","entitlement","path","note"],"description":"Published catalog counts by manufacturer and release year. Use coverage to assess the published scope before interpreting an empty result."},"changes":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string","const":"changes"},"entitlement":{"type":"string","minLength":1},"path":{"type":"string","format":"uri","pattern":"^https?://"},"note":{"type":"string","minLength":1}},"required":["name","entitlement","path","note"],"description":"Club ids each catalog release changed. Use it to refresh a stored copy without a full rescan."},"health":{"type":"string","format":"uri","pattern":"^https?://"}},"required":["name","description","documentation","openapi","openapi_well_known","docs","version","authentication","rate_limit","resources","conventions","coverage","health"],"description":"The discovery index. Generated from the same registries the router is built from, and includes publication and version information."},"Health":{"type":"object","additionalProperties":false,"properties":{"ok":{"type":"boolean"},"db":{"type":"string","enum":["ok","error","unconfigured"]},"missing":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"description":"Registered resources whose catalog table this target lacks. Apply that resource's migration."},"unservable":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"description":"Resources migrated but with nothing published to serve. Materialize and publish the build."},"degraded":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"description":"Club types whose tables carry a document column the published build left unfilled, as `<resource>@<version>`. An operator signal: materialize and publish the build. It is not part of ok."},"request_id":{"type":"string","pattern":"^req_"}},"required":["ok","db"],"description":"Not a liveness check. 503 here can mean one registered club type is missing while every other resource serves normally, so a monitor must not read it as a total outage."},"IronHeadCore":{"type":"object","additionalProperties":false,"properties":{"designation":{"type":"string","enum":["1","2","3","4","5","6","7","8","9","pw","aw","gw","sw","lw"]},"loft_deg":{"type":"number","exclusiveMinimum":0},"lie_deg":{"type":"number","exclusiveMinimum":0}},"required":["designation"],"description":"One iron of the set, by designation: `4` to `9`, `pw`, `aw`, `gw`, `sw`, `lw`. A partial set lists only the irons the record states."},"IronHead":{"type":"object","additionalProperties":false,"properties":{"designation":{"type":"string","enum":["1","2","3","4","5","6","7","8","9","pw","aw","gw","sw","lw"]},"loft_deg":{"type":"number","exclusiveMinimum":0},"lie_deg":{"type":"number","exclusiveMinimum":0},"length_in":{"type":"number","exclusiveMinimum":0},"offset_in":{"type":"number","minimum":0},"offset_mm":{"type":"number","minimum":0,"description":"Offset in millimetres, present when the maker prints the offset in millimetres. Never converted from offset_in."}},"required":["designation"],"description":"One iron of the set with its stock build length and offset."},"IronVariant":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^var_[0-9A-HJKMNP-TV-Z]{26}$"},"designation":{"type":"string","enum":["1","2","3","4","5","6","7","8","9","pw","aw","gw","sw","lw"]},"hand":{"type":"string","enum":["rh","lh"]},"market":{"type":"string","pattern":"^[A-Z]{2}$"}},"required":["id","designation","hand","market"],"description":"One iron in one hand and market, as the record states it. A combination the record does not name is not listed."},"IronCore":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^clb_[0-9A-HJKMNP-TV-Z]{26}$"},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"club_type":{"type":"string","enum":["driver","mini-driver","fairway-wood","hybrid","iron","wedge","putter"],"description":"The resource this club belongs to: driver, mini-driver, fairway-wood, hybrid, iron (a set), wedge or putter."},"summary":{"type":"string","minLength":1,"maxLength":160,"description":"One sentence naming the club, its maker, introduction year, club type and family. Built from this document's fields at each catalog build. Contains no specifications and no performance or suitability claims."},"manufacturer":{"$ref":"#/components/schemas/NamedEntity"},"family":{"$ref":"#/components/schemas/NamedEntity"},"release_year":{"type":"integer","minimum":1900,"maximum":2100,"description":"The year the manufacturer released this head. Present on every club."},"released":{"type":"string","format":"date","description":"First US retail availability, as an exact date. Absent when only `release_year` is known."},"hands":{"type":"array","items":{"type":"string","enum":["rh","lh"]},"minItems":1,"uniqueItems":true,"maxItems":2,"enum":[["rh"],["lh"],["rh","lh"]],"description":"Available hands, ordered rh then lh."},"irons":{"type":"array","items":{"$ref":"#/components/schemas/IronHeadCore"},"minItems":1,"description":"Per-iron loft and lie."},"variants":{"type":"array","items":{"$ref":"#/components/schemas/IronVariant"},"minItems":1,"description":"One entry per designation, hand and market the record names."},"url":{"type":"string","format":"uri","pattern":"^https://","description":"Canonical club URL."},"updated_at":{"type":"string","format":"date-time","pattern":"Z$","description":"When this response document last changed. Compare within the same view when refreshing a stored catalog; there is no updated_after filter."}},"required":["id"],"description":"The Core iron document: a model's identity and its per-iron loft and lie.","x-required-unprojected":["id","slug","name","manufacturer","release_year","url","updated_at"]},"IronExpanded":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^clb_[0-9A-HJKMNP-TV-Z]{26}$"},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"club_type":{"type":"string","enum":["driver","mini-driver","fairway-wood","hybrid","iron","wedge","putter"],"description":"The resource this club belongs to: driver, mini-driver, fairway-wood, hybrid, iron (a set), wedge or putter."},"summary":{"type":"string","minLength":1,"maxLength":160,"description":"One sentence naming the club, its maker, introduction year, club type and family. Built from this document's fields at each catalog build. Contains no specifications and no performance or suitability claims."},"manufacturer":{"$ref":"#/components/schemas/NamedEntity"},"family":{"$ref":"#/components/schemas/NamedEntity"},"release_year":{"type":"integer","minimum":1900,"maximum":2100,"description":"The year the manufacturer released this head. Present on every club."},"released":{"type":"string","format":"date","description":"First US retail availability, as an exact date. Absent when only `release_year` is known."},"hands":{"type":"array","items":{"type":"string","enum":["rh","lh"]},"minItems":1,"uniqueItems":true,"maxItems":2,"enum":[["rh"],["lh"],["rh","lh"]],"description":"Available hands, ordered rh then lh."},"irons":{"type":"array","items":{"$ref":"#/components/schemas/IronHead"},"minItems":1,"description":"Per-iron loft, lie, length and offset."},"variants":{"type":"array","items":{"$ref":"#/components/schemas/IronVariant"},"minItems":1,"description":"One entry per designation, hand and market the record names."},"url":{"type":"string","format":"uri","pattern":"^https://","description":"Canonical club URL."},"updated_at":{"type":"string","format":"date-time","pattern":"Z$","description":"When this response document last changed. Compare within the same view when refreshing a stored catalog; there is no updated_after filter."},"_links":{"type":"object","additionalProperties":false,"properties":{"self":{"type":"string","format":"uri","pattern":"^https?://"}},"required":["self"]}},"required":["id"],"description":"The Club-builder iron document, served for `view=expanded`: Core plus each iron's length and offset.","x-required-unprojected":["id","slug","name","manufacturer","release_year","url","updated_at"]},"WedgeVariantCore":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^var_[0-9A-HJKMNP-TV-Z]{26}$"},"hand":{"type":"string","enum":["rh","lh"]},"market":{"type":"string","pattern":"^[A-Z]{2}$"},"loft_deg":{"type":"number","exclusiveMinimum":0},"bounce_deg":{"type":"number","minimum":0},"grind":{"type":"string","minLength":1},"lie_deg":{"type":"number","exclusiveMinimum":0}},"required":["id","hand","market","loft_deg"],"description":"One loft, bounce, grind, hand and market. `grind` is the manufacturer's grind or sole-profile label as given; an absent bounce or grind is unknown."},"WedgeVariant":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^var_[0-9A-HJKMNP-TV-Z]{26}$"},"hand":{"type":"string","enum":["rh","lh"]},"market":{"type":"string","pattern":"^[A-Z]{2}$"},"loft_deg":{"type":"number","exclusiveMinimum":0},"bounce_deg":{"type":"number","minimum":0},"grind":{"type":"string","minLength":1},"lie_deg":{"type":"number","exclusiveMinimum":0},"length_in":{"type":"number","exclusiveMinimum":0}},"required":["id","hand","market","loft_deg"],"description":"A wedge variant with its stock build length."},"WedgeCore":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^clb_[0-9A-HJKMNP-TV-Z]{26}$"},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"club_type":{"type":"string","enum":["driver","mini-driver","fairway-wood","hybrid","iron","wedge","putter"],"description":"The resource this club belongs to: driver, mini-driver, fairway-wood, hybrid, iron (a set), wedge or putter."},"summary":{"type":"string","minLength":1,"maxLength":160,"description":"One sentence naming the club, its maker, introduction year, club type and family. Built from this document's fields at each catalog build. Contains no specifications and no performance or suitability claims."},"manufacturer":{"$ref":"#/components/schemas/NamedEntity"},"family":{"$ref":"#/components/schemas/NamedEntity"},"release_year":{"type":"integer","minimum":1900,"maximum":2100,"description":"The year the manufacturer released this head. Present on every club."},"released":{"type":"string","format":"date","description":"First US retail availability, as an exact date. Absent when only `release_year` is known."},"lofts_deg":{"type":"array","items":{"type":"number","exclusiveMinimum":0},"minItems":1,"uniqueItems":true,"description":"Sorted union of offered nominal lofts."},"hands":{"type":"array","items":{"type":"string","enum":["rh","lh"]},"minItems":1,"uniqueItems":true,"maxItems":2,"enum":[["rh"],["lh"],["rh","lh"]],"description":"Available hands, ordered rh then lh."},"variants":{"type":"array","items":{"$ref":"#/components/schemas/WedgeVariantCore"},"minItems":1},"url":{"type":"string","format":"uri","pattern":"^https://","description":"Canonical club URL."},"updated_at":{"type":"string","format":"date-time","pattern":"Z$","description":"When this response document last changed. Compare within the same view when refreshing a stored catalog; there is no updated_after filter."}},"required":["id"],"description":"The Core wedge document.","x-required-unprojected":["id","slug","name","manufacturer","release_year","url","updated_at"]},"WedgeExpanded":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^clb_[0-9A-HJKMNP-TV-Z]{26}$"},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"club_type":{"type":"string","enum":["driver","mini-driver","fairway-wood","hybrid","iron","wedge","putter"],"description":"The resource this club belongs to: driver, mini-driver, fairway-wood, hybrid, iron (a set), wedge or putter."},"summary":{"type":"string","minLength":1,"maxLength":160,"description":"One sentence naming the club, its maker, introduction year, club type and family. Built from this document's fields at each catalog build. Contains no specifications and no performance or suitability claims."},"manufacturer":{"$ref":"#/components/schemas/NamedEntity"},"family":{"$ref":"#/components/schemas/NamedEntity"},"release_year":{"type":"integer","minimum":1900,"maximum":2100,"description":"The year the manufacturer released this head. Present on every club."},"released":{"type":"string","format":"date","description":"First US retail availability, as an exact date. Absent when only `release_year` is known."},"lofts_deg":{"type":"array","items":{"type":"number","exclusiveMinimum":0},"minItems":1,"uniqueItems":true,"description":"Sorted union of offered nominal lofts."},"hands":{"type":"array","items":{"type":"string","enum":["rh","lh"]},"minItems":1,"uniqueItems":true,"maxItems":2,"enum":[["rh"],["lh"],["rh","lh"]],"description":"Available hands, ordered rh then lh."},"variants":{"type":"array","items":{"$ref":"#/components/schemas/WedgeVariant"},"minItems":1},"url":{"type":"string","format":"uri","pattern":"^https://","description":"Canonical club URL."},"updated_at":{"type":"string","format":"date-time","pattern":"Z$","description":"When this response document last changed. Compare within the same view when refreshing a stored catalog; there is no updated_after filter."},"_links":{"type":"object","additionalProperties":false,"properties":{"self":{"type":"string","format":"uri","pattern":"^https?://"}},"required":["self"]}},"required":["id"],"description":"The Club-builder wedge document, served for `view=expanded`: Core plus each variant's length.","x-required-unprojected":["id","slug","name","manufacturer","release_year","url","updated_at"]},"PutterVariant":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^var_[0-9A-HJKMNP-TV-Z]{26}$"},"hand":{"type":"string","enum":["rh","lh"]},"market":{"type":"string","pattern":"^[A-Z]{2}$"},"neck":{"type":"string","pattern":"^[a-z0-9]+([ -][a-z0-9]+)*$"},"length_in":{"type":"number","exclusiveMinimum":0},"loft_deg":{"type":"number","minimum":0},"lie_deg":{"type":"number","exclusiveMinimum":0}},"required":["id","hand","market"],"description":"One hand, neck, length and market. `neck` is the manufacturer's name for the neck, lower-case."},"PutterCore":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^clb_[0-9A-HJKMNP-TV-Z]{26}$"},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"club_type":{"type":"string","enum":["driver","mini-driver","fairway-wood","hybrid","iron","wedge","putter"],"description":"The resource this club belongs to: driver, mini-driver, fairway-wood, hybrid, iron (a set), wedge or putter."},"summary":{"type":"string","minLength":1,"maxLength":160,"description":"One sentence naming the club, its maker, introduction year, club type and family. Built from this document's fields at each catalog build. Contains no specifications and no performance or suitability claims."},"manufacturer":{"$ref":"#/components/schemas/NamedEntity"},"family":{"$ref":"#/components/schemas/NamedEntity"},"release_year":{"type":"integer","minimum":1900,"maximum":2100,"description":"The year the manufacturer released this head. Present on every club."},"released":{"type":"string","format":"date","description":"First US retail availability, as an exact date. Absent when only `release_year` is known."},"hands":{"type":"array","items":{"type":"string","enum":["rh","lh"]},"minItems":1,"uniqueItems":true,"maxItems":2,"enum":[["rh"],["lh"],["rh","lh"]],"description":"Available hands, ordered rh then lh."},"variants":{"type":"array","items":{"$ref":"#/components/schemas/PutterVariant"},"minItems":1},"url":{"type":"string","format":"uri","pattern":"^https://","description":"Canonical club URL."},"updated_at":{"type":"string","format":"date-time","pattern":"Z$","description":"When this response document last changed. Compare within the same view when refreshing a stored catalog; there is no updated_after filter."}},"required":["id"],"description":"The Core putter document.","x-required-unprojected":["id","slug","name","manufacturer","release_year","url","updated_at"]},"PutterExpanded":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^clb_[0-9A-HJKMNP-TV-Z]{26}$"},"slug":{"type":"string","pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"},"name":{"type":"string","minLength":1},"club_type":{"type":"string","enum":["driver","mini-driver","fairway-wood","hybrid","iron","wedge","putter"],"description":"The resource this club belongs to: driver, mini-driver, fairway-wood, hybrid, iron (a set), wedge or putter."},"summary":{"type":"string","minLength":1,"maxLength":160,"description":"One sentence naming the club, its maker, introduction year, club type and family. Built from this document's fields at each catalog build. Contains no specifications and no performance or suitability claims."},"manufacturer":{"$ref":"#/components/schemas/NamedEntity"},"family":{"$ref":"#/components/schemas/NamedEntity"},"release_year":{"type":"integer","minimum":1900,"maximum":2100,"description":"The year the manufacturer released this head. Present on every club."},"released":{"type":"string","format":"date","description":"First US retail availability, as an exact date. Absent when only `release_year` is known."},"hands":{"type":"array","items":{"type":"string","enum":["rh","lh"]},"minItems":1,"uniqueItems":true,"maxItems":2,"enum":[["rh"],["lh"],["rh","lh"]],"description":"Available hands, ordered rh then lh."},"variants":{"type":"array","items":{"$ref":"#/components/schemas/PutterVariant"},"minItems":1},"url":{"type":"string","format":"uri","pattern":"^https://","description":"Canonical club URL."},"updated_at":{"type":"string","format":"date-time","pattern":"Z$","description":"When this response document last changed. Compare within the same view when refreshing a stored catalog; there is no updated_after filter."},"_links":{"type":"object","additionalProperties":false,"properties":{"self":{"type":"string","format":"uri","pattern":"^https?://"}},"required":["self"]}},"required":["id"],"description":"The Club-builder putter document, served for `view=expanded`.","x-required-unprojected":["id","slug","name","manufacturer","release_year","url","updated_at"]},"IronCoreList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/IronCore"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]},"IronExpandedList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/IronExpanded"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]},"WedgeCoreList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WedgeCore"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]},"WedgeExpandedList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WedgeExpanded"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]},"PutterCoreList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PutterCore"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]},"PutterExpandedList":{"type":"object","additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PutterExpanded"}},"page":{"$ref":"#/components/schemas/Page"}},"required":["data","page"]}}},"x-semantic-invariants":["every route is a GET; a routed path reached by another method is 405 with Allow","lofts_deg and loft_adjustment_deg are sorted distinct arrays","hands order rh then lh","unprojected objects omit unknown optional values and preserve real false and zero","an unprojected response carries every field in its schema's x-required-unprojected; `fields=` is the only thing that removes one, and `id` survives every projection","page.next is present exactly when page.has_more is true","public discovery and health routes reject unknown query parameters with 400; catalog list and detail routes do too; hosel-system, clubs and equipment routes ignore them as documented on those routes","an ETag covers the representation, not only the record: view, fields and variants can change it","a 304 is refunded and does not count against the rate limit, and its RateLimit-Remaining reports the refunded budget","a 4xx other than 401 and 429 is refunded the same way, and its RateLimit-Remaining reports the refunded budget","a path with a trailing slash redirects 301 to the canonical path and is never a 404"],"x-forge-commands":{"changes":{"description":"Clubs added, updated or removed in each catalog release after a given one."},"coverage":{"description":"What the published catalog holds, by manufacturer and year."},"drivers":{"description":"Driver models: list them, fetch one, and read a model's hosel context."},"fairway-woods":{"description":"Fairway wood models: list them, fetch one, and read a model's hosel context."},"grips":{"description":"Grips, as components. Needs the grips entitlement."},"hosel-systems":{"description":"Hosel systems and the clubs fitted with them. Needs the club-builder entitlement."},"hybrids":{"description":"Hybrid models: list them, fetch one, and read a model's hosel context."},"irons":{"description":"Iron models: list them and fetch one."},"mini-drivers":{"description":"Mini-driver models: list them, fetch one, and read a model's hosel context."},"putters":{"description":"Putter models: list them and fetch one."},"service":{"description":"Discovery, health and the contract itself. No key is needed for any of them."},"shafts":{"description":"Shafts, as components. Needs the shafts entitlement."},"wedges":{"description":"Wedge models: list them and fetch one."},"weight-systems":{"description":"Weight systems, as components. Needs the weight-systems entitlement."}}}