---
title: "Identifiers — JustTCG API"
description: "How JustTCG identifies cards and variants: stable UUIDs (recommended), the legacy human-readable slugs and how they are composed, and the v1 to v2 field mapping."
url: https://justtcg.com/docs/identifiers
markdown_url: https://justtcg.com/docs/identifiers.md
---

# Identifiers

Updated

Every card and variant now carries two identifiers: a stable UUID (recommended) and a human-readable slug (legacy). This page explains both, how slugs are composed, and what changes in v2.

**TL;DR:** Start reading the new `uuid` field on cards and variants and use it as your primary key. The existing `id` (a slug) keeps working and remains useful as a human-readable label, but it is no longer the recommended way to reference a card.

## Two identifiers, one card

We are migrating identity from slug-based IDs to UUIDs for both cards and variants. Slugs are derived from mutable text (names, sets, rarities), so they are **not stable**. Upstream renames and edge cases caused collisions and duplicates over time. UUIDs are content-addressed and never change.

`uuid`Recommended

Stable, globally-unique, and deterministic. The canonical key we upsert on internally. Prefer this for storage, joins, and lookups.

`f8c3de3d-1fea-5d7c-a8b0-29f63c4c3454`

`id`Legacy / slug

Human-readable and great for debugging or URLs. Still returned and still queryable, but can change and is not recommended as a primary key.

`pokemon-battle-academy-fire-energy-22-charizard-stamped-promo`

## Slugs (legacy, human-readable)

A slug is a **composite** identifier: several source fields are individually sanitized, slugified, and joined with dashes. The card slug is built from `game` · `set` · `name` · `rarity`; a variant slug appends the normalized `condition` and `printing` after an underscore.

### Anatomy of a slug

Example: `pokemon-battle-academy-fire-energy-22-charizard-stamped-promo`

pokemon\-battle-academy\-fire-energy-22-charizard-stamped\-promo

-   game
    
    The game the card belongs to.
    
-   set
    
    Slugified set name.
    
-   name
    
    Card name, including parenthetical qualifiers.
    
-   rarity
    
    Slugified rarity (e.g. common, uncommon, rare, promo).
    

A [variant](https://justtcg.com/docs/schema/variant) slug extends the card slug with its condition and printing, e.g. `…charizard-stamped-promo_near-mint`.

**How each segment is generatedAdvanced — only needed if you reconstruct slugs yourself**

Every text field passes through the same two steps before being joined. If you reconstruct slugs on your end, mirror this order exactly.

1.  **1\. Sanitize special characters.** A handful of characters that slugification would otherwise silently strip are first rewritten to a word, so meaningfully different cards don't collapse to the same slug (see the table below).
2.  **2\. Slugify.** Lowercase and trim → apostrophes become dashes → remaining punctuation (`. , ! ? : ; ( )`) is removed → spaces become dashes → any non-word characters are dropped → repeated dashes collapse to one → leading/trailing dashes are trimmed.

#### Special-character mapping

These substitutions are applied to **all** text fields (name, rarity, etc.) before slugification. They are what keep `Unown (?)` and `Unown (!)`, or the asterisk alt-art markers `Mega Man*` and `Mega Man**`, from colliding.

| Character | Replaced with | Example |
| --- | --- | --- |
| ? | " question" | Unown (?) → …unown-question |
| ! | " exclamation" | Unown (!) → …unown-exclamation |
| + | " plus" | Energy+ → …energy-plus |
| \* | " star" | Mega Man\* → …mega-man-star |

#### Condition normalization

For variant slugs, the raw condition is first normalized to a canonical value before slugification. Any grade suffix is dropped to its base — `Near Mint (Holofoil)` becomes `Near Mint` — and sealed product collapses to `Sealed`.

```javascript
// Sealed / unopened product → "Sealed"
// Otherwise, collapse any suffix to the base grade:
"Near Mint"        // "Near Mint …"        → "Near Mint"
"Lightly Played"   // "Lightly Played …"   → "Lightly Played"
"Moderately Played"// "Moderately Played …"→ "Moderately Played"
"Heavily Played"   // "Heavily Played …"   → "Heavily Played"
"Damaged"          // "Damaged …"          → "Damaged"
```

## Preparing for API v2

In v2, UUIDs become the primary `id` on both objects, and today's slug-based IDs move to a dedicated `slug` field. Adopting `uuid` now means a one-line rename when you upgrade.

| v1 (today) | v2 | Notes |
| --- | --- | --- |
| card.id | card.slug | Human-readable slug, now demoted to a secondary field. |
| card.uuid | card.id | The stable UUID becomes the canonical card ID. |
| variant.id | variant.slug | Human-readable variant slug. |
| variant.uuid | variant.id | The stable UUID becomes the canonical variant ID. |

Nothing breaks today: v1 responses are unchanged except for the additive `uuid` field. Migrate at your own pace by reading `uuid` now, so the eventual switch to v2 is just `id → slug` and `uuid → id`.
