**Source:** https://heykiku.com/help/api-versioning

# API versioning policy

## How URL versioning works

All endpoints today live under `/api/*` — this is the permanent v1 surface. v1 is not a "latest" pointer; it's a frozen contract.

When we ship breaking changes, v2 lives at `/api/v2/*`. v1 stays available for at least 12 months from the v2 announcement.

v3 ships at `/api/v3/*` — v1 never auto-upgrades. Pin your clients to the version you tested against.

## What's a backwards-compatible change

Adding any of the following doesn't require a new API version:

- A new endpoint
- New optional fields in existing request schemas
- New fields in response bodies
- New error codes (the set of `code` strings is open-ended; clients should handle unknown codes gracefully)
- New scope values may be added. The semantics of existing scope names are frozen for the life of the API version — a scope's allowed actions never get tighter. Note that effective access also depends on your membership: a scope that passes today may fail later if your workspace role is changed by an admin.

## What's a breaking change

We bump the version when we:

- Remove or rename an existing field
- Change a field's type or semantics
- Tighten validation (a previously-accepted input becomes a 400)
- Remove a scope or change what a scope grants
- Change the meaning of an existing error `code`

## What you can and can't depend on

**Error `code` strings are stable.** If you're switching on a code today, that code keeps the same meaning for the life of the API version.

**Error `message` strings are not stable.** Display the message to humans; don't pattern-match it in code.

**Cursor pagination tokens are opaque.** Treat them as strings; don't parse them. We may change their internal structure at any time.

**HTTP status codes are part of the contract.** A 401 stays a 401 for the same error class.

## Deprecation policy

When we deprecate a scope, key format, or header semantic, we announce it at least 12 months before removal.

During the deprecation window, every response that uses the deprecated artifact includes `Deprecation: <HTTP-date>` (RFC 9745) and `Sunset: <HTTP-date>` (RFC 8594) headers — the deprecation date and the removal date respectively.

## Errors

Our error envelope is `{ error: { code, message, doc_url? } }`. The `code` is a stable identifier; the `message` is human copy. `doc_url`, when present, points back to this page. We'll move per-code documentation into dedicated pages as the platform matures.