Versioning
This page is the promise the rest of the site relies on. Every “branch on the code, not the message” and “handle an unfamiliar code gracefully” elsewhere is only advice because of what is written here.
The unit of compatibility is /v1
/v1 is the HTTP major version. Additive changes stay on /v1. A breaking change
means /v2, announced before it exists, served alongside /v1.
There is no /v1.1 and there will not be. A path that grows minor versions turns one
integration decision into a recurring migration, and the number in the path stops
meaning anything. The contract’s own release version lives in info.version inside the
OpenAPI document, where a tool can read it and your URLs do not have
to change.
Additive: expect these, do not break on them
Strict schema validation that rejects unknown fields will break on a routine release. If your stack validates responses, configure it to allow additional properties.
Breaking: these get a new major and a notice first
- removing an endpoint, or an operation’s
operationId; - removing a response field, or making an optional request field required;
- changing a field’s type, or narrowing an accepted value range;
- removing a member of a closed enum —
JobStatusis closed atqueued | running | succeeded | failed | cancelled, so adding a state is breaking too; - renaming or removing an error code;
- changing what authentication is required, or which scope an operation needs;
- changing the meaning of an existing field while keeping its name and type.
The last one is the dangerous entry, because it passes every mechanical check. It is treated as breaking anyway.
error.code is the contract; error.message is not
error.code is stable and machine-readable. error.message is human text that is
rewritten whenever it can be made clearer, in a patch release, without notice. Code
that matches on message substrings will break, and the break will look like ours.
Errors
request_id is always present and always opaque. Log it; do not parse it.
What the enum promise actually is
A field documented with a fixed set of values will not lose one of them without a major version. It may gain one if the field is documented as open. Where that matters for a product — the skin issue list, the makeup product matrix — the page for that product says which it is.
Deprecation
Nothing is removed from /v1 without first being marked deprecated in the contract. A
deprecated operation keeps working exactly as documented, is flagged deprecated: true
in the API reference, and answers Deprecation and Sunset headers
so your monitoring can see it before your users do. The notice period for a specific
change is stated with the change; a binding one belongs in your agreement.