# Versioning

## What is stable

`/v1` is stable once announced. Within it:

- **Additive changes ship without a bump** — a new field on a response, a new optional request field, a new route, a new error code. They appear in the [changelog](/changelog).
- **New enum values are announced 30 days ahead.** Your client must tolerate an unknown value rather than crashing on it. This is the single most common way an integration breaks on an API that never made a breaking change.
- **Breaking changes go to `/v2`**, and `/v1` keeps serving for at least six months.

## How notice is delivered

Three channels, because each one reaches a different reader:

| channel | reaches |
|---|---|
| `Deprecation` and `Sunset` response headers, plus `Link: rel="deprecation"` | code that logs them |
| the [Atom feed](/changelog.xml) | the person who has to act |
| email to a registered client's `contacts` | best-effort, if you gave one |

// Subscribe to the feed. The headers reach your logs; the feed reaches you.

[RFC 9745](https://www.rfc-editor.org/rfc/rfc9745) for `Deprecation`, [RFC 8594](https://www.rfc-editor.org/rfc/rfc8594) for `Sunset`.

## The machine contract

```bash
curl -s https://api.inittasks.com/openapi.json
```

OpenAPI 3.1, generated from the same schemas that validate the requests — not a hand-maintained document beside them. Every response carries `Link: <…/openapi.json>; rel="service-desc"`.

If the reference pages here and the document disagree, **the document wins**: these pages are a build artefact, and a deploy can be newer than the docs you are reading.

## Writing a client that survives

- [✓] Ignore unknown response fields; never validate a response with a closed schema.
- [✓] Treat an unknown enum value as "something new", not as an error.
- [✓] Branch on the problem `type` URI, never on `detail` or on the status alone — several codes share a status.
- [✓] Follow `next_cursor`; never construct or parse a cursor.
- [✓] Send `Idempotency-Key` on every write, so a retry after a timeout is safe.
