# Versioning and Lifecycle

<Lead>

`/v4` is the version of **all of Zuplo's API**, not of one subsystem. Stable v4
surfaces only change additively: anything that would break a client is added next
to the old surface instead.

</Lead>

## <N n="1" />One version for the whole API

The shared rule VER-1 versions per subsystem. That is exactly how customers ended
up with monetization v1, v2 and v3 next to API keys v1. v4 deliberately departs
from it: one prefix, one set of conventions, one OpenAPI document. New
capabilities are **added to v4**.

<DoDont>
<Do title="One prefix for every product">

```text
/v4/buckets/{bucketId}/ai/pools
/v4/buckets/{bucketId}/consumers
/v4/accounts/{accountId}/buckets
```

</Do>
<Dont title="A version per subsystem">

```text
/v3/metering
/v2/key-auth
/v1/api-keys
```

</Dont>
</DoDont>

## <N n="2" />Changing v4 without breaking it

<Rule id="VER-3" review>

Within v4, only additive changes are allowed. A breaking change to a stable v4
surface is not made: a replacement is added next to it, and the old one goes
through deprecation.

</Rule>

<DoDont>
<Do label="Allowed" title="Non-breaking">

- new operations and collections
- new optional request fields and parameters
- new response fields
- new enum values (enums are extensible)
- `null` where there was none

</Do>
<Dont label="Not allowed" title="Breaking">

- removing or renaming a path, field or parameter
- new required request fields, or making an optional field required
- changing a field's type or format
- removing an enum value, or accepting fewer request values
- changing a status code or error `type`

</Dont>
</DoDont>

## <N n="3" />Maturity labels

<Rule id="VER-4" lint="v4-document">

`x-stability: preview` or `x-stability: beta` marks surface that may still change
without a deprecation period. No label means stable.

</Rule>

<Flow>
<FlowStep label="Today" code="x-stability: preview">

The whole v4 document. It may still change without a deprecation period.

</FlowStep>
<FlowStep label="Graduation" title="Remove the label">

Operations graduate individually.

</FlowStep>
<FlowStep label="Stable" title="No label">

Bound by the table above from then on.

</FlowStep>
</Flow>

<DoDont>
<Do title="Stability in the spec">

```yaml
x-stability: preview
```

</Do>
<Dont title="Stability in the URL">

```text
/v4beta/buckets/{bucketId}/ai/apps
/v4/buckets/{bucketId}/ai/apps-preview
```

</Dont>
</DoDont>

## <N n="4" />Deprecation

<Rule id="VER-2" review>

A deprecated operation is marked and announced, gets at least 90 days of notice
when it is stable, and is removed only after its sunset date. Unchanged from the
shared rule.

</Rule>

<Flow>
<FlowStep label="1. Mark it" code="deprecated: true">

Plus a successor in the description.

</FlowStep>
<FlowStep label="2. Announce it" title="Deprecation and Sunset headers">

At runtime, from the `http-deprecation-outbound` policy.

</FlowStep>
<FlowStep label="3. Wait" title="At least 90 days">

Of notice, for stable operations.

</FlowStep>
<FlowStep label="4. Remove it" status="410">

`410 Gone` after the sunset date.

</FlowStep>
</Flow>

## <N n="5" />v1 to v3 and api.zuplo.com

<Tiles cols={3}>
<Tile title="Frozen">

Existing `dev.zuplo.com` versions are frozen and keep working.

</Tile>
<Tile title="Moved resource by resource">

The portal moves to v4 resource by resource. A portal feature built on v4 no
longer needs its `api.zuplo.com` counterpart.

</Tile>
<Tile title="Removed when unused">

When nothing calls an `api.zuplo.com` route anymore, it is removed.

</Tile>
</Tiles>

<EnforcedBy
  lint="v4-path-shape v4-document"
  checks="One /v4 prefix on every path (VER-1), and x-stability on the document (VER-4)."
>

Breaking changes (VER-3) and deprecations (VER-2).

</EnforcedBy>
