Versioning & deprecation policy
Four version numbers, what moving each one means, and what happens before anything a caller depends on is ever removed.
Four independent versions
/v1 or /v2 in the path is URL generation: which family of endpoints and response shape this is. API_VERSION (in every /v2/health response) is the shape of /v2 requests and responses: field names, types, required-ness, enum values. score.version (SCORING_VERSION, reported on both /v1 and /v2) is the formula behind a score. titleScoreVersion (returned by POST /v2/titles) is the formula behind a title’sscore, which is a different question from a topic’s and therefore a different number. None of the four moves because one of the others did — a scoring recalibration never changes response shape, a response-shape change never changes how a score is computed, and neither touches how a title is scored. See the scoring methodology for what a scoring version covers.
What is a breaking change
An increase to API_VERSION’s major number, and advance notice in the changelog, for any of:
- Removing a field, an endpoint, or a request parameter
- Renaming a field, or changing its type
- Making an optional request field required, or a nullable response field non-null in a way that changes its meaning
- Narrowing an enum (removing a value another caller might branch on)
- Changing a status code a documented case returns, or the shape of the error envelope
- Changing authentication, or what a valid key looks like
Not breaking. These always get a changelog entry, and they never move the major number:
- Adding a new, optional field to a request
- Adding a new field to a response (a caller that reads specific fields is unaffected)
- Widening an enum by adding a new value (a caller must already tolerate an unrecognized one)
- Adding a new endpoint
- Fixing a response that did not match its documented schema, where the fix brings it back into line with what was always specified
Clarified 2026-09-27. This page previously said a breaking change moved API_VERSION’s “minor or major” number, which left a minor bump ambiguous. It is not: only the major number moves for a breaking change. A new capability that breaks nothing may move the minor number so a caller can tell which build it is talking to — 2.1.0 added POST /v2/titles and the insufficient_context error code, and took nothing away. A change that moves neither, such as a new response field, is announced in the changelog alone.
A scoring change is never breaking to the contract
A new SCORING_VERSION can change the number in score.overall for the same phrase — that is the point of a recalibration — but it never changes the response’s shape, so it is never an API_VERSION bump. A version 1 score and a version 2 score are simply not comparable; store score.version beside any score you keep, and treat a version change as a reason to re-run an old phrase rather than to trust the two numbers side by side.
How a deprecation is announced
Before a field, endpoint, or SDK version is removed, its responses carry a Deprecation header (the date it was deprecated) and, once a removal date is set, a Sunset header (that date) and a Link header pointing at its replacement or at this page. The same change is logged in the changelog, tagged Deprecation, on the day it is announced. A deprecated piece of the API keeps working, unchanged, until the sunset date — nothing is removed silently, and nothing is removed on the same day it is announced.
Worked example: how /v2 actually shipped
The error-envelope change above — a bare string becoming a structured object — is exactly the kind of thing this page says needs a new URL prefix, not a change inside the one that exists. It got one: /v2/analyze, /v2/suggest and /v2/health carry the new contract, and /v1/analyze, /v1/suggest and /v1/health keep answering exactly as they always did — same bare { "error": "..." } shape, no request id, no rate-limit headers, same status codes, down to the wording of each error message. The only thing added to a /v1 response is the Deprecation header itself; nothing a JSON parser reads changed. /v1 has its own OpenAPI document, separate from /v2’s and frozen the same way, at /v1/openapi.json. There is no Sunset header yet, and none will be added without notice here and in the changelog first.
What’s deprecated right now
/v1 in full (announced 2026-09-22, no sunset date set): every /v1/* response carries a Deprecation header. New integrations should build against /v2 directly — see the API reference or the step-by-step migration guide. Nothing else in the API is deprecated today; the header mechanism (src/lib/deprecation.ts) is otherwise unused, ready for the next time it is needed.
SDK versioning
@hitsonar/sdk and hitsonar version independently of API_VERSION and score.version, following ordinary semver for the package itself: a patch for a bug fix, a minor version for a backward-compatible addition (a new method, a new optional parameter), a major version only when the SDK’s own surface changes in a way existing code would need to adapt to. An SDK major version is not tied to an API major version in either direction — the SDK can gain a major version for its own reasons (say, dropping support for an old language runtime) while the API contract it talks to is unchanged, and vice versa. See the TypeScript SDK guide and the Python SDK guide.
