GET, and one endpoint takes a photo of a card and
tells you which card it is.
Base URL
/v1 needs a key. See Authentication.
Responses
Every read of the catalog — series, expansions, cards, products and their prices — answers with the same two keys, and so does every failure. Exactly one of them is ever non-null, so checking either one tells you about the other. A detail endpoint puts the object indata:
data as well. next_cursor sits inside the
envelope rather than beside it, so data and error are the only two keys any response has:
next_cursor is null on the last page.
Errors
Every failure has the same shape, and thecode is the part to branch on:
message is always present and never empty — it is for a human reading a log, and its wording
is not part of the contract. Branch on code.
POST /v1/scan adds codes of its own; they are listed on Scan a card.
Paging
List endpoints page by cursor, not by offset — rows do not shift under you between pages.
A
limit above the maximum is clamped, not refused, and a value that is not a number falls
back to the default.
Walking a whole expansion means calling until next_cursor comes back null — here, three
cards at a time:
q changes what a page contains, not how you walk it: the rows come back
best-match first, each carrying a score, and the same cursor keeps working.
Searching
There is no search endpoint. Every list takesq and searches its own resource:
cards by name or collector number, series,
expansions and products by name. q composes with that
list’s own filters, so ?q=charizard&expansion_id=base1 searches inside one expansion.
What comes back is a ranked set of candidates rather than one resolved id. See
List cards for how the ranking and its ties behave, and Scan a card to
identify a card from a photo instead of a name.
Attaching related data
Some endpoints takeinclude with a comma-separated list. Today only prices is understood,
on List cards. Without it the prices key is absent, not
null and not [], so a response stays byte-identical to what it was before the field
existed.
Caching
/v1/* responses carry an ETag. Send it back as If-None-Match and an unchanged resource
answers 304 Not Modified with no body — cheaper to receive and cheaper to parse. It is not
cheaper against your rate limit: the limiter counts the request before the
304 is produced, so a conditional request that comes back unchanged costs exactly as much of
your budget as a full 200 would.
Versioning
The version is in the path./v1 is current, and a breaking change would arrive as /v2
rather than by altering /v1 under you. Adding a field to a response is not breaking, so
parse defensively: ignore keys you do not recognise.
Service health
GET /health is unauthenticated and reports whether the data being served is current:
status is ok or degraded. Degraded means a background task has not succeeded inside its
window, so some corner of the catalog is staler than it should be — the API keeps answering.