Versioning and deprecation

This page is the promise. It is published before the first partner integrates, because a policy written after something breaks is not a policy.

The version is in the path

Every endpoint lives under /v1. That prefix is the contract: for as long as /v1 is served, the guarantees below hold. There is no version header, no date-based pinning and no ?version= parameter — one URL, one contract, so the version a request ran against is visible in your own logs.

What /v1 guarantees

While /v1 exists, we will not:

  • Remove or rename a field in a response.
  • Change the type of a field, including turning a nullable field into a non-nullable one or a number into a string.
  • Remove an endpoint, or change what an existing one returns.
  • Remove a query parameter, or narrow what an existing one accepts.
  • Remove an error code, or change the HTTP status a given code is returned with.
  • Change the response envelopedata + pagination on lists, data on single resources, error on failures.
  • Change what an identifier addresses. An id you stored today resolves to the same boat in five years.

What we may change without a new version

These are not breaking changes, and your integration must tolerate them:

ChangeWhy it is safe
Adding a field to a responseIgnore fields you do not use. Do not use a strict deserialiser that rejects unknown keys.
Adding an endpoint or a query parameterNothing existing moves.
Adding an error codeHandle unknown codes by their HTTP status. See Errors.
Adding a value to an enumNew boat types and categories are editorial data, not schema. Treat an unrecognised slug as data, not as a bug.
Reordering fields in a JSON objectJSON objects are unordered.
Changing a message stringMessages are for humans. Branch on error.code.
Catalogue content changingA boat gaining a specification, a manufacturer being renamed, new records appearing. This is the point of the API.
Performance, caching and rate-limit headersObservable, but not part of the response contract.

The most common integration failure we see is a strict schema validator on the client that rejects an unknown field. Adding fields is explicitly allowed here, and our published OpenAPI response schemas do not set additionalProperties: false for exactly that reason. Configure your generated client to ignore unknown properties.

How a breaking change would happen

If we ever need to break the contract, we do it by publishing /v2. /v1 does not change under you.

  1. /v2 is published alongside /v1, with a migration guide naming every difference.
  2. /v1 is marked deprecated. Every /v1 response then carries a Deprecation header and a Sunset header with the retirement date (RFC 9745 / RFC 8594), plus a Link header pointing at the migration guide. Your monitoring can see this without anyone reading an email.
  3. We email every key owner whose keys have made a /v1 request in the previous 90 days. Deprecation notices go to the people whose integrations are actually running, not to a mailing list.
  4. /v1 keeps working for at least 12 months from the deprecation announcement. We will not shorten that window.
  5. After sunset, /v1 returns 410 Gone with a body pointing at /v2. It does not silently start behaving like /v2.

Twelve months is a floor, not a target. If usage on the old version is still significant as the date approaches, we extend it and say so — an integration that breaks on a date nobody at your end remembers is a worse outcome than us running two versions for another quarter.

Security is the one exception

We reserve the right to make a breaking change without notice if the alternative is leaving data exposed or a vulnerability unpatched. If that ever happens, the change is announced at the moment it ships, with an explanation of what it was.

This has not happened. It is stated because a policy with no exceptions is one nobody can honour.

Retiring a field without breaking you

A field we no longer wish to publish is marked deprecated in the OpenAPI document and in these docs, and keeps being returned for the life of /v1. It may become permanently null, but the key does not disappear and its type does not change.

Watching for changes

  • The OpenAPI document is generated from the code that serves the API, so every contract change shows up there first.
  • Deprecation and Sunset headers appear on responses, so a scheduled job can alert on them without anyone reading a changelog.
  • Email, to the key owner, for anything that needs a decision from you. This is why the name on a key matters: "staging importer" tells us who to contact about which integration.

If you are building something that would be expensive to migrate, email [email protected] and tell us. Knowing what partners depend on is what keeps the list of things we will not break honest.