# The compatibility contract

# The compatibility contract

Every path under `/v1/` is frozen by a short set of promises. They are
printed in full at the top of the [permits reference](/api), which is
generated from the same file our servers are tested against, so the two
cannot disagree. This page is the short version and the retirement rule.

## In one paragraph

We may add fields, add enum values, add endpoints, return `null` for a
field documented as nullable, and add or remove entries in a list. We will
never remove or rename a field, change a field's type, change what an enum
value means, change or reuse an id, change an endpoint's URL, or remove an
enum value. So: ignore what you do not recognise, treat an unknown enum
value as "unknown" and still render the rest, store ids rather than labels,
and expect an id to disappear from a list when a district retires a status.

## Versions and retirement

A change that would break a promise ships as `/v2/permits/…` beside v1.
Versions are per product. A retired version keeps working for at least 12
months after its successor ships; during that window its responses carry
`Deprecation` and `Sunset` headers and every key holder is emailed. Nothing
is retired today.

## Ids

An id is a UUID that names one thing forever: a district, a status row, a
permit type. Ids authorize nothing. When a district renames a status, the
old row retires and a new one appears with a new id; that is a list entry
leaving and another arriving, which the contract allows.
