API versioning

Every Xident API version is a date, like 2026-08-13. Each of your websites is pinned to one, and the shape of every response and every webhook for that version never changes — not a renamed field, not a removed field, not a changed type.

When we need to make a change that would break an existing integration, we publish a new dated version instead. Your pinned version keeps working exactly as it did, and you move when you choose to.

What counts as a breaking change

This distinction decides whether you need to do anything, so it is worth being precise about.

ChangeNew version?What you must do
A new optional response fieldNoNothing. New fields appear on every version.
A new value in an existing set (a new reason, a new verification_type)NoHandle a default. We document every set as open for exactly this reason.
A new optional request parameterNoNothing.
A field renamed or removedYesNothing until you move versions.
A field's type or meaning changesYesNothing until you move versions.
A request parameter becomes requiredYesNothing until you move versions.

Your side of this: your integration must tolerate fields it does not recognise, and must handle an unrecognised value in any set by falling through to a default. Every official SDK already does both. If you parse our JSON strictly and reject unknown keys, an additive change will break you and a new version will not save you.

How your version is chosen

In order of precedence:

  1. The X-API-Version request header, if you send one.
  2. The version pinned to the website in your dashboard, under Website Settings.

There is no "always use the latest" setting, on purpose. A website that floated onto each new version would suffer precisely the breakage this system exists to prevent.

curl https://api.xident.io/verify/v1/result/xtk_… \
  -H "Authorization: Bearer sk_live_…" \
  -H "X-API-Version: 2026-08-13"

The header is how you trial a new version before committing to it: send it on a few calls, confirm your code handles the new shape, then change the pin. It works in both directions — you can also send an older version than your pin.

latest is deliberately not accepted as a value. An alias that floats would silently change your payloads the day we ship, which is the one thing this whole mechanism is for.

Every response tells you its version

On both success and error, in a header and in the body:

{
  "success": true,
  "data": { "token": "xtk_…", "status": "success", "verified": true },
  "meta": {
    "request_id": "req_…",
    "timestamp": "2026-08-13T10:02:31Z",
    "api_version": "2026-08-13"
  }
}

The same value comes back as an X-API-Version response header. When you are debugging a shape that is not what you expected, this is the first thing to check.

Invalid versions

A version we cannot serve is rejected outright rather than quietly rounded to something near it — because rounding means our next release silently changes your payload.

CodeWhen
INVALID_API_VERSIONNot a YYYY-MM-DD date, or sent more than once
UNKNOWN_API_VERSIONA valid date that is not a released version, or later than the newest
API_VERSION_SUNSETA version whose support has ended
{
  "success": false,
  "error": {
    "code": "UNKNOWN_API_VERSION",
    "message": "X-API-Version 2026-09-01 is not a released API version",
    "details": { "supported": ["2026-08-13"], "latest": "2026-08-13" }
  },
  "meta": { "request_id": "req_…", "timestamp": "2026-08-13T10:02:31Z" }
}

Webhooks

Each webhook payload carries the version that produced it in its api_version field, and its data is byte-identical to what GET /result returns at that version. A webhook endpoint uses its own pinned version if it has one, otherwise the website's — so you can migrate one endpoint and verify it before moving the rest.

A redelivered webhook replays the original bytes, in the version that produced them. Changing your pin does not rewrite history.

Deprecation and support

A version is supported for at least 12 months after we deprecate it, and we do not deprecate a version until a newer one is available to move to.

A deprecated version keeps working and keeps serving its shape. What changes is that it starts telling you so, using the standard IETF headers (RFC 9745 and RFC 8594):

Deprecation: @1799971200
Sunset: Sat, 14 Aug 2027 00:00:00 GMT
Link: <https://docs.xident.io/api-versions#2026-08-13>; rel="deprecation"
Link: <https://docs.xident.io/api-versions>; rel="successor-version"

You will also see a notice in your dashboard. We will not move your pin for you, and we will not cut your integration off on a calendar date without talking to you first.

SDKs

Each official SDK sends the API version it was built against, so its response types always match the payload it receives. That means upgrading an SDK's major version is how you adopt a new API version — and an SDK patch or minor release never changes the shape you get.

Every SDK exposes an override if you want to pin explicitly:

SDKOverride
Goxident.WithAPIVersion("2026-08-13")
Node.jsnew Xident(key, { apiVersion: '2026-08-13' })
PythonXident(api_key=…, api_version="2026-08-13")
PHPnew Config($key, apiVersion: '2026-08-13')

Released versions and what changed in each are listed on the API versions page.