Skip to main content

Best practices

Money and dates​

  • Money is integer USD cents. price_cents: 1850 means $18.50. The currency field is always "USD" in v1 (present so a future version can vary it). Divide by 100 for display; never assume a currency symbol beyond USD.
  • Dates are ISO 8601, UTC. Plain dates are YYYY-MM-DD (e.g. release dates); timestamps are YYYY-MM-DDTHH:MM:SSZ.

Images​

Card and set image URLs (image_url, pack_image_url) point at our public CDN (images.pikaqian.com) and are returned to every tier. Fetch the bytes directly from the CDN — don't route image traffic through the API, and don't send your API key to the CDN. This keeps image loads off your quota and on the edge.

  • image_url / pack_image_url are null when no servable image exists for that card/set — handle the null with a placeholder.
  • Pokémon objects carry no image.

Caching​

Card metadata changes rarely; prices update on a cadence (see updated_at on a PriceSummary). Cache aggressively:

  • Cache set/card/Pokémon metadata for hours — it's effectively static.
  • Cache prices for minutes, and lean on updated_at rather than re-polling in a tight loop.
  • Cache images for a long time — a card's image URL is stable and the underlying scan essentially never changes.

Caching is also the simplest way to stay well under your rate limits.

Use the right endpoint​

  • For grids/lists, the list endpoints return a lightweight CardBrief (no pricing, no card text). Fetch full detail or /cards/{id}/prices only for the cards a user actually drills into.
  • For type-ahead / global search, use /v1/search — it returns up to 10 cards, sets, and Pokémon in one call, and it's the only endpoint that matches Chinese names (and pinyin, and exact collector numbers). For deeper or filtered results, switch to the typed list endpoints.
  • Request the largest sensible page_size (up to 100) to minimise round-trips, and page with cursors (see Pagination).

Chinese card text​

Card detail carries the printed card text (hp, local_element, local_subtypes, weaknesses, resistances, retreat_cost, attacks, abilities, local_rules, local_flavor_text, regulation_mark, illustrators) on every tier:

  • It is Chinese, verbatim — there is no English translation yet. As with local_name, every key holding Chinese text is local_-prefixed.
  • [] means "none on the card"; null means "not applicable" or not available for that print. A Dragon-type Pokémon has weaknesses: []; a trainer has hp: null.
  • Effect text keeps the inline tokens printed on the card so you can render icons: 【草】【火】【水】【雷】【超】【斗】【恶】【钢】【妖】【无】 for energy types, 【麻痹】【混乱】【中毒】【睡眠】【灼伤】 for special conditions, 【昏厥】【基础】【撤退】【ex】【V】【GX】【VMAX】, 「…」 around card names, and […] around once-per-game reminders.
  • In attacks[].local_cost, + is the TAG TEAM GX extra-energy marker, not an energy; [] is a free attack. damage ("30+", "20×") and weaknesses[].value ("×2") are the printed strings — the × is U+00D7, not the letter x.
  • local_subtypes is the card's printed classification (宝可梦V, 宝可梦ex, TAG TEAM, 太晶, …, then a trainer's or energy's subtype) and wins over the legacy card_type where the two disagree.
  • Attacks and abilities are in printed order; a VSTAR Power (kind: "vstar_power") always comes last.

Sales window​

/v1/cards/{id}/sales (pro and above) returns only the last 90 days of listings. The from/to params can narrow that window but can't reach behind it — there's no full historical price record in v1.

Reliability​

  • Branch on the error code, not HTTP status or message.
  • Keep the request_id from failed responses for support.
  • Respect Retry-After on 429 and back off with jitter.