Card Scanner API

Updated . Plan numbers are the ones on the developers page that day; the live plans table wins if they ever disagree.

Quick answer

The HobbyCardIndex card scanner API identifies a sports or trading card from a photo: POST the image and get back the matching card with its parallel, print run, a confidence score, its prices and up to seven alternatives, and a graded slab also returns the grader, grade and cert number read from the label. Lite includes 25,000 scans a month for $99, and a free setup month allows 1,000 a day.

How the scan endpoint works

Everything lives under https://hobbycardindex.com/api/v1/ and takes your key in an X-API-Key header (an Authorization: Bearer header works too). Every successful response is wrapped as {"success": true, "data": {...}}; the examples on this page show what sits inside data. Prices are US dollars with two decimals.

POST /scan with a JSON body: image, the photo as base64 (JPEG, PNG or WebP, under 10 MB; a data: URL prefix is fine), and optionally category (baseball, pokemon, marvel and so on) to narrow the match and slab (true or false) when you already know whether it's graded. Our own scanner matches the photo against more than 8 million card images. match is the best card with its id, player or character, year, set, card number, parallel, printRun, a confidence from 0 to 1 and its prices; it's null when nothing is close enough. alternatives are up to seven more cards with the same fields, without prices. Pass an id on to /prices/{cardId} and /sales.

Try it: a photo of a graded card

curl -X POST 'https://hobbycardindex.com/api/v1/scan' \
  -H 'X-API-Key: hci_live_...' \
  -H 'Content-Type: application/json' \
  -d "{\"image\":\"$(base64 -w0 slab.jpg)\",\"category\":\"baseball\"}"
{
  "match": {
    "id": 12345,
    "name": "Mike Trout #US175",
    "playerName": "Mike Trout",
    "year": 2011,
    "setName": "Topps Update",
    "cardNumber": "US175",
    "parallel": "Base",
    "printRun": null,
    "confidence": 0.97,
    "prices": {
      "loose": 293,
      "psa10": 4500,
      "psa9": 1250,
      "psa8": 640
    }
  },
  "alternatives": [
    {
      "id": 12346,
      "name": "Mike Trout [Gold] #US175",
      "playerName": "Mike Trout",
      "year": 2011,
      "setName": "Topps Update",
      "cardNumber": "US175",
      "parallel": "Gold",
      "printRun": 2011,
      "confidence": 0.91
    }
  ],
  "slab": {
    "grader": "PSA",
    "grade": "10",
    "certNumber": "12345678",
    "certVerified": true
  },
  "usage": {
    "scans": {
      "used": 13,
      "allowance": 25000
    }
  }
}

Example values. A raw card returns null for slab. In Node, read the file and call .toString('base64'); in Python, base64.b64encode(f.read()).decode().

Card recognition API: what it reads

The scanner reads the card face to find the card, then reads colour and finish to pick the parallel, and reads the serial stamp when that can't settle it. Look-alike parallels can still come back wrong, which is why the response carries alternatives with their own confidence scores: show them and let your users choose, the way our own app does. On a graded card the label is read too, so the slab block names the grading company, the grade and the cert, with certVerified true when that cert resolved to the grader's record. The same request handles raw cards, cards in toploaders and slabs from PSA, BGS, CGC and SGC, across sports cards and the trading card games.

Slab identification API

For a graded card, the scan is the fast path from photo to price: one call returns the card, the grader and grade, the cert number and the price at that grade. If you'd rather start from the number on the label, GET /certs/{grader}/{certNumber} on the cert lookup page returns the grader's record and the matching card. An intake flow at a shop or a show usually does both: scan first, then confirm the cert.

Scans by plan, and what counts

Lite includes 25,000 photo scans a month at 2 a second, Growth Lite 125,000 at 3 a second, Growth 500,000 at 5 a second and Platform 1,500,000 at 10 a second; the free setup month is capped at 1,000 scans a day. Scans are their own pool, separate from requests. Every scan counts, including a request without a usable photo; a scan that fails on our side (a 5xx) doesn't. Once the monthly scans are used, the three card sizes carry on at $1 per 250 (Lite), 500 (Growth Lite) or 1,000 (Growth) more calls, to a ceiling of 3x. Errors: 400 NO_IMAGE or INVALID_IMAGE, 413 IMAGE_TOO_LARGE, 403 REQUIRES_PARTNER_PLAN on an Enterprise key, and 429 when a key goes over its scans a second or the scanner is busy; retry after the Retry-After seconds.

If you're deciding between an API and a desk scanner for a backlog, best scanners for trading cards covers the hardware side, and the Pokémon card scanners hub shows what the phone scanner does inside the app.

What you get

Plans and prices

Commercial plans in US dollars, as listed on the developers page on November 1, 2026
PlanPriceRequests a monthPhoto scansSold-sale lookupsCert lookupsLookups a secondPast the requests and scans (up to 3x)
Lite$99 a month25,00025,0005,00015010$1 per 250 more
Growth Lite$249 a month125,000125,00025,00075015$1 per 500 more
Growth$499 a month500,000500,000100,0003,00020$1 per 1,000 more
Platformfrom $1,500 a month2,000,0001,500,000500,00050,000, plus 50,000 pop reports50Set up with Sean, invoiced; bulk price files included

Price history comes with every size. Sold-sale, cert and pop lookups stop at the plan's number and never run over. Two add-ons: pop reports plus cert lookups for $100 a month, which brings 32,000 of each to Lite, Growth Lite or Growth, and the daily price files for $450 a month on Growth Lite or Growth (included in Platform, not offered on Lite). Lite, Growth Lite and Growth are month to month by card, cancelled any time in Settings, API Access, and run to the end of the paid month.

The free setup month is 30 days on real data with no card: 1,000 requests and 1,000 photo scans a day, 500 sold-sale lookups and 100 cert lookups for the month. You apply in Settings, API Access once you're signed in, and Sean reviews each one. When the 30 days end, the first month of the plan you applied with is invoiced, and paying it keeps the key going. Full plan details are on the developers page.

Apply for a free setup month

Credit and data use

A commercial plan licenses the data for a product your users see. You can store the prices and price history you pull while the plan is active and use them on card pages, in charts, collection values and your own estimates. Sold-sale records can be shown to your users and kept in your product, but not turned into a standalone sales database, copied by the category or offered as a download. Card recognition stays with the scan endpoint: show our identifications, don't use them to build a recognizer of your own.

The terms ask for one link back to us somewhere on your site, such as "Prices and API supplied by Hobby Card Index". It does not need to be beside the prices or on your main page. When a plan ends, stored copies go within 30 days. The full wording is in the Terms of Service, section 8, and the shorter version is under Data use on the developers page.

Common questions

Is there an API to identify a card from a photo?

Yes. POST /api/v1/scan on the HobbyCardIndex API takes a photo as base64 JSON and returns the matching card with its player or character, year, set, card number, parallel, print run, a confidence from 0 to 1 and its prices, plus up to seven alternatives. It matches against more than 8 million card images.

Does the card scanner API read graded slabs?

Yes. On a graded card the label is read too, and the slab block carries the grader, grade and cert number, with certVerified true when the cert number resolved to the grader's record. On a raw card slab is null. You can pass slab true or false in the request when you already know which it is.

How accurate is card recognition on parallels?

The scanner reads colour and finish to pick the parallel, and reads the serial stamp when that can't settle it, but look-alike parallels can still come back wrong. That's why the response carries up to seven alternatives with their own confidence scores: show them and let your users choose, the way our own app does.

What image formats and sizes does the scan API take?

JPEG, PNG or WebP, under 10 MB, sent as base64 in the image field of a JSON body; a data: URL prefix is fine. Add category (baseball, pokemon, marvel and so on) to narrow the match. Errors are 400 NO_IMAGE or INVALID_IMAGE, 413 IMAGE_TOO_LARGE and 429 when a key goes over its scans a second.

How many scans does each plan include?

Lite includes 25,000 photo scans a month at 2 a second, Growth Lite 125,000 at 3, Growth 500,000 at 5 and Platform 1,500,000 at 10 a second. The free setup month allows 1,000 a day. Past the monthly scans, Lite, Growth Lite and Growth keep working at $1 per 250, 500 or 1,000 extra calls, up to 3x.

Can I use the scan results to train my own card recognizer?

No. The terms keep card recognition with our scan endpoint: you can show our identifications to your users and build on them in your product, but not use them to recognize cards yourself in place of the scan, including by pairing identifications with photos, fingerprints or embeddings. Prices and price history are yours to store while the plan is active.