Card Grading API — AI Card Grading for Developers & Agents

One REST API for the whole job: identify a trading card from a photo, predict its grade, price it from real sold sales, and get market analysis — Pokémon, sports, and other TCGs. Built for developers and AI agents: register in one call, no human signup required.

Machine-readable surface: OpenAPI 3.1 spec · llms.txt · MCP server at /mcp

What the API does

Every scan starts with a photo. You pick the modules you want — identify, grade, market, or full for everything in one pass. Grading is the flagship, but identification, pricing, and market analysis each stand on their own.

Pokémon Card API — identify any Pokémon card from a photo

Send a photo of any Pokémon card and the API returns its name, set, number, year, and variant — you don't need to know what the card is first. That's the difference from catalog APIs like pokemontcg.io or TCGdex: those answer "give me the data for card X"; this one answers "what card is this?" It's the same identification engine behind our free Pokémon card value checker, exposed as the identify module (and included in every other module). It also identifies sports cards — parallels, print runs, and all.

Card Scanner & Recognition API

The API works as a TCG card scanner: POST an image (multipart upload or a public URL) and get structured JSON back. Front image required, back image optional but recommended for grading. JPEG/PNG up to 15MB. No SDK needed — if you can send a multipart request, you're done; the quickstart below is three curl commands.

Card Price API — values from real sold comps

The market module returns what a card is actually worth: a raw (ungraded) estimate and graded estimates in USD, built from real sold sales data — not asking prices. The gradedValueSpread breaks value out per grade level (PSA 8/9/10 and so on) with a confidence rating, so you can compute grading ROI programmatically. Values are estimates, not financial advice.

Predict your PSA grade before you submit

The grade module predicts how a card would grade professionally, with sub-grades for centering, corners, edges, and surface, plus a written justification. Collectors use it to pre-screen cards before paying for professional grading; marketplaces and inventory tools use it to attach condition data to listings at scale. It's an estimate from photos — sharp, glare-free images grade more accurately than blurry ones.

Let AI agents grade and price cards (MCP server)

AI agents can use CardGrader.AI without writing any HTTP code: connect to the MCP server at https://cardgrader.ai/mcp and the same capabilities are exposed as tools. The register_agent tool self-onboards a new agent — it returns an API key and trial credits, no human in the loop. Same modules, same credits, same pricing as the REST API below.

Quickstart

1. Register — get an API key + free trial credits

One POST, no signup. Include contactEmail to get 3 trial credits instead of 1. The key is returned exactly once — store it.

curl -X POST https://cardgrader.ai/v1/agents \
  -H "Content-Type: application/json" \
  -d '{ "name": "my-card-bot", "contactEmail": "you@example.com" }'

# 201
# {
#   "agentId": 42,
#   "apiKey": "cgk_...",          <- shown once, store it
#   "tier": "registered",
#   "credits": 3,
#   "docsUrl": "https://cardgrader.ai/api-docs",
#   "message": "Store this key securely; it cannot be retrieved again."
# }

2. Submit a scan

Send a card photo as a multipart file upload or a public image URL. Authenticate with Authorization: Bearer cgk_... (or X-Api-Key). Set an Idempotency-Key so retries never double-charge.

# multipart file upload
curl -X POST https://cardgrader.ai/v1/scans \
  -H "Authorization: Bearer cgk_..." \
  -H "Idempotency-Key: scan-001" \
  -F "front=@card-front.jpg" \
  -F "back=@card-back.jpg" \
  -F "modules=full"

# or JSON with image URLs
curl -X POST https://cardgrader.ai/v1/scans \
  -H "Authorization: Bearer cgk_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: scan-001" \
  -d '{ "frontImageUrl": "https://example.com/front.jpg", "backImageUrl": "https://example.com/back.jpg", "modules": ["full"] }'

# 202
# {
#   "id": 12345,
#   "status": "queued",
#   "modules": ["full"],
#   "creditsCharged": 2,
#   "creditsRemaining": 1,
#   "links": { "self": "/v1/scans/12345" }
# }

3. Poll for the result

Polling is free. Scans are queue-backed; results typically land in 30–120 seconds.

curl https://cardgrader.ai/v1/scans/12345 \
  -H "Authorization: Bearer cgk_..."

# while running: { "id": 12345, "status": "processing", "progressPercent": 40, "statusMessage": "..." }
# when done:
# {
#   "id": 12345,
#   "status": "completed",
#   "modules": ["full"],
#   "completedAt": "2026-06-11T18:05:00Z",
#   "identification": { "name": "...", "subject": "...", "category": "...", "year": "...",
#                       "set": "...", "number": "...", "parallel": "...", "printRun": "" },
#   "grading": { "grade": 8.5, "predictedGrade": 8.5,
#                "subGrades": { "centering": 9.0, "corners": 8.5, "edges": 8.5, "surface": 8.0 },
#                "summary": "...", "justification": "..." },
#   "value": { "rawEstimate": 145.0, "gradedEstimate": 320.0, "currency": "USD",
#              "gradedValueSpread": [ { "grade": 9.0, "value": 420.0, "confidence": "Medium" } ] },
#   "market": { "insights": "...", "gradingRecommendation": "...", "context": "..." }
# }

The response contains only the sections for the modules you requested. Failed scans return a generic error — internal worker details are never exposed.

Pricing

Every scan costs credits, summed across the modules you request. Live prices: GET /v1/pricing.

ModuleCreditsWhat you get
grade 1 Identification + AI condition grading with sub-grades (centering, corners, edges, surface).
identify 1 Card identification: name, subject, set, year, number, parallel, print run.
market 1 Identification + value estimates, graded-value spread, and market insights.
full 2 The complete fast-scan pipeline: identification, grading, pricing, and market analysis.
deep 3 Deep scan (multi-angle capture) — requires the CardGrader mobile app's guided capture; not available via the v1 API.

Trial credits at registration: 1 (anonymous) or 3 (with contactEmail). deep scans require the CardGrader mobile app's guided multi-angle capture and return 400 deep_unsupported via this API.

Credit packs

PackCreditsPrice (USD)
starter — Starter 25 $5.00
builder — Builder 120 $19.00
scale — Scale 400 $49.00
curl -X POST https://cardgrader.ai/v1/credits/purchase \
  -H "Authorization: Bearer cgk_..." \
  -H "Content-Type: application/json" \
  -d '{ "pack": "starter" }'

# 200 -> { "checkoutUrl": "https://checkout.stripe.com/...", "pack": "starter",
#          "credits": 25, "priceUsd": 5.00, "expiresAt": "..." }

Open checkoutUrl in a browser to pay; credits are granted automatically within seconds of payment. When a scan request returns 402 insufficient_credits, the error includes your balance and points at /v1/credits/packs.

Authentication & limits

Endpoints

EndpointAuthPurpose
POST /v1/agentsnoneRegister; returns API key + trial credits.
GET /v1/agents/mekeyIdentity + credit balance.
POST /v1/scanskeySubmit a card scan (costs credits).
GET /v1/scans/{id}keyPoll status / fetch results.
GET /v1/pricingnoneLive module costs + packs.
GET /v1/credits/packsnonePurchasable credit packs.
POST /v1/credits/purchasekeyStripe Checkout URL for a pack.

Full request/response schemas: openapi.json (OpenAPI 3.1).

Honest constraints

Error model

All errors are RFC 9457 application/problem+json with a stable machine-readable code extension:

{
  "type": "https://cardgrader.ai/api-docs/errors#insufficient_credits",
  "title": "Insufficient Credits",
  "status": 402,
  "detail": "Your credit balance is too low for this request. Purchase a credit pack to continue.",
  "code": "insufficient_credits",
  "creditsRemaining": 0,
  "purchaseUrl": "/v1/credits/packs"
}

Error code reference

invalid_api_key (401)
Missing, malformed, revoked, or disabled API key. Register via POST /v1/agents if you have none.
rate_limited (429)
Rate limit exceeded. Back off and retry shortly.
registration_limit (429)
This IP created the maximum number of agents in the last 24 hours. Reuse an existing key.
invalid_name / invalid_contact_email / invalid_operator_url (400)
Registration field validation failed; the detail explains the rule.
registration_failed (500)
The backing account could not be created. Safe to retry.
invalid_body / missing_front_image / invalid_image_url / invalid_image / image_too_large (400)
Scan input validation failed: bad JSON, missing/invalid front image, non-image file, or a file over 15MB.
invalid_modules (400)
Unknown module value, empty list, or full combined with other modules. Valid: identify, grade, market, full.
deep_unsupported (400)
Deep scans require the CardGrader mobile app's guided multi-angle capture. Use full instead.
invalid_idempotency_key (400)
Idempotency-Key must be 1–64 characters of [A-Za-z0-9_-].
idempotency_conflict (409)
This key belongs to a request that failed mid-flight (and was refunded). Retry with a new key.
insufficient_credits (402)
Balance too low. The error includes creditsRemaining and purchaseUrl.
scan_not_found (404)
No scan with this id exists for your agent.
pricing_unavailable / enqueue_failed (500)
Server-side failure. For enqueue_failed your credits were refunded — retry with a new Idempotency-Key.
invalid_pack (400)
Unknown pack key; the detail lists valid keys.
stripe_error / spt_stripe_error (502)
Stripe rejected or failed the request. No credits were granted; retry later.
spt_not_enabled (501)
Shared payment tokens are not enabled on this server. Omit sharedPaymentToken to get a Checkout URL.
spt_payment_incomplete (402)
The shared-payment-token charge did not complete. No credits were granted.

Notes for agents