# Versioning

How the API names its versions, what can change without one, and how much notice you get before anything you rely on stops working.

## The Layout-Version header

Versions are dates. The current version is `2026-10-01`, and it is the only one. Send `Layout-Version` on a request to pin the version you code against. Leave it out and you get the current version. Every answer from an endpoint, errors included, says which version answered in its own `Layout-Version` header.

```bash
curl https://api.layout.link/v1/whoami \
  -H "Authorization: Bearer $LAYOUT_SECRET_KEY" \
  -H "Layout-Version: 2026-10-01"
```

A version this API does not answer is `400 unsupported_version`, and the message lists the versions it does. Nothing runs.

Pin a version in production. Then a new version changes nothing for you until you change the header yourself, after reading what it changes.

## Changes without a new version

Additive changes ship into the current version, so write code that tolerates them:

- A new endpoint, or a new optional request field or query parameter.
- A new field in a response or a webhook payload. Ignore fields you do not know.
- A new error `code`. Handle one you do not know by its HTTP status.
- A new event type. You receive it only once a subscription lists it.
- A new `Limit` name, or a raised limit.
- Message text. `message` is for a person; switch on `code`.

## How a breaking change ships

A breaking change is anything that can stop working code from working: removing or renaming an endpoint, a field or an error code, changing a field's type or meaning, making an optional field required, or changing what a status code means.

That is the policy going forward. `2026-10-01` is the only version, and no route answers differently by version yet. Breaking changes announced in the [changelog](https://docs.layout.link/changelog) since 2026-10-01 shipped into it, so pinning it does not hold them back. Read the changelog entry for each one.

1. **It ships as a new dated version.** The version you pinned keeps answering exactly as it did.
2. **It is announced in the [changelog](https://docs.layout.link/changelog)** on the day it ships, marked breaking, naming the new version, what changed and what to do about it.
3. **The old version keeps working for at least 180 days** from that announcement. A version is never removed without a changelog entry that gives the date it stops answering.
4. **After that date** a request that pins it is `400 unsupported_version`. A request without the header gets the current version.

## Deprecation

A deprecated field stays in every version Layout answers today, marked deprecated in the [OpenAPI specification](https://docs.layout.link/openapi.json), and its answers carry a `Deprecation` header and a `Link` header with `rel="deprecation"` pointing at the changelog entry. It is removed only in a new dated version, with at least 180 days' notice.

Today `User.handoffUrl`, in the `POST /v1/users` answer, is deprecated. That answer carries `Deprecation: @1792540800` and a link to [the changelog entry](https://docs.layout.link/changelog/verifying-makes-the-account), including when an `Idempotency-Key` replays it. The `refunded` order state is deprecated too and is never sent; read `refunded_minor` instead.

## What is not versioned

- **The MCP server.** `Layout-Version` applies to the REST API. MCP tools are described to the model on every connection, and a change to one is in the changelog.
- **Limits.** A change to a limit is in the changelog.
- **The console.** It is a product, not an interface your code calls.
