Versions
How Capa dates the API, how to pin a version, and how to hear about the next one.
The /api/ surface has no version in its path. It has a date in a header.
Capa-Version: 2026-10-01A version is a dated snapshot of how the API behaves. Once a date is published, it never changes shape. New behaviour arrives as a new date, and your integration keeps the old one until you change the header or the key's pin.
Today there is one version, 2026-10-01.
Two dials
Capa separates the API's shape from your content's shape.
| Dial | Header | Who moves it | Today |
|---|---|---|---|
| Platform version | Capa-Version | Capa, when we change the API | 2026-10-01 |
| Data contract | Capa-Contract | You, when you change your models | 1 |
Neither forces the other. Our envelope moving is our business. Your fields moving is yours.
Which version a request gets
Capa picks the first of these that applies:
- The
Capa-Versionheader on the request, when it names a supported date. - The version your key is pinned to.
2026-10-01, the first version.
Nothing floats. A key never starts receiving a newer shape on the day we publish one.
A Capa-Version that is not a supported date is refused, never rounded:
{ "error": { "type": "invalid_request", "code": "invalid_version",
"message": "Capa-Version 2026-13-99 is not a supported version.",
"param": "Capa-Version",
"hint": "Supported versions: 2026-10-01.",
"docs": "https://docs.capacms.com/errors/invalid_version" },
"meta": { "version": "2026-10-01", "contract": 1, "requestId": "req_0f3c…" } }Every response says which version served it, in the Capa-Version response header and in meta.version. See invalid_version.
Pin the key, not every call
A cap_ key is pinned to the newest version at the moment you create it. That pin never moves on its own.
So the day a second date exists, the keys you already hold keep the date they were made under. Only a key made after that day gets the new one.
A legacy pk_ or sk_ key carries no pin. It resolves to 2026-10-01.
To move a key to another date, change its pin. This is a session call, so it goes to api.capacms.com with your login token:
curl -X PATCH https://api.capacms.com/v2/tenants/api-keys/<keyId> \
-H 'Authorization: Bearer <your session token>' \
-H 'content-type: application/json' \
-d '{ "apiVersion": "2026-10-01" }'A date that does not exist is refused, so a key can never be pinned to a version that is not there.
The SDK sends the header for you. Pin it in code where you create the client:
import { createClient } from "@capacms/sdk/next";
const capa = createClient({
baseUrl: "https://cdn.capacms.com",
apiKey: process.env.CAPA_KEY!,
version: "2026-10-01",
});List the versions
GET /api/versions needs no key. It is the one route a build script can call without a credential.
curl https://cdn.capacms.com/api/versions{ "data": { "current": "2026-10-01",
"versions": [ { "date": "2026-10-01", "status": "current",
"changes": [ { "id": "2026-10-01.initial",
"kind": "behaviour",
"surfaces": ["rest"],
"summary": "First dated version of /api/." } ] } ] },
"meta": { "version": "2026-10-01", "requestId": "req_0f3c…" } }status | Meaning |
|---|---|
current | The newest version. |
supported | Older, fully supported, no end date. |
deprecated | A successor exists and has been announced. It still serves every byte it served. |
sunset | Its end date has passed. |
Hear about the next version
Ask for every version newer than yours:
curl 'https://cdn.capacms.com/api/versions?from=2026-10-01'Today the list is empty. Put this call in a weekly job and your own tooling tells you when a new date ships.
Each change in the list has a stable id (<date>.<slug>), a kind (response, request or behaviour), the surfaces it touches (rest, graphql) and a one-sentence summary.
Sunset
Capa does not retire a version on its own schedule while you are still calling it.
A version is deprecated only when its successor exists and has been announced. It gets a sunset date only after its traffic has been zero for thirty days.
No version is deprecated today. No response carries a Deprecation or Sunset header yet, and no version answers 410.
Contracts
Capa-Contract names your data-model version. There is exactly one today, 1, and it is the default, so you can leave the header off.
Any other value is refused with 404 contract_not_found. Multiple contracts arrive later, with screens to start, compare, publish and retire them.
Related
- API overview for the request and response shape.
- API versions reference and the API changelog.
- Keys for what else a key carries.