List sets
All 615 sets with release date, totals, print region and series, newest first.
/v1/sets1 creditfree planCache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=600
A few hundred rows, so this response carries meta.total_count — the card endpoints do not, because counting a filtered card query exactly would cost more than the query itself.
The catalogue runs from Expansion Pack, 1996-10-20, to 30th Celebration, 2026-09-16, across three print regions. Asian print lines are separate sets with their own codes and numbering, not translations of Western ones, which is what region is for.
Query parameters
| Name | Type | Default | Description |
|---|---|---|---|
q | string | — | Accent-insensitive substring match on the set name, or an exact code or slug. |
series | string | — | Series slug, e.g. base. Sets whose series is unmapped match no value. |
region | string | — | Print region: WEST (176 sets), JP (379) or CN (60), counted 2026-08-27. KR is accepted and matches 0 rows. Anything else is INVALID_PARAMETER with the accepted values in details.supported. |
orderBy | string | -release_date | One or more of code, name, release_date, total, updated_at. Tiebreaker is code. |
limit | integer | 50 | Rows per page, 1 to 250. Above 250 you get LIMIT_EXCEEDED — follow links.next instead of raising it. |
cursor | string | — | Opaque keyset cursor from links.next. Never construct one; it carries the sort order it was issued for and is rejected if orderBy changes mid-run. |
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/sets" \
--data-urlencode "region=JP" \
--data-urlencode "limit=2" \
-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": "m6",
"code": "m6",
"slug": "storm-emeralda",
"legacy_id": null,
"name": "Storm Emeralda",
"series": null,
"region": "JP",
"release_date": "2026-07-31",
"total": 116,
"printed_total": null,
"ptcgo_code": null,
"symbol_url": null,
"logo_url": "https://media.rarebit.app/sets/m6/logo-normal.webp",
"updated_at": "2026-08-26T17:47:39.900Z"
},
{
"id": "m5",
"code": "m5",
"slug": "abyss-eye",
"legacy_id": null,
"name": "Abyss Eye",
"series": null,
"region": "JP",
"release_date": "2026-05-22",
"total": 118,
"printed_total": null,
"ptcgo_code": null,
"symbol_url": null,
"logo_url": "https://media.rarebit.app/sets/M5/logo-normal.webp",
"updated_at": "2026-08-26T17:47:39.900Z"
}
],
"meta": { "limit": 2, "count": 2, "total_count": 379, "has_more": true },
"links": { "next": "https://api.pokemontcgapi.com/v1/sets?limit=2®ion=JP&cursor=eyJrIjpbIjIwMjYtMDUtMjJUMDA6MDA6MDAuMDAwWiJdLCJ..." }
}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 | INVALID_CURSOR | The cursor is malformed, or was issued for a different orderBy than the one on this request. |
| 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. |
| 400 | LIMIT_EXCEEDED | limit is above 250, or a batch request carries more than 100 ids. |
The full taxonomy, with what to do about each code, is on the errors page.
Unknown parameters are ignored
A query parameter this endpoint does not know is dropped silently — it is not an error and it does not change the result. A typo in a filter name therefore returns a full, unfiltered page rather than a 400, so check the parameter names in the table above before concluding that a filter does nothing.
Regions, counted
region= | Sets | What it covers |
|---|---|---|
WEST | 176 | The English-language print line and its European siblings |
JP | 379 | Japanese sets, with their own codes and numbering |
CN | 60 | Simplified Chinese print line |
KR | 0 | Valid in the schema, no rows in the catalogue |
Those four numbers come from meta.total_count on GET /v1/sets?region=…&limit=1, which is the cheapest way to re-check them yourself.