Compatibility
Compatibility
What we may change in v1 without warning, and what would require a new major version. Stated as an enumerated list rather than a promise, so an integration can be built defensively against exactly the right set.
Paths, methods, scopes, field names, error codes and validation rule names are published in English, because English is the language of the interface itself — they are what a caller types or matches on. So is every code sample and JSON payload, and the exact sentence an error response carries: /v1 does not read Accept-Language, so translating what the API literally sends would misdescribe it. Everything written about them follows the language of this page.
The current revision is 2026-08-01. The path stays /v1; the revision identifies the document that describes it.
Changes we will not make to v1
These require a new major version. If we ever need one, existing versions keep answering while you migrate.
- Removing an operation.
- Removing or renaming a parameter, or a field in a response.
- Adding a new required parameter.
- Making a previously optional parameter required.
- Changing the type of a parameter or a response field.
- Removing a value from an enum.A client switching on the value has no branch for its absence, so it fails in whichever way its language fails on an unhandled case.
- Adding a new validation rule to an existing parameter.A request that succeeded yesterday would begin to fail, which is a removal of capability wearing the costume of a bug fix.
- Changing authentication or authorization requirements, including the scope an operation demands.
Changes we may make at any time
Your integration must tolerate all of these. They will happen, and they will not be announced.
- Adding a new operation.
- Adding a new optional parameter.
- Adding a new optional request header.
- Adding a new field to a response.Parse responses permissively — a client that rejects unknown fields will break on our first addition.
- Adding a new response header.
- Adding a value to an enum.Handle an unrecognised value as a default case rather than an error. New passport categories and new event types will appear.
- Subdividing an error code into more precise ones — but only where the original could not be resolved by runtime logic such as a retry.Splitting a code a client BRANCHES on is breaking; splitting one it only logs is not. The distinction is whether behaviour depended on it.
What your client must tolerate
Each of these corresponds to a change above that we reserve the right to make. A client that violates one will break on something we consider routine.
- Ignore response fields you do not recognise, rather than rejecting the response.
- Treat an unrecognised enum value as a default case, not an error.
- Treat identifiers as opaque strings; never parse or pattern-match them.
- Do not depend on the ORDER of fields in a JSON object, or on the exact wording of a human-readable error message. Branch on the machine-readable error code instead.
- Retry on 429, and on any other refusal that carries a Retry-After header, waiting for the time it names. It is not only a 429 header: a 409 resource_busy, a 503 storage_unavailable and a 503 entitlement_unavailable carry one too, because retrying is their remedy.
- Retry a 5xx with a NEW Idempotency-Key. A key that recorded a server error replays that error for the retention window — deliberately, because the failure may have been a lost response to a write that SUCCEEDED, and reusing the key is what stops one failed write becoming two.
- Retry a refused conditional write with a NEW Idempotency-Key. A precondition_failed is recorded against the key that received it and replays for the retention window, so re-reading the passport and retrying under the SAME key returns the original refusal — with the version numbers the FIRST attempt saw. The recording is deliberate: it is what makes a retry after a lost response safe. This applies to the 412 only. A 400 for a malformed header is refused before any key is claimed and is never recorded, so correct the header and retry under the SAME key: your original result is still there.
- Watch for the Deprecation and Sunset response headers, and for the Link: rel="successor-version" they carry. That is how the removal of an endpoint is announced, and it arrives long before the endpoint stops answering.
Treat every identifier as an opaque string of at most 255 characters. Do not parse them, do not validate their format, and do not assume they are UUIDs — the format may change without notice.
Deprecation
An endpoint scheduled for removal answers with Deprecation and Sunset headers, and a Link header naming its successor. They arrive long before the endpoint stops answering. Watch for them.