API conventions
Permissions, pagination, errors and image availability.
Card, copy and species identity
cardId identifies a catalog printing, inventoryItemId a physical copy, slotId a stable storage slot and collectionId a storage collection. Repeated copies keep distinct identities. Existing versioned commands retain their itemId fields for physical copies; do not rewrite queued commands or backups to match Activity's inventoryItemId query filter.
Catalog card, set and series responses declare game: "pokemon". Only Pokémon TCG is supported today, including Trainers and Energy without National Dex links. No game selector is offered. Internal IDs, canonical IDs and reviewed aliases are globally unique opaque application IDs across games and sources. Keep existing IDs unchanged and pass them back exactly; do not parse them or use a bare provider-local product number as cardId.
externalIds contains provider-local evidence keyed by source within the record's game. For example, synthetic tcgplayer:["42"] and cardmarket:["42"] on a game:"pokemon" record are different identifiers. Neither is application ID 42. Future ingestion must allocate collision-free global card/set/series IDs and keep external IDs scoped by game and source before joining or inserting; adding a game field to copies cannot fix a catalog primary-key collision. No other game or provider integration is implied.
{kind:"pokemon",pokemonId} deliberately identifies a species. list_pokemon and get_pokemon remain dedicated species endpoints. get_pokemon_set_slots (GET /pokemon/sets/{id}/slots) returns dex-grouped Pokémon species, not stable storage slots. Use list_cards with a set filter for all set printings, and list_storage_slots for actual stable slots.
The public list_collection, save_collection_item and delete_collection_item species-row operations have been removed without aliases. Use native reads and native commands for copies, slots and wants. Every binder is native, so get_legacy_pokemon_analytics and resolve_import have been removed too.
Pagination
List and search operations use bounded pages with a maximum of 100 records. Follow the returned cursor for the next page. A page is not the entire dataset, and a cursor belongs to the query that created it.
Limits
The initial budget is 60 reads and 20 writes per minute per account, shared across its credentials. Provider refreshes and long-running comparisons have their own stricter limits. A 429 response includes Retry-After.
Errors
| Status | Meaning |
|---|---|
| 401 | Invalid, expired or revoked credential |
| 402 | Premium or lifetime access required |
| 403 | Required permission missing |
| 404 | Record unavailable to this account |
| 409 | Conflict or confirmation required |
| 413 | Request body too large |
| 422 | This operation is unsupported for the requested data |
| 429 | Rate limit reached |
| 503 | A required service is unavailable |
Errors include a stable code, a message and a request ID. Private responses are not cacheable.
Starting a sold-comps comparison job, or refreshing price checks from a source other than eBay, is app-only and returns 403 with code ui_only. Saved comparisons and price checks stay readable through the API.
Images and prices
Image fields refer only to verified R2 objects. Missing images remain missing; the API does not fall back to another image host. Public CDN image links can still be accessed by someone who already has the URL.
Prices include available source, currency, confidence and freshness evidence. Missing amounts and uncertain prices are not invented. Price signals require medium or high confidence.
Tracked background refreshes cover owned physical copies, including Unassigned ones, and explicit wanted cards, including Trainers and Energy. Empty targets are excluded. Repeated copies share a card/language request; a missing language stays unknown and no finish is guessed. An incomplete read stops selection before any provider request. Manual and scheduled refresh rules are unchanged, and the selection adds no REST/MCP permission.
Private uploaded binder artwork lives in a separate private R2 bucket. Upload preparation returns a five-minute signed PUT URL, required headers and an artworkRef for the appearance design. Upload the exact declared bytes, then save the appearance revision. Downloads use five-minute signed GET URLs.
Safe writes
Collection and storage commands must protect against overwriting a newer edit. Duplicate retries of creation, purchase and job operations must not create duplicate effects. See the API reference for each request schema. Binder creation requires an Idempotency-Key, sent as a header or in the body; when both are present they must match. Settings replacement requires a baseFingerprint from the previous read. Native storage commands use revisions and a retry-stable operationId instead (see native storage). Retry keys are retained for 24 hours. Cursors do not freeze the dataset while other clients make changes.
Native storage
Native storage contracts use authenticated execution with exact revision and operation-ID semantics and their own bounds. They do not use the 24-hour Idempotency-Key retention. Native developer reads expose a separate redacted projection. Undo over REST and MCP uses the native storage recovery operations.
Native reads
Native developer reads declare a private redacted copy/storage/slot projection with signed scope/filter/revision-bound cursors. A response page is never a complete planning snapshot or a fresh-read queue acknowledgement.
Copied preset previews provide authenticated discovery and bounded read-only manifests through the same registry/dispatcher. Preset entry IDs are provenance, not slot/collection/operation identities. No private planning state, ownership, autosync or durable set/master-set scope is implied.