# Identify a card from a photo

Send a photo and get back the card and, where the photo shows it, the exact printing: 1st Edition, Shadowless, reverse holo, stamped promos, the 1999–2000 copyright print. The same feature is available as the GraphQL field `identifyCard`, the MCP tool `identify_card` and the CLI command `raritydb identify`.

```graphql
query($image: String!) {
  identifyCard(image: $image) {
    status confidence hints
    card { code name number set { name printedTotal } }
    printing { key finish stamps subtype }
    printings { key finish stamps subtype }
    candidates { score textScore imageSimilarity reasons card { code name } }
    reading { name number printedTotal setCode language firstEditionStamp shadowless holoArea slabGrader slabGrade slabCert }
    quality { cardFound shortEdgePx sharpness glareFraction }
  }
}
```

```bash
raritydb identify charizard.jpg
raritydb identify charizard.jpg --tilted charizard-tilted.jpg --json
```

`image` is base64, a data URL (`data:image/jpeg;base64,…`) or an `https://` URL. It must be a JPEG, PNG or WebP of at most 10 MB, with at least 600 px on the short edge. Each call counts as one request.

## How it works

1. The card's outline is found and straightened, and the photo's quality is measured (`quality`).
2. A vision model reads what is printed on the card: name, collector number, set size, set code, language, stamps, the copyright line, where the holo shine is, and a graded slab's label (`reading`).
3. At the same time the photo is compared with the reference scan of every card (`imageSimilarity`).
4. Both kinds of evidence rank the candidates. Each candidate lists its `reasons`, e.g. "number 4 matches; set size 102 matches Base Set; looks like the reference scan (similarity 0.96)".
5. The cues visible on the card narrow the best match's printings (`printing`, or `printings` when more than one is still possible).

## Status

| Status | Meaning |
|---|---|
| `MATCH` | The text and the image agree, and the best candidate clearly beats the next one. |
| `AMBIGUOUS` | Several cards fit. `candidates` ranks them, and `hints` says what would settle it. |
| `NO_MATCH` | Not a trading card, or nothing in the catalog fits. |

`printing` is only set when exactly one printing fits what the photo shows. Otherwise `printings` lists those still possible, and `hints` names the missing cue, for example "Tilt the card under a light so the holo shine shows (holo or reverse)".

## Several cards in one photo

`identifyCards` takes one photo of a spread on a table or a binder page (up to 20 cards) and identifies each card. Cards are found by their outlines and returned in reading order, with their `row`, `column` and `box` (where the card is in the photo, as fractions of its width and height).

```graphql
query($image: String!) {
  identifyCards(image: $image) {
    foundBy detected hints
    cards { row column box { x y width height } error identification { status card { code name } printing { key } } }
  }
}
```

```bash
raritydb identify-cards binder-page.jpg --grid 3x3
```

- **Binder pages:** when the cards touch, their edges can't be told apart. Pass `grid: "3x3"` (rows x columns) and the photo is split evenly instead (`foundBy: "grid"`).
- **Quota:** each identified card counts as one photo check. Cards past your remaining checks come back with `error` instead of an `identification`, so a page never fails halfway.
- **Errors per card:** a card too small or unreadable gets its own `error`; the others are unaffected.
- **Size:** cards in a page photo can be as small as 400 px on the short edge (600 for a single photo). For the best reads, photograph a 9-pocket page from straight above, filling the frame.
- **One card found:** if no separate cards are found, the whole photo is read as one card, with a hint.

## Photo tips

- Lay the card flat on a plain, contrasting background and fill most of the frame.
- Use even light. Glare over the number or set code is the most common cause of `AMBIGUOUS`.
- Take it out of a toploader if you can. A penny sleeve is fine.
- Holo or reverse holo? Add `tiltedImage` (CLI: `--tilted`), a second photo tilted under a light so the shine shows.
- Graded slabs work: the grader, grade and cert number are read from the label (`reading.slabGrader`, `slabGrade`, `slabCert`).

## Graded slabs

When the photo shows a slab label, `slab` says where to verify its cert with the grader, and whether the number is even possible for that grader:

```graphql
{ identifyCard(image: $image) { reading { slabGrader slabGrade slabCert } slab { grader formatValid verifyUrl directLink note } } }
```

| Grader | `verifyUrl` |
|---|---|
| PSA | `https://www.psacard.com/cert/{cert}` |
| CGC Cards | `https://www.cgccards.com/certlookup/{cert}/` |
| TAG | `https://my.taggrading.com/card/{cert}` |
| Beckett (BGS) | `https://www.beckett.com/grading/card-lookup` (a form; `directLink: false`) |
| SGC | `https://www.gosgc.com/cert-code-lookup` (a form) |

We link to the graders' pages and don't look certs up ourselves. Open the page and check that it shows **this card and this grade**, because a fake slab can carry a real cert copied from another card. `formatValid: false` means the number can't be one of that grader's certs, which is a red flag. The same check is available without a photo: `slabVerification(grader: "PSA", cert: "12345678")`, `raritydb slab psa 12345678`, or the `verify_slab` MCP tool.

## What it can and can't tell

- **Can:** the set, number and language of any card in the catalog, including Japanese and other Asian prints. Visible printing cues: the 1st Edition stamp, Shadowless (Base Set), the 1999–2000 copyright, holo vs reverse holo (best with a tilted photo), stamps, Poké Ball / Master Ball patterns.
- **Can't:** distinguish printings that look the same in a photo (some print-run differences, or a misprint that isn't visible), or authenticate a card. It is also not a condition grade.
- Reference scans exist for most, not all, cards. A card without one is matched on its printed text alone.
