Documentation

Changelog

Reverse-chronological log of every API change. Watch [BREAKING] entries closely.

Machine-readable: RSS feed · JSON feed · Markdown

  • changed

    Graded prices on /v2/cards use the weighted median of recent sales#

    Oct 30, 2026

    A current graded price is now the weighted median of the slab's sales in the last 90 days, with each sale counting half as much for every 14 days of age, instead of always its most recent sale. It is always one of the actual sale prices, never an average. A fresh sale weighs more than older ones, so the price is usually still the newest sale; it differs once a slab has three or more sales close together in time. That is rare for slabs today, so few prices change now; the difference grows as slabs sell more often. Expiry is unchanged: a graded price expires 90 days after the slab's most recent sale, and last_sale_at and price_expires_at still refer to that sale. Graded browse and search (graded=only) sort by the served price. See Thin markets.

  • changed

    Graded prices on /v2/cards expire after 90 days without a sale, and updated_after now returns graded variants#

    Oct 30, 2026

    A graded variant's price is its most recent sale. It now expires when that sale is more than 90 days old: markets[].price becomes null, price_status is expired, last_price keeps the sale, and updated_at stays the time of the sale. Until now a graded price stayed current however old its sale was. Every graded market also gains last_sale_at (when the sale behind the price happened) and price_expires_at (when it ages out); both are null on raw variants. Graded browse and search (graded=only) list expired slabs after priced ones. updated_after now returns a graded variant when we record a new sale for it, when a sale moves out of one of its periods windows, and when its price expires. Before, it never returned graded variants. periods is unchanged. See Thin markets.

    Note: Graded sales can reach us days after they happen, so a graded variant counts as changed when we record the sale, not when it sold. An `updated_after` sync now picks up late sales and expiries, but a variant may come back with an `updated_at` older than your last sync.
  • added

    Barcode lookup for sealed product on /v2/cards#

    Oct 19, 2026

    Look up sealed product by its retail barcode with the new gtin parameter: GET /v2/cards?gtin=820650850714. It accepts a 12-digit UPC-A, a 13-digit EAN-13 or JAN, an 8-digit EAN-8 and a 14-digit GTIN-14, and ignores spaces and hyphens. A barcode sent as q (12 to 14 digits) is now matched the same way, then falls back to a normal name search if no product carries it, so apps that pass scanner input straight to q get the product instead of an empty result. One barcode can match several listings, so data may hold more than one card. See v2 identifiers.

    Note: Coverage starts with sealed Magic: The Gathering, Pokémon and Yu-Gi-Oh! product and will grow. A code with an invalid check digit returns `400`; a valid code we don't recognize returns `404`.
  • changed

    changes_count on /v2/cards now counts price changes#

    Oct 19, 2026

    markets[].periods.<window>.changes_count now counts the number of times the sale price changed during the window. Five sales all at the same price count 0. Until now it carried the same value as sales_count, which is unchanged. See periods fields.

  • added

    Sales counts on /v2/cards#

    Oct 19, 2026

    Every window in markets[].periods now carries sales_count: the number of sales recorded for the variant in that market over the window (7d, 30d, 90d, 1y, all_time). It is on browse, search, direct lookups and POST /v2/cards, for raw and graded variants, and follows include=periods[.<window>] like every other period statistic. It counts sales, not units, and leaves out refunded and voided sales. A window with no recorded sales is omitted, so read a missing window as zero. See periods fields.

    Note: `changes_count` keeps working and carries the same value; its description has been corrected, since in v2 it was always a count of sales rather than of price changes. Individual sale records are not exposed.
  • changed

    All-time price statistics now cover full history#

    Oct 12, 2026

    v1 minPriceAllTime / maxPriceAllTime were computed over the trailing year only, so they always matched minPrice1y / maxPrice1y. They now cover everything recorded since tracking began in March 2025, and existing values have been backfilled. minPriceAllTimeDate / maxPriceAllTimeDate now give the date the extreme was first reached; previously a price that stayed at its extreme was stamped with its most recent update.

    Note: Expect all-time lows to drop and highs to rise for many variants, and their dates to move earlier. The 1y fields are unchanged.
  • added

    v2 batch (POST /v2/cards) documented#

    Oct 12, 2026

    POST /v2/cards fetches many cards in one request and returns them in the v2 schema. Send a JSON array of lookup objects with snake_case keys (card_id, variant_id, tcgplayer_id, tcgplayer_sku_id, mtgjson_id, scryfall_id); include, updated_after and regions go on the query string. See v2 batch.

    Note: v1-style camelCase items (`cardId`) return `400` on v2. The v2 lookup parameter for a SKU is `tcgplayer_sku_id`; earlier docs listed it as `tcgplayer_sku`.
  • added

    Price status and last known price on every variant#

    Oct 5, 2026

    Since 2026-10-01 a variant priced at $100 or more that goes 14 days without a reported price expires to a null price (see Thin markets). The response now says so explicitly. v1 variants carry priceStatus (current, expired, unpriced) and lastKnownPrice; v2 markets[] entries carry price_status and last_price. lastUpdated / updated_at is defined as when the price was last observed, so for an expired variant it is when the last price was seen. Price history and window statistics are never modified by an expiry.

    Note: An expiry now counts as a price change: `updated_after` returns the expired variant once, with its `null` price, without `include_null_prices=true`. If your incremental sync assumed every returned price is non-null, handle `null` (or branch on `priceStatus`).
  • changed

    OpenAPI (Swagger) spec now covers /v2/cards#

    Sep 22, 2026

    The public OpenAPI spec at https://justtcg.com/docs/swagger.json (now version 1.1.0) describes the /v2/cards beta alongside v1: GET /v2/cards and GET /v2/cards/{id}, with graded variants, the per-region markets array, cursor pagination headers, and application/problem+json errors. v2 operations are tagged v2 (beta) and marked x-beta: true.

    Note: The spec's server URL is now `https://api.justtcg.com` and every path carries its version prefix (`/v1/cards` rather than `/cards`). The URLs clients call are unchanged, but if you generated a client from the old spec, regenerate it. v2 batch is not live yet, so it is not in the spec.
  • added

    New Games: Palworld OFFICIAL CARD GAME and Cyberpunk TCG#

    Sep 11, 2026

    Added support for two new games: Palworld OFFICIAL CARD GAME (palworld-official-card-game) and Cyberpunk TCG (cyberpunk-tcg).

  • added

    Filter variants by language#

    Sep 1, 2026

    Added the language query parameter to GET /v1/cards and GET /v2/cards. Pass one or more languages, comma-separated, to narrow the variants array on each returned card: ?language=Japanese or ?language=English,Japanese. Values are case-insensitive, and an unrecognized value returns an error rather than being ignored. Accepted values are English, Japanese, French, German, Spanish, Italian, Chinese (S), Chinese (T), Portuguese, Russian, and Korean. See the /v1/cards and /v2/cards references.

    Note: This filters variants, not cards. Result counts and pagination are unchanged whether or not you send it, which means a card with no variant in the language you asked for is still returned, with an empty `variants` array. Filter those out client-side if you only want matches. Variants with no language recorded are English.
  • changed

    Commercial use rights clarified#

    Jul 27, 2026

    Expanded Section 7 of the Terms of Service to spell out what paid subscribers may do with the data: display prices and history to end users, derive your own analytics and valuations, cache and store price points with no retention limit, and combine our data with other lawful sources. The boundary is unchanged (no reselling raw data and no building an API substitute), but it's now stated explicitly rather than implied. Also published a plain-English Commercial Use Guidelines page.

    Note: No rights were removed. If you're on a paid plan and building your own product, this change only clarifies what was already intended. The free tier remains personal, non-commercial use.
  • added

    /v2/cards is now in Beta#

    Jul 9, 2026

    Opened the beta of /v2/cards, see the /v2/cards reference. Headline changes: graded cards as first-class variants, multi-region localized pricing via a per-variant markets array, an optional regions parameter (defaults to NA), snake_case everywhere, cursor pagination (RFC 8288 Link header), and application/problem+json errors. v2 covers the /cards endpoint only; /games and /sets stay on v1.

    Note: Beta: the contract is finalized but may still change before GA. v1 is unchanged and remains the default for every endpoint; adopt v2 per call at your own pace.
  • added

    UUIDs added to both Card and Variant objects.#

    Jun 8, 2026

    Added uuid to both Card and Variant objects. This provides a stable, globally unique identifier for each entity, independent of the human-readable id. We recommend using this as your primary key moving forward. API v2 will use UUIDs as the primary id field. The slug-based id will still be supported for backwards compatibility.

  • added

    Price History [1 Year Duration]#

    Apr 15, 2026

    Added 1y as a new allowed value for the priceHistoryDuration query parameter on the GET /cards endpoint. When requested, the priceHistory array on each variant returns one data point per day over the trailing 365 days, sourced from a daily materialized aggregate. Existing values (7d, 30d, 90d, 180d) are unchanged, and the default remains 7d.

  • added

    min_price Parameter Added to /cards Endpoint#

    Feb 25, 2026

    Added the min_price optional query parameter to the GET /cards endpoint. This allows users to filter results by a minimum market price (e.g., min_price=1.00), significantly reducing noise from low-value cards in analytics and trending lists.

  • added

    MCP Endpoint Added#

    Feb 19, 2026

    The MCP endpoint provides comprehensive pricing data to your agentic workflows.

  • added

    UniVersus Game Support Added#

    Feb 17, 2026

    Added support for UniVersus. Use universus as the game query parameter to access UniVersus card data.

  • added

    Sorcery Game Support Added#

    Dec 29, 2025

    Added support for Sorcery: Contested Realm. Use sorcery-contested-realm as the game query parameter to access Sorcery card data.

  • changed

    90-Day and 180-Day Price History Support Added#

    Dec 19, 2025

    Added support for 90d and 180d price history. Deprecated priceHistory30d in the process. Use query param priceHistoryDuration to select desired durations (7d, 30d, 90d, 180d). Defaults to 7d. priceHistory30d will be removed in a future major release.

  • added

    New Games: hololive OFFICIAL CARD GAME and Dragon Ball Super: Fusion World#

    Dec 15, 2025

    Added support for two new games: hololive OFFICIAL CARD GAME (hololive-official-card-game) and Dragon Ball Super: Fusion World (dragon-ball-super-fusion-world).

  • added

    Game and Set Value Index Fields Added#

    Dec 13, 2025

    Added game_value_usd to /games and set_value_usd to /sets. These represent the total value of all cards in the game/set, calculated by taking the highest price of any variant for each card.

  • added

    include_null_prices Parameter Added#

    Dec 9, 2025

    Added the include_null_prices boolean query parameter to /cards. When true, the response includes cards that don't have any pricing data. Default false.

  • added

    Card Number Filter Added to /cards#

    Dec 8, 2025

    Added the number query parameter to /cards so you can filter cards by their specific card number within a set.

  • changed

    Introduced sealed_count and variants_count Fields#

    Nov 21, 2025

    Fixed card counts in /sets and /games to exclude sealed products. Introduced sealed_count on both endpoints and variants_count on /sets.

  • added

    updated_after Parameter Added to /cards#

    Nov 19, 2025

    Added updated_after to both GET /cards and POST /cards (Batch). Filters results to variants whose pricing was updated at or after the provided Unix timestamp. Cannot be combined with the search query parameter (q).

  • added

    External Identifiers Added#

    Oct 27, 2025

    Added support for querying cards by MTGJSON and Scryfall IDs. Variants can be queried using TCGplayer SKU IDs.

  • added

    Set Release Dates Added to /sets#

    Oct 17, 2025

    The /sets endpoint now includes the release date of each set.

  • changed

    Set IDs Standardized and set_name Added to Card Object#

    Sep 30, 2025

    Set IDs standardized to lowercase-hyphenated format including the game name. Added set_name to the card object.

  • added

    Payload Reduction Parameters Added#

    Sep 29, 2025

    Added include_price_history and include_statistics query parameters to /cards. Available windows: 7d, 30d, 90d, allTime.

  • added

    JavaScript and TypeScript SDKs Released#

    Sep 23, 2025

    Released the official JS / TS SDKs. Install via npm: npm install justtcg-js.

  • added

    90-Day Analytics on /cards#

    Aug 26, 2025

    Added a suite of 90-day statistical fields for deeper quarterly market analysis.

    Note: Statistical fields only — the full point-by-point `priceHistory90d` is deferred to a future major release.
  • added

    Language Field Added to Variant Object#

    Aug 12, 2025

    Added language to the variant object.

  • added

    New Games: Grand Archive TCG and Pokemon Japan#

    Aug 10, 2025

    Added support for Grand Archive TCG (grand-archive-tcg) and Pokemon Japan (pokemon-japan).

  • added

    Multi-Condition and Multi-Printing Support#

    Aug 1, 2025

    The /cards endpoint now accepts condition and printing query parameters with multiple comma-separated values, e.g. /cards?condition=NM,LP&printing=First Edition,Unlimited.

  • removedBreaking

    [BREAKING] Card ID Standardization Completed#

    Jul 11, 2025

    The id format for cards and variants now includes the card's rarity. Old format game-set-name, new format game-set-name-rarity. All previously stored IDs are invalid and must be re-fetched.

  • added

    OrderBy Parameters Added#

    Jul 4, 2025

    Added orderBy (price, 24h, 7d, 30d) and order (asc, desc) for sorting.

  • removedBreaking

    [BREAKING] Card ID Standardization#

    Jul 1, 2025

    Card IDs now include the full game name. Some IDs with invalid characters have been standardized.

  • changed

    Rate Limit Policy Update#

    Jun 14, 2025

    API rate limits adjusted for free users. See the Rate Limits page for details.

  • added

    v1 API Launched#

    Apr 2, 2025

    Version 1 introduces initial endpoints and card structure.