Two things carry a version: the HTTP API, and the release.

The API version

Every documented route is under /api/v1, and the prefix is a compatibility promise. Within v1: These will not change:
  • A route’s path or method.
  • A field’s name, type or meaning in a response.
  • The meaning of a status code for a given failure.
  • A scope’s name, or what it permits.
  • The pagination contract — cursors stay opaque and remain valid the way Pagination describes.
These may change without being a breaking change:
  • New fields appearing in a response. Parse leniently: a client that rejects unknown fields will break on an additive release, and that is the client’s bug rather than an API break.
  • New routes, new optional request fields, new enum members in a field documented as extensible.
  • The opaque contents of a cursor. Treat it as a token, never decode it.
  • Rate limits and quotas, which are operational rather than contractual. See Errors and limits.
A change that would break the first list means /api/v2, not an edit to v1.

The specification is the contract

The OpenAPI specification — the endpoint pages in the API reference are generated from it — is the machine-readable version of the above, and a test keeps it honest: it enumerates the routes the router actually registers and fails the build if the specification and the code disagree about which routes exist. Stated with its limit, because a guard trusted beyond its limit is worse than no guard: it covers routes and methods, not request and response schemas. Those are hand-written and can drift. If you find the specification and a response disagreeing on a field, the response is what the software does — please report it.

Release versions

Releases use semantic versioning on a tag: v0.1.0, then v0.2.0, v0.2.1, and so on. A release identifier orders releases and nothing more; it does not encode compatibility. The API version does that. This is worth stating twice under semver, because the scheme invites the opposite assumption: a major version bump here would describe the product — a migration that cannot be rolled back, a capability withdrawn — and the API underneath would still be /api/v1 unless the API itself broke. Read the changelog labels for upgrade safety, not the number. Releases before v0.1.0 were identified by date — the changelog entries numbered 2026.07, 2026.08 and 2026.09. Those identifiers are left as they were published rather than renumbered, so the record matches what was announced at the time.

Deprecation

A capability being replaced is announced as deprecated in the changelog entry that introduces its replacement, and the entry names what to move to. It keeps working until a release explicitly removes it, and that removal is labelled changed. There is no automatic sunset window and no Deprecation response header today. If you are building something long-lived against the API, the changelog is the surface to watch — it is where a deprecation is stated.

Database schema

The schema is not a public interface. It changes whenever a release needs it to, including in ways that would be breaking if anything outside TRUSTIVAN read it. Read the API, not the database. Reporting built on direct SQL against these tables will break on an upgrade, and the changelog will not warn you, because from the product’s point of view nothing user-facing changed.