Versioning and change policy
What `/v1` means, which changes we make in place, and what would force a new version.
Every path is prefixed /v1. There is one live version, and there is no /v2.
What we change in place
/v1 receives additive and corrective changes without a new version:
- New operations, and new optional request fields. An operation you do not call and a field you do not send cannot affect you.
- New response fields. Parse responses tolerantly — deserialize into a type that ignores unknown fields rather than one that rejects them. This is the single most common way an integration breaks on an otherwise compatible change.
- New values in an enumerated set, when the product gains a state. Handle an unrecognized value as "something new" rather than throwing.
- Corrections to the specification where it disagreed with the service. These change the document, not the behaviour: a field that was always nullable being declared nullable, a response body that was declared but never sent being removed, a media type corrected to what is actually returned. If a generated client breaks on one of these, it was relying on something the API never actually did.
Corrections are the category to watch after a documentation update. They can change
generated client types — for instance, a response field correctly declared nullable
becomes string | null in TypeScript. The wire bytes are unchanged; what changed is
that the document stopped over-promising.
What would require a new version
We would not do any of these to /v1:
- Removing or renaming an operation, a path, or a field
- Changing a field's type, or the spelling of a value it returns
- Making an optional request field required, or narrowing what a field accepts
- Changing the meaning of an existing status code
Work of that kind is tracked separately and would ship as a new version alongside
/v1, not as a change to it.
Staying informed
The changelog records changes to this API. Read it before upgrading a generated client, since that is where corrections are called out.
The machine-readable specification is always current at
https://app.lettrlabs.com/api/openapi/v3.json. It is generated from the running
service rather than hand-maintained, so it reflects what is deployed. If you generate
a client, pin a copy of the specification in your own repository and diff it when you
update — that way a corrected declaration shows up as a reviewable change rather than
as a surprise compile error.
Writing an integration that survives changes
- Ignore unknown response fields.
- Treat an unrecognized enumerated value as unknown, not as an error.
- Send only the fields you mean to set; omit the rest rather than sending
null. Where a field is genuinely optional, its documentation says so and it is absent from the schema'srequiredlist. - Do not depend on field ordering, on
metadatacontaining anything not documented for that operation, or on the absence of fields you do not use.