Versioning

Two numbers are published, and they say different things.

Number Where What it names
v1 The path, https://api.doc.cheap/v1/… The API: its endpoints, its authentication, its error shape
1.0 meta.schema_version in every result The revision of the response body

One response shape exists, and no way to ask for another. A request that tries to select one is refused with 422 validation_failed naming what it sent. Silently serving the only shape there is would leave the caller believing something else arrived.

meta.schema_version

Every result carries it, and its value is "1.0".

It is a string, not a number: "1.0" and "1.10" are different revisions, and arithmetic on them is wrong.

A consumer that pins the value fails loudly on a revision it was not written for, which is the point of publishing it. A consumer that reads the body without checking gets whatever the current revision means by each key.

What counts as breaking

A breaking change is one that can turn a working consumer into a broken one without the consumer changing.

Change Breaking
Removing a key from a response Yes
Renaming a key Yes
Narrowing a type — a nullable key that stops being nullable is not breaking; one that starts being nullable is Yes, when it widens
Adding a value to an enum a consumer branches on Yes
Removing a request field Yes
Making an optional request field required Yes
Changing what an existing key means, at the same type Yes
Adding a key to a response No
Adding an optional request field No
Adding a new endpoint No
Adding an error code to an endpoint that already answers errors No
Widening an accepted range No

A removal or a rename moves the major segment of meta.schema_version. An addition moves the minor segment.

What a consumer should assume

A consumer built on those four assumptions survives every change in the non-breaking column without a release.

How a breaking change would be announced

Nothing here has broken yet — version 1 is the first production version, and this section describes what would happen rather than what has.

A breaking change to the response body would arrive as a new major meta.schema_version. The previous revision would keep being served to callers that ask for it, by a mechanism published with the change. A breaking change to the API itself would arrive under a new path segment beside /v1, and /v1 would keep answering.

Either would be announced on the changelog, which carries an Atom feed at /changelog/feed.xml, before the change lands rather than with it.

An address, once published, keeps working. The per-code error pages are the clearest case. docs_url in an error body is /errors/<code>, and a body already sent cannot be rewritten, so those addresses do not move.

What is not versioned