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 envelope —
data+paginationon lists,dataon single resources,erroron failures. - Change what an identifier addresses. An
idyou 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:
| Change | Why it is safe |
|---|---|
| Adding a field to a response | Ignore fields you do not use. Do not use a strict deserialiser that rejects unknown keys. |
| Adding an endpoint or a query parameter | Nothing existing moves. |
| Adding an error code | Handle unknown codes by their HTTP status. See Errors. |
| Adding a value to an enum | New boat types and categories are editorial data, not schema. Treat an unrecognised slug as data, not as a bug. |
| Reordering fields in a JSON object | JSON objects are unordered. |
Changing a message string | Messages are for humans. Branch on error.code. |
| Catalogue content changing | A boat gaining a specification, a manufacturer being renamed, new records appearing. This is the point of the API. |
| Performance, caching and rate-limit headers | Observable, 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.
/v2is published alongside/v1, with a migration guide naming every difference./v1is marked deprecated. Every/v1response then carries aDeprecationheader and aSunsetheader with the retirement date (RFC 9745 / RFC 8594), plus aLinkheader pointing at the migration guide. Your monitoring can see this without anyone reading an email.- We email every key owner whose keys have made a
/v1request in the previous 90 days. Deprecation notices go to the people whose integrations are actually running, not to a mailing list. /v1keeps working for at least 12 months from the deprecation announcement. We will not shorten that window.- After sunset,
/v1returns410 Gonewith 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.