# Versioning and change policy (/versioning) Every path is prefixed `/v1`. There is one live version, and there is no `/v2`. ## What we change in place [#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 [#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 [#staying-informed] The [changelog](/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 [#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's `required` list. * Do not depend on field ordering, on `metadata` containing anything not documented for that operation, or on the absence of fields you do not use.