Skip to content
pokemontcgapi.com
Documentation

Versioning

One path prefix, what it guarantees, what may change without notice, and how a deprecation would be announced.

There is one prefix, /v1, and it is in the path and nowhere else. No version header, no Accept negotiation, no default that shifts under you, and no second shape to choose between.

https://api.pokemontcgapi.com/v1/...   { data, meta, links } — cursors, snake_case keys

A request without the prefix is not routed to a default. /cards returns 404 ROUTE_NOT_FOUND, which is louder than quietly serving whatever the newest shape happens to be.

What the prefix guarantees

Within /v1, none of the following will change:

  • A field that exists will not be removed, renamed, or change type.
  • A field that is non-null today will not start returning null.
  • An error.code will not change meaning, and a condition that returns one code today will not start returning a different one.
  • An HTTP status for a given failure will not change.
  • The order of paginated results for a given orderBy will stay deterministic.
  • Default values — limit=50, orderBy=id — will not change.

What may change at any time

  • New fields may appear in any object. Parse permissively — a strict decoder that rejects unknown keys will break on a Tuesday.
  • New optional parameters may be added. Existing behaviour without them is unchanged.
  • New `error.code` values may appear as failure modes become distinguishable. Handle the codes you care about and fall back on the status class.
  • `error.message` wording may change. Never parse it.
  • Catalogue data changes constantly. That is the product.
  • Cursor contents may change shape. They are opaque; nothing may depend on their encoding.

Additive is not breaking

This is the contract that lets us ship without a version bump. If your client tolerates unknown fields and unknown error codes, no ordinary release can break it.

If a breaking change is ever needed

It goes in a new path prefix, served alongside /v1 rather than replacing it. We would rather carry two prefixes than rewrite your parser for you. Concretely:

StageWhat happens
AnnouncementOn the changelog, and by email to every account that used the affected route in the previous 30 days.
DeprecationResponses gain Deprecation and Sunset headers (RFC 8594) carrying the removal date. Nothing stops working.
Minimum noticeSix months between the sunset header appearing and the route being removed. We would rather promise a window we can hold to than a longer one we cannot.
RemovalThe route returns 404 ROUTE_NOT_FOUND. A prefix is never repurposed for a different shape.
deprecation-headers.txt
Deprecation: Sun, 01 Mar 2026 00:00:00 GMT
Sunset: Tue, 01 Sep 2026 00:00:00 GMT
Link: </changelog>; rel="deprecation"

Knowing what changed

SourceUse
ChangelogHuman-readable, dated, one entry per release.
Deprecation / Sunset headersMachine-readable. Log them and the alarm arrives months early.
GET https://api.pokemontcgapi.com/v1/statusPer-source data freshness and catalogue counts. Answers "is the catalogue stale" without emailing anyone.

Writing a client that survives

permissive.ts
// Permissive: extra keys are carried through instead of rejected.
interface Card {
  id: string;
  name: string;
  set_code: string;
  [key: string]: unknown;
}

function isCard(value: unknown): value is Card {
  if (typeof value !== "object" || value === null) return false;
  const row = value as Record<string, unknown>;
  // Only the fields you actually use. Validating fields you ignore turns
  // an additive release into an outage.
  return typeof row.id === "string" && typeof row.name === "string";
}

Do not pin to a date

There is no ?version=2026-08-17 parameter and there will not be one. Date-pinned APIs accumulate a version per customer and eventually cannot be changed at all. A path prefix with a stated sunset is slower to move and far easier to reason about.

view this page as markdown