chck.ai logo

Partner integration

CHCK Grading API

Grade trading cards from your own site and read back CHCK certificates. Two images in, a certificate number, sub-grades, and an estimated market value out — usually in under a minute.

Basics

  • Base URL https://chck.ai/api/public/v1
  • Format JSON request and response bodies, UTF-8.
  • Versioning the path carries the version. Breaking changes ship as /v2.
  • Rate limit per-key hourly quota (120 requests by default). Over quota returns 429 rate_limited.

Authentication

We issue a key that looks like chck_ab12cd34ef_…. Send it on every request. Keys are shown once at creation — store it as a server-side secret and never ship it to a browser.

header
x-api-key: chck_ab12cd34ef_9f3c…
Errors always come back as { "error": { "code", "message" } } with codes missing_api_key, invalid_api_key, key_revoked, rate_limited, invalid_request, not_found, grading_failed.

Endpoints

post/gradingsSubmit a card for grading
get/gradings/{id}Poll a submission
get/certificates/{number}Look up any live CHCK certificate

Submit a card

Pass each face as a public url or as base64 (max 12MB each). Shoot the raw card — not a slab — with all four edges and a sliver of background visible. Card hints are optional; CHCK identifies the card itself.

request
curl -X POST https://chck.ai/api/public/v1/gradings \
  -H "x-api-key: $CHCK_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "external_ref": "order-1042",
    "front_image": { "url": "https://partner.example.com/1042-front.jpg" },
    "back_image":  { "url": "https://partner.example.com/1042-back.jpg" },
    "card": { "player": "Victor Wembanyama", "year": "2023", "brand": "Prizm" }
  }'
201 response
{
  "grading_id": "6f1b6c62-8a1e-4f0e-9d0b-2b0b8f2f1a11",
  "external_ref": "order-1042",
  "status": "complete",
  "certificate": {
    "certificate_number": "9m69pu",
    "certificate_url": "https://chck.ai/c/9m69pu",
    "issued_at": "2026-08-05T03:12:44.000Z",
    "revoked": false,
    "grade": {
      "overall": 9,
      "centering": 9.5,
      "corners": 9,
      "edges": 9,
      "surface": 9.5,
      "centering_offset": { "horizontal": 55, "vertical": 52 },
      "model_version": "chck-grade-2.5",
      "graded_at": "2026-08-05T03:12:40.000Z"
    },
    "pipeline": {
      "engine": "chck-grade-2.5",
      "graded_by": "CHCK grading engine (chck.ai) — rubric, centering geometry and scoring",
      "vision_provider": "Anthropic Claude — vision inference, integrated by CHCK",
      "hosted_by": "chck.ai"
    },
    "card": {
      "player": "Victor Wembanyama", "year": "2023", "brand": "Prizm",
      "set": "Panini Prizm", "card_number": "136", "variant": null,
      "category": "basketball"
    },
    "estimated_value": {
      "currency": "USD", "low": 180, "mid": 240, "high": 320,
      "confidence": "medium"
    },
    "images": {
      "front": "https://chck.ai/api/public/card-image/9m69pu/front",
      "back":  "https://chck.ai/api/public/card-image/9m69pu/back"
    }
  }
}

The call is synchronous and typically returns in 15–40 seconds — set your HTTP client timeout to at least 90 seconds. If your platform can't hold the request open, rely on the webhook instead and treat a timeout as “in progress”, then poll /gradings/{id}.

422 rejection
{
  "error": { "code": "grading_failed", "message": "This card appears to already be in a graded slab." },
  "grading_id": "6f1b6c62-…",
  "status": "rejected",
  "reason": "holder_detected"
}

Rejection reasons: holder_detected (already slabbed), face_check_failed (missing side, duplicate faces, or front/back mismatch), grading_failed (unreadable images). Rejections are not billed.

Look up a certificate

request
curl https://chck.ai/api/public/v1/certificates/9m69pu \
  -H "x-api-key: $CHCK_API_KEY"

Returns { "certificate": { … } } in the same shape as above, or 404 not_found when the number is unknown or the certificate has been revoked. Use it to render a “Graded by CHCK” badge on your listing pages, and cache the response for up to an hour.

Webhooks

Give us an https:// endpoint and we POST grading.completed or grading.failed as soon as a submission settles. Respond 2xx quickly; do your work asynchronously.

payload
{
  "event": "grading.completed",
  "api_version": "v1",
  "sent_at": "2026-08-05T03:12:44.000Z",
  "external_ref": "order-1042",
  "data": {
    "grading_id": "6f1b6c62-…",
    "status": "complete",
    "certificate": { "certificate_number": "9m69pu", "grade": { "overall": 9 } }
  }
}
Every delivery carries chck-event, chck-timestamp (unix seconds) and chck-signature. Verify before trusting the body.
verify (node)
import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyChckWebhook(rawBody, headers, secret) {
  const ts = headers["chck-timestamp"];
  const sent = String(headers["chck-signature"] || "").replace(/^sha256=/, "");
  // Reject anything older than 5 minutes to stop replays.
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex");
  const a = Buffer.from(expected), b = Buffer.from(sent);
  return a.length === b.length && timingSafeEqual(a, b);
}

End-to-end quickstart

node
const res = await fetch("https://chck.ai/api/public/v1/gradings", {
  method: "POST",
  headers: {
    "x-api-key": process.env.CHCK_API_KEY,
    "content-type": "application/json",
  },
  body: JSON.stringify({
    external_ref: order.id,
    front_image: { url: order.frontImageUrl },
    back_image: { url: order.backImageUrl },
  }),
});

if (res.status === 201) {
  const { certificate } = await res.json();
  await saveGrade(order.id, {
    certNumber: certificate.certificate_number,
    grade: certificate.grade.overall,
    reportUrl: certificate.certificate_url,
  });
} else {
  const { error } = await res.json();
  console.error("CHCK grading failed", error.code, error.message);
}
Import openapi.json into Postman or Insomnia to generate a client and try every endpoint.

Getting a key & support

Email contact@chck.ai with your company, expected monthly volume, and the webhook URL you want registered. We'll send back a key plus a webhook signing secret. Grading volume submitted through the API is invoiced per contract — API submissions do not draw down dashboard credits.