# Get a sealed product

> One sealed product by sku or slug.

- **Endpoint**: `GET /v1/sealed/{id}`
- **Cost**: 1 credit
- **Minimum plan**: free
- **Cache-Control**: `public, max-age=60, s-maxage=300, stale-while-revalidate=600`

Source: https://pokemontcgapi.com/docs/api/sealed/get

`index_eur` is the catalogue price in euros where one is known, and `last_price_at` says when a market price was last observed. The observations themselves — source, variant, currency, date — are on `/v1/sealed/{id}/prices`.

## Path parameters

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `id` **required** | string | — | The `sku` (which is also the `id`) or the `slug`. Both resolve; the sku wins if a slug happens to equal another product’s sku. |

## Query parameters

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `lang` | string | — | Locale for `name`, falling back to English. |

## 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**

```bash
curl -s "https://api.pokemontcgapi.com/v1/sealed/evolving-skies-booster-box" \
  -H "X-Api-Key: $PTCG_API_KEY"
```

**TypeScript**

`request.ts`

```ts
const url = new URL("https://api.pokemontcgapi.com/v1/sealed/evolving-skies-booster-box");

const res = await fetch(url, {
  headers: { "X-Api-Key": process.env.PTCG_API_KEY ?? "" },
});

if (!res.ok) {
  const { error } = await res.json();
  throw new Error(`${error.code}: ${error.message} (${error.request_id})`);
}

const { data, meta } = await res.json();
```

**Python**

`request.py`

```python
import os, httpx

res = httpx.get(
    "https://api.pokemontcgapi.com/v1/sealed/evolving-skies-booster-box",
    headers={"X-Api-Key": os.environ["PTCG_API_KEY"]},
)
res.raise_for_status()
payload = res.json()
```

## Example response

`200 OK` · `Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=600`

`response.json`

```json
{
  "id": "evolving-skies-booster-box",
  "sku": "evolving-skies-booster-box",
  "slug": "evolving-skies-booster-box",
  "name": "Evolving Skies Booster Box",
  "kind": "BOOSTER_BOX",
  "set_code": "evs",
  "set_name": "Evolving Skies",
  "image_url": "https://media.rarebit.app/boxes/evolving-skies-booster-box-normal.webp",
  "release_date": null,
  "pack_count": 36,
  "languages": [],
  "index_eur": 1750,
  "last_price_at": "2026-09-02T00:36:37.317Z",
  "created_at": "2026-05-23T12:43:56.069Z",
  "updated_at": "2026-09-02T15:56:54.473Z"
}
```

## 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. |
| 404 | `SEALED_NOT_FOUND` | No sealed product with that id. |

The full taxonomy, with what to do about each code, is on the [errors](https://pokemontcgapi.com/docs/errors) page.
