Laboratory › Developers › Versioning
Versioning
Five different things here have versions and they are not interchangeable. Conflating them is the most common way an API client ends up citing the wrong thing.
| Version of what | Looks like | Means | Changes when | Found in |
|---|---|---|---|---|
| API contract version | 2026-09-10 | The shape of requests and responses on this surface. | An endpoint, field or status code changes meaning. | contract_version in /api/index.json |
| Scientific object version | v2 | One immutable state of one claim identity. | The laboratory publishes a new version. The old one is never edited. | identity.version |
| Schema version | 1.0.0 | The version of a published JSON Schema. | A response envelope's structure changes. | x-schema-version in each schema |
| Ontology version | 1.0.0 | The version of the status vocabulary. | A term's definition changes. Definitions are never silently edited. | /api/ontology.json |
| Artifact version | sha256:3ebd952f… | Content-addressed identity of raw bytes. | The bytes change, which makes it a different artifact. | artifact digests in records and manifests |
Compatibility rules
- Additive changes — a new endpoint, a new optional field — do not change the contract version.
- A removed or retyped field, a changed status code, or a changed meaning is breaking and requires a new contract version.
- A superseded or withdrawn claim is not an API-breaking change. The endpoint behaves identically; the record's lifecycle field differs. A client that treats a lifecycle change as a contract break has misread the contract.
- Version URLs are permanent and their content never changes. This is the strongest compatibility guarantee here and it will not be relaxed.
- A deprecated endpoint is announced in the API changelog, keeps working for at least one contract version, and states its replacement before it is removed.
The permanence guarantee
Supersession is not a breaking change
When demo-0001 went from v2 to v3 and the claim was withdrawn, no endpoint
changed shape, no field changed type, and no status code changed. v2 still returns exactly what it
returned before. A client that treated the lifecycle change as a contract break had misread the contract.
This is why scientific state changes live in the changes feed and API contract changes live in the changelog. Mixing them would train clients to ignore both.