/v1 in the URL is a major-version boundary only — it does not let you pin the exact response shape your integration was built against, and it gives HASP no way to evolve response shapes without either breaking every caller at once or accumulating parallel major URL versions forever. HASP solves this the way Stripe does: a dated version, independent of the URL, resolved per request.
How a version resolves
Every request resolves to exactly one dated version (YYYY-MM-DD), in this order:
- The
Hasp-Versionrequest header, if sent — an explicit per-request override. - Your API key’s pinned default, if one is configured.
- The deployment’s current default version, if neither of the above applies.
Hasp-Version response header, so you can confirm what actually applied without guessing:
Hasp-Version value this deployment doesn’t recognize is rejected with 400 INVALID_API_VERSION before the request does anything else — it never silently falls back to a different version. That rejection response predates version resolution, so (like a 404 for an unrecognized route) it does not carry a Hasp-Version response header.
Per-key pinning
Every API key carries its own default dated version (pinned_api_version) — every request made with that key resolves to the pinned version unless the request explicitly overrides it with its own Hasp-Version header. This is the recommended way to run a production integration long-term: pin the key once, and every deploy of your integration keeps working exactly as built, with no header required on every call. The request header always wins over the key’s pin — useful for testing an upcoming version against a key still pinned to an older one.
Only one dated version exists today, so every key currently resolves to it either way. Self-serve key pinning (setting pinned_api_version yourself, via the dashboard or the API) ships alongside the first additional dated version — check the changelog when that lands.
A pinned version never breaks
This is the core guarantee: once a dated version is published, HASP never changes what it returns to a caller pinned to that version — not a renamed field, not a removed field, not a changed status code for an existing condition. A change that would alter an existing version’s shape or semantics always ships as a new dated version, together with exactly one transformer translating the new shape back to each still-supported older version. Old and new callers each keep receiving exactly the shape their pinned version promised. What’s always safe (non-breaking, ships within the current version, no new date required):- Adding a new field to a response.
- Adding a new endpoint.
- Adding a new dated version.
- Adding a new possible value to an already-open-ended set (e.g. a new webhook event type).
- Renaming, removing, or changing the type of an existing field.
- Changing an existing endpoint’s default behavior.
- Changing the meaning or status code of an existing error condition.
- Narrowing an existing behavior (e.g. a previously-unbounded field becoming validated).
/v1 and dated versions are independent axes
/v1 is the API’s major/URL version — it changes only for an incompatible architectural shift, not for the routine evolution dated versions absorb. Dated versions evolve within /v1 and do not by themselves justify a new URL major version. In practice, expect /v1 to stay /v1 for a very long time, with dated versions carrying almost all forward evolution.
The OAuth 2.1 token-issuance and discovery endpoints (/v1/oauth/*, /.well-known/*) sit outside the dated-version framework entirely — they authenticate the caller rather than act as the caller, run before version resolution in the request lifecycle, and return the standard OAuth/RFC 8414 wire shapes their specs require rather than a HASP-versioned response.
Deprecation
When a dated version is deprecated (a newer version has superseded it and its support window has begun winding down), responses served under that version carry standard deprecation headers so automated tooling — not just a human reading changelog — can detect it:Deprecation: true signals the version you’re pinned to is no longer the recommended one; Sunset is the date after which HASP may stop accepting requests pinned to it. A deprecated version keeps returning the exact shape it always has — deprecation headers are a notice to migrate, not a behavior change. Migrate before the Sunset date by re-pinning your API key (or your request’s Hasp-Version header) to a newer version and adjusting your integration for that version’s documented changes.
As of this writing, only one dated version (2026-07-12) exists, so no request currently receives these headers — this section documents the policy that takes effect the first time a second version ships.