Get sales
What copies actually sold for on Cardmarket, day by day.
Realized sales, not asking prices: the average price copies sold for on each day any changed hands, every language and condition together. On a product sold in two versions, without finish it is the plain version's chart; the other version's starts at our first read of that view.
Sparse: a day without a sale has no point. The series begins at our first read of the product page; Cardmarket shows about the last 30 days on which a copy sold, and each read since adds the new days.
Pokémon, Yu-Gi-Oh!, Dragon Ball Super, One Piece and Magic: The Gathering also have older windows, from archived copies of the product page (the Wayback Machine, captured 2018 to 2023), each carrying the chart as it stood that day. English cards with sales before 2024: Magic 8,719, Yu-Gi-Oh! 4,877, Pokémon 3,619, Dragon Ball Super 2,463, One Piece 25. Between the last capture and our first read there is a gap, of years for most cards.
Path parameters
| Parameter | Type | Description |
|---|---|---|
| cardIdrequired | string | A card id. An id retired by a set re-key keeps working and is reported in meta.movedFrom. |
Query parameters
Any other query parameter is a 400 naming it and listing these, so a misspelt one is never silently ignored. api_key is accepted on every endpoint as an alternative to the header.
| Parameter | Type | Description |
|---|---|---|
| days | integer | How many days back from today, 1 to 7,305. Default: |
| finish | string | A printing Cardmarket sells as its own product, such as masterball, pokeball or staff: that product's chart instead of the card's. On a product sold in two versions, foil or reverse-holo is the other version's chart, which Cardmarket shows with the page's foil switch on. Any finish prices reports is accepted; one with no chart of its own has no points. |
Response
200 The sales.
| Field | Type | Description |
|---|---|---|
| data | object | The sales. |
| data.cardId | string | The card's current id. |
| data.source | string | Always cardmarket.One of: |
| data.finish | string | Present when finish was asked for: the printing or version whose chart the series is.Absent unless it applies. |
| data.currency | string | Always EUR.One of: |
| data.sales | object[] | Oldest first. |
| data.sales[].day | string | YYYY-MM-DD. |
| data.sales[].avgSell | number | Average sale price that day, EUR. |
| meta | object | The window. |
| meta.days | integer | The window used. |
| meta.count | integer | Days with a sale. |
| meta.note | string | How to read the series. |
| meta.pricesFrom | string | Present when the prices are another printing's: englishTwin for a localized printing served its English printing's, localizedTwin for an English printing no marketplace sells in English, served its twin's in another language.One of: Absent unless it applies. |
| meta.englishId | string | Present with englishTwin: the English printing the prices are from.Absent unless it applies. |
| meta.pricesTwin | object | Present with localizedTwin: the printing quoted.Absent unless it applies. |
| meta.pricesTwin.id | string | Its id. |
| meta.pricesTwin.language | string | The language its copies are in, so the quotes are labelled with it. |
| meta.movedFrom | string | The id you asked for, when it was retired by a set re-key. Absent unless it applies. |
Examples
Real responses from the production API, recorded on 2026-10-05 by the script that also checks every field above against them. Arrays are shown in full.
Last 30 days
curl "https://api.tcggraph.com/v1/prices/pkm_sv3pt5_6/sales?days=30" \
-H "Authorization: Bearer $TCGGRAPH_API_KEY"const response = await fetch("https://api.tcggraph.com/v1/prices/pkm_sv3pt5_6/sales?days=30", {
headers: {
Authorization: `Bearer ${process.env.TCGGRAPH_API_KEY}`,
},
});
const body = await response.json();
if (!response.ok) throw new Error(`${body.error.code}: ${body.error.message}`);import os
import requests
response = requests.get(
"https://api.tcggraph.com/v1/prices/pkm_sv3pt5_6/sales",
params={
"days": "30",
},
headers={"Authorization": f"Bearer {os.environ['TCGGRAPH_API_KEY']}"},
)
body = response.json()
response.raise_for_status(){
"data": {
"cardId": "pkm_sv3pt5_6",
"source": "cardmarket",
"currency": "EUR",
"sales": [
{
"day": "2026-09-05",
"avgSell": 8.08
},
{
"day": "2026-09-06",
"avgSell": 8.24
},
{
"day": "2026-09-07",
"avgSell": 9.31
},
{
"day": "2026-09-08",
"avgSell": 6.99
},
{
"day": "2026-09-09",
"avgSell": 8.16
},
{
"day": "2026-09-10",
"avgSell": 8.67
},
{
"day": "2026-09-11",
"avgSell": 8.29
},
{
"day": "2026-09-12",
"avgSell": 7.49
},
{
"day": "2026-09-13",
"avgSell": 8.95
},
{
"day": "2026-09-14",
"avgSell": 8.07
},
{
"day": "2026-09-15",
"avgSell": 8.25
},
{
"day": "2026-09-16",
"avgSell": 8.63
},
{
"day": "2026-09-17",
"avgSell": 12.17
},
{
"day": "2026-09-18",
"avgSell": 7.03
},
{
"day": "2026-09-19",
"avgSell": 7.69
},
{
"day": "2026-09-20",
"avgSell": 8.86
},
{
"day": "2026-09-21",
"avgSell": 9.78
},
{
"day": "2026-09-22",
"avgSell": 8.46
},
{
"day": "2026-09-23",
"avgSell": 9.54
},
{
"day": "2026-09-24",
"avgSell": 8.14
},
{
"day": "2026-09-25",
"avgSell": 7.72
},
{
"day": "2026-09-26",
"avgSell": 7.95
},
{
"day": "2026-09-27",
"avgSell": 7.25
},
{
"day": "2026-09-28",
"avgSell": 8.61
},
{
"day": "2026-09-29",
"avgSell": 9.34
},
{
"day": "2026-09-30",
"avgSell": 7.59
},
{
"day": "2026-10-01",
"avgSell": 7.58
},
{
"day": "2026-10-02",
"avgSell": 8.05
},
{
"day": "2026-10-03",
"avgSell": 9.66
},
{
"day": "2026-10-04",
"avgSell": 7.94
}
]
},
"meta": {
"days": 30,
"count": 30,
"note": "One point per day copies sold; days without a sale are absent. Every language and condition together."
}
}Errors
Every error has the same body; switch on error.code. Any endpoint can also answer 401, 402, 403 or 429 for reasons of key, plan or rate; those are on Errors.
| Status | Code | When |
|---|---|---|
| 400 | invalid_request | days outside 1 to 7,305 or not a whole number, finish not a finish prices reports, or a parameter this endpoint does not take. |
| 404 | not_found | No card has that id. |
Too many days
curl "https://api.tcggraph.com/v1/prices/pkm_sv3pt5_6/sales?days=9000" \
-H "Authorization: Bearer $TCGGRAPH_API_KEY"const response = await fetch("https://api.tcggraph.com/v1/prices/pkm_sv3pt5_6/sales?days=9000", {
headers: {
Authorization: `Bearer ${process.env.TCGGRAPH_API_KEY}`,
},
});
const body = await response.json();
if (!response.ok) throw new Error(`${body.error.code}: ${body.error.message}`);import os
import requests
response = requests.get(
"https://api.tcggraph.com/v1/prices/pkm_sv3pt5_6/sales",
params={
"days": "9000",
},
headers={"Authorization": f"Bearer {os.environ['TCGGRAPH_API_KEY']}"},
)
body = response.json()
response.raise_for_status(){
"error": {
"code": "invalid_request",
"message": "`days` must be a whole number from 1 to 7305.",
"details": {
"field": "days",
"got": "9000"
}
}
}