Batch cards
Resolve up to 100 card ids in one request instead of 100 round trips.
/v1/cards/batch1 credit per 25 ids, rounded upfree planCache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=600
For hydrating a known list — a deck list, a collection, a set of ids from your own database. One request, one round trip.
The response is not an error when some ids are missing: requested and found let you diff without comparing arrays. Unknown ids are simply absent from data. In the example below base1-4 resolves to bs-4 and sv3-223 to obf-223, because both were sent as alternate ids — which is also the quickest way to see that resolution happened.
Query parameters
| Name | Type | Default | Description |
|---|---|---|---|
ids required | string | — | Comma-separated ids, at most 100 — a 101st is LIMIT_EXCEEDED. Alternate {set}-{number} ids are accepted alongside ours, and may be mixed freely. |
select | string | — | Comma-separated card fields to return. id is always included. camelCase and snake_case both resolve, so nationalPokedexNumbers works and comes back as national_pokedex_numbers. An unknown name is INVALID_SELECT_FIELD, with the full list in details.valid_fields. |
include | string | — | Comma-separated relations to expand: prices, translations, images, set, artist. Each one is an extra join, so ask only for what you render. include=prices is how you get the per-source price breakdown. legalities is not an accepted value and is rejected with 400 INVALID_INCLUDE. |
lang | string | — | Locale for the card name: en, ja, fr, de, es, it — the six with translation rows in the catalogue. A card with no translation in the requested locale falls back to English rather than to null. |
Headers
| Name | Type | Default | Description |
|---|---|---|---|
X-Api-Key required | string | — | Your API key. Authorization: Bearer <key> is accepted as an alias. |
If-None-Match | string | — | Send back the ETag you stored. The API returns a strong ETag on every catalogue response, and a 304 is a header exchange: no body, no database row read. |
Example request
curl -s -G "https://api.pokemontcgapi.com/v1/cards/batch" \
--data-urlencode "ids=base1-4,sv3-223,zzz-1" \
--data-urlencode "select=id,name,set_code,index_eur" \
-H "X-Api-Key: $PTCG_API_KEY"Example response
200 OK · Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=600
{
"data": [
{ "id": "bs-4", "name": "Charizard", "index_eur": 561.84, "set_code": "bs" },
{ "id": "obf-223", "name": "Charizard ex", "index_eur": 91.32, "set_code": "obf" }
],
"requested": 3,
"found": 2
}Errors
Every error body carries error.code, error.message and error.request_id. Switch on the code, never on the message.
| Status | Code | When |
|---|---|---|
| 401 | MISSING_API_KEY | No X-Api-Key header and no bearer token on a route that requires one. |
| 401 | INVALID_API_KEY | The key does not match any account. |
| 400 | LIMIT_EXCEEDED | limit is above 250, or a batch request carries more than 100 ids. |
| 400 | INVALID_SELECT_FIELD | A name in select is not a card field. |
| 400 | INVALID_INCLUDE | A name in include is not a known relation. |
| 400 | INVALID_PARAMETER | A query parameter has the wrong type or an unsupported value — a non-integer limit, an unknown lang, an unknown region, a sort key that is not sortable. |
The full taxonomy, with what to do about each code, is on the errors page.
There is no envelope and no cursor here: the caller already knows how many ids it sent, so meta.has_more would be a field that is always false.