Thin markets and price expiry
Some cards rarely sell. This page explains what that does to a price, when a price expires, and which fields tell you how far to trust it. It applies to v1 and v2 alike; only the field names differ.
price becomes null, its status says expired, and the value that expired is kept in lastKnownPrice (v1) or last_price (v2). Price history and statistics are never changed.Why thin markets look odd
A variant's price is the last price the market recorded for that condition. It is never smoothed, clamped, or overridden. For cards that rarely trade raw, such as vintage chase cards, ultra-rare promos, and most graded grades, a single condition can go months between sales. One mislisted sale can therefore set the price for a long time, and conditions can look inverted (Moderately Played above Near Mint).
How a price expires
Marketplaces eventually correct or age out bad sales and stop reporting a price for that condition altogether. When that happens we do not keep serving the last value forever: a variant priced at $100 or more that goes 14 days without a reported price expires to a null price until a new sale is recorded. Expiry has been in effect since 2026-10-01.
Expiry changes price and nothing else. The variant reports an expired status and carries the value that expired. Its last-observed timestamp, price history and window statistics are left untouched. When a new sale arrives, the status returns to current. Graded variants never expire, because a slab that trades a few times a year is normal rather than a sign of a stale market.
The fields, in v1 and v2
| Meaning | v1 | v2 |
|---|---|---|
| Current price (null when expired or never priced) | price | markets[].price |
| Why the price is what it is: current, expired or unpriced | priceStatus | markets[].price_status |
| The value that expired (null unless expired) | lastKnownPrice | markets[].last_price |
| When the price was last observed | lastUpdated | markets[].updated_at |
| Price changes in the last 90 days | priceChangesCount90d | markets[].periods.90d.changes_count |
The status takes one of three values. current: a market report is in effect. expired: the last price aged out, so the price is null and the last observed value is carried alongside it. unpriced: this condition has never had a price. Full field references: Variant object (v1) and Variant object (v2).
{
"id": "one-piece-card-game-…-secret-rare_near-mint_foil",
"price": null,
"priceStatus": "expired",
"lastKnownPrice": 4400.43,
"lastUpdated": 1782360444
}Incremental syncs
An expiry counts as a price change, so a sync that uses updated_after receives the expired variant once, with its null price. If your sync assumes every returned price is non-null, handle null or branch on the status field. Outside of updated_after, a card whose every variant is null is omitted from browse responses unless you pass include_null_prices=true.
Judging confidence yourself
The response carries what you need:
- Treat a variant with 0 price changes in 90 days, or a last-observed time older than 14 days, as low confidence.
- Treat a condition priced above the next-better condition of the same card as a flag, and clamp it client-side if your use case needs a strict ladder.
For the vast majority of the catalog these checks never fire. JustTCG is a sales-data API, not a valuation service: when there is no market activity, we would rather show you that than invent a number.