> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dev.gojinko.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Versioning & deprecation

> How the public contract changes, what counts as breaking, and how much warning you get.

The Jinko public API is versioned with **semver on the published contract**. The number lives in `info.version` of the [OpenAPI document](/api-reference/introduction), and it is the one signal that the contract moved.

```bash theme={null}
curl -s https://docs.gojinko.com/api-reference/public-api.yaml | grep -m1 '^  version:'
#   version: 0.5.0
```

Read it from the environment you are actually calling. A sandbox and production can be serving different contract versions during a rollout, and the served document is the truth about which.

## The three rules

<Steps>
  <Step title="Additive changes bump the minor version, with no notice">
    A new optional field, a new endpoint, a new event type, a new error code, a new enum value on a field you send us: all of these ship in a minor bump with no advance notice. Your integration keeps working through them, which is why they need none.
  </Step>

  <Step title="Breaking changes ship on a new path, never in place">
    We do not repurpose a field, tighten a type, or remove a route from `/v1`. A change that cannot be made additively goes to `/v2`, and the two run side by side for **at least 90 days** so you can move at your own pace.
  </Step>

  <Step title="Deprecations are announced on the wire, where you cannot miss them">
    A route on its way out keeps answering, and every one of its responses carries headers that name its replacement and its removal date. You do not have to be reading announcements to find out: your own logs tell you, well before anything stops working.
  </Step>
</Steps>

## What counts as breaking

| Change                                    | Breaking? | How it ships                                                               |
| ----------------------------------------- | --------- | -------------------------------------------------------------------------- |
| New optional response field               | no        | Minor bump. Ignore fields you do not know.                                 |
| New optional request field                | no        | Minor bump. It defaults to today's behaviour.                              |
| New endpoint                              | no        | Minor bump.                                                                |
| New value in a response enum              | no        | Minor bump. Treat response enums as open and handle the unknown case.      |
| New `error.code`                          | no        | Minor bump. Have a default branch, see [Errors](/concepts/errors).         |
| New webhook event type                    | no        | Minor bump. Ignore events you do not handle.                               |
| Removing or renaming a response field     | **yes**   | New path, with overlap.                                                    |
| Making an optional request field required | **yes**   | New path, with overlap.                                                    |
| Narrowing a type, or a field's meaning    | **yes**   | New path, with overlap.                                                    |
| Removing an endpoint                      | **yes**   | Deprecation headers first, then removal after the announced sunset.        |
| Removing an `error.code`                  | **yes**   | New path. The enum is closed, so a code disappearing is a contract change. |

<Warning>
  **"Ignore what you do not recognise" is load-bearing.** A client that rejects an unknown response field, an unknown enum value, an unknown error code, or an unknown webhook event turns every additive release into an outage for itself. Nothing in the additive column above is announced ahead of time, because a correct client does not need the warning.
</Warning>

## Deprecation headers

While a route is deprecated but still answering, every response it sends carries three headers:

| Header        | Value                                              | What it tells you                           |
| ------------- | -------------------------------------------------- | ------------------------------------------- |
| `Deprecation` | `true`                                             | This route is on its way out.               |
| `Sunset`      | An HTTP-date, e.g. `Thu, 31 Dec 2026 23:59:59 GMT` | The instant after which it stops answering. |
| `Link`        | `</v1/checkout>; rel="successor-version"`          | The route that replaces it.                 |

They are set before anything else runs, so a 401 carries them just as a 200 does. That is deliberate: a caller whose credentials are stale is exactly the caller most likely to be running old code.

The first route to carry them is **`POST /v1/book`**, superseded by [`POST /v1/checkout`](/api/checkout):

```bash theme={null}
curl -is -X POST https://api.gojinko.com/v1/book \
  -H "X-API-Key: $JINKO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "trip_id": "402" }' | grep -iE '^(deprecation|sunset|link):'
# deprecation: true
# sunset: Thu, 31 Dec 2026 23:59:59 GMT
# link: </v1/checkout>; rel="successor-version"
```

If you are calling `/v1/book`, switch to `/v1/checkout`. It is the same operation under the name the rest of the platform uses, and it is where new behaviour lands.

<Tip>
  **Log the `Deprecation` header, do not just read it.** One line in your client that warns when a response carries `Deprecation: true` costs nothing and turns every future sunset into something you find out about on the day it is announced rather than the day it takes effect.
</Tip>

## The error-code enum is closed

`error.code` is a fixed set, published as an enum in the spec. The platform sends no code outside it, and every code in it has a producer. The spec and the [errors page](/concepts/errors) are kept in step with the platform's own table, so the list you read is the list you can receive.

Adding a code is additive and lands in a minor bump, so keep a default branch for a code you do not recognise. Removing one is breaking.

## What we deliberately do not do

* **No dated versions in a request header.** There is no `Jinko-Version` header to pin. The contract version is a property of the document you read, not of the call you make.
* **No silent behaviour changes inside a version.** If the answer to the same request changes in a way you can observe, the minor version moves, so `info.version` is enough to tell you something did.
* **No removals without the sunset window.** A route that carries no `Sunset` header is not going anywhere.

## Where to look

* **The served contract**: `info.version` in the [OpenAPI document](/api-reference/introduction). It is the version of the environment you fetched it from.
* **What changed**: the contract version itself is the signal. Compare `info.version` against the one you last integrated against, and read a deprecated route's `Deprecation` and `Sunset` headers straight off your own responses. A public changelog is not published yet.
* **What a code means**: [Errors & troubleshooting](/concepts/errors) carries the full enum with a remedy for each entry.
