Docs
Concepts

Versions

How Capa dates the API, how to pin a version, and how to hear about the next one.

View as Markdown

The /api/ surface has no version in its path. It has a date in a header.

Capa-Version: 2026-10-01

A 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.

DialHeaderWho moves itToday
Platform versionCapa-VersionCapa, when we change the API2026-10-01
Data contractCapa-ContractYou, when you change your models1

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:

  1. The Capa-Version header on the request, when it names a supported date.
  2. The version your key is pinned to.
  3. 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…" } }
statusMeaning
currentThe newest version.
supportedOlder, fully supported, no end date.
deprecatedA successor exists and has been announced. It still serves every byte it served.
sunsetIts 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.