API versioning
The public API uses dated versions, the same scheme as Shopify, so a version you build against won't shift under you. Dated versions are the coarse boundary for breaking changes; within a version the schema still evolves additively.
Version names
A version is named YYYY-MM, where the month is a quarter start: 2026-01, 2026-04, 2026-07, 2026-10. A new dated version is cut only when there is a breaking change — quarters with no breaking change are skipped, so versions are relatively rare.
There is also an unstable version that tracks the leading edge, for previewing changes ahead of a stable release. Don't build production integrations against it.
Selecting a version
Two ways, in order of precedence:
- URL path (recommended): put the version in the endpoint —
…/backend/<subdomain>/api/2026-07/graphql. It's explicit, cache-friendly, and copy-pasteable. - Request header: send
X-Api-Version: 2026-07against the bare…/backend/<subdomain>/graphqlendpoint.
If you omit the version — or name one that is unknown or past its sunset — the request is served by the oldest still-supported version, never the newest. You are never silently upgraded onto a breaking change. Pin a version explicitly for any integration you intend to keep.
Every response echoes the version that served it in an X-Api-Version header, so you can always tell which contract answered — and detect drift if you relied on the fallback.
Support window
Each stable version is supported for at least 12 months, with at least 9 months of overlap with the next one. In practice two to three versions are live at any time, which is a comfortable window to migrate in. A version's sunset date is published the day it ships.
What counts as a breaking change
Within a single version we may make additive changes, and your client must tolerate them:
- adding a new type, query, or mutation;
- adding an optional argument to an existing field;
- adding a field to an object type;
- adding a value to an enum (so never assume an enum is closed).
A new dated version is reserved for genuinely breaking changes: removing or renaming a field or type, tightening nullability, or changing the meaning of an argument or a default. Those never happen inside an existing version — the version you pinned keeps its behavior until its sunset date.
Deprecations
Deprecations are signalled two ways, so you learn about them before anything breaks:
- In the schema. A field being retired is marked
@deprecatedwith a reason that names its replacement. Introspection and the GraphQL Playground surface this to every client automatically. - In the response. When a request actually resolves a deprecated field, the response carries an
X-Api-Deprecated-Reasonheader (and a matchingextensions.deprecationsentry) naming the specific deprecations it touched — so a deprecation shows up in your logs the moment you hit one, without your having to go looking for it.
A deprecated field is kept for a published minimum period before it is removed in a later dated version.