# Price sources

> The redistribution policy in the open: every source that can appear in a price row, with its label and minimum delay.

- **Endpoint**: `GET /v1/prices/sources`
- **Cost**: free, no key needed
- **Minimum plan**: free
- **Cache-Control**: `public, max-age=86400`

Source: https://pokemontcgapi.com/docs/api/prices/sources

No key yet? One call gets you one: `POST /v1/accounts/free` with an `Idempotency-Key` header and your email address returns a working key in the response. Keep the original Idempotency-Key and body for response replay for up to 24 hours, under the conditions in the quickstart. The trial is 800 credits over 30 days once the address is confirmed, no card; paid plans start at 29 € a month. See the [quickstart](https://pokemontcgapi.com/docs/quickstart) and the [pricing](https://pokemontcgapi.com/pricing).

Every source that can appear in a price row, with the label to print next to the number and the minimum age of any observation it carries: a figure is not served until it is older than `min_delay_hours`. `is_own` marks the composite we compute ourselves. This response does not include update cadence. Cardmarket card figures are re-read daily for Western cards and about every 48 hours for Japanese and Chinese cards; a daily point carries the latest known value. See [price methodology](https://pokemontcgapi.com/price-methodology).

## Headers

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `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/prices/sources" \
  -H "X-Api-Key: $PTCG_API_KEY"
```

**TypeScript**

`request.ts`

```ts
const url = new URL("https://api.pokemontcgapi.com/v1/prices/sources");

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/prices/sources",
    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=86400`

`response.json`

```json
{
  "data": [
    {
      "source": "CARDMARKET",
      "label": "Cardmarket",
      "min_delay_hours": 24,
      "is_own": false
    },
    {
      "source": "CARDTRADER",
      "label": "CardTrader",
      "min_delay_hours": 24,
      "is_own": false
    },
    {
      "source": "COMMUNITY",
      "label": "Community-observed",
      "min_delay_hours": 0,
      "is_own": false
    },
    {
      "source": "EBAY",
      "label": "eBay",
      "min_delay_hours": 24,
      "is_own": false
    },
    {
      "source": "PRICECHARTING",
      "label": "PriceCharting",
      "min_delay_hours": 24,
      "is_own": false
    },
    {
      "source": "PTCG_INDEX",
      "label": "pokemontcgapi composite index",
      "min_delay_hours": 0,
      "is_own": true
    },
    {
      "source": "TCGPLAYER",
      "label": "TCGplayer",
      "min_delay_hours": 24,
      "is_own": false
    }
  ],
  "count": 7
}
```

## Errors

Every error body carries `error.code`, `error.message` and `error.request_id`. Switch on the code, never on the message.

| Status | Code | When |
| --- | --- | --- |
| 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](https://pokemontcgapi.com/docs/errors) page.
