Skip to content
Best Grading Tools
API

Documentation

Everything you need to find cards, process images and build with BGT.

Your first request

  1. Create a project in the console.
  2. Create a sandbox key with pdfs:write and usage:read.
  3. Store the key in your server environment as BGT_API_KEY.
  4. Run this example. It returns a PDF with test data and a test watermark.
cURL
curl --fail --show-error --max-time 180 'https://europe-west1-bestgradingtools-prod.cloudfunctions.net/developerApi/v1/pdfs' \
  -H "Authorization: Bearer $BGT_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: example-document-0001' \
  --data '{"title":"My collection","brand":"My studio","cards":[{"name":"Example card","score":8.5}]}' \
  --output collection.pdf
Success returns a PNG or PDF. Errors return JSON. Check the HTTP status before saving the file.
JavaScript / Node.js
JavaScript
import { writeFile } from 'node:fs/promises';
const response = await fetch('https://europe-west1-bestgradingtools-prod.cloudfunctions.net/developerApi/v1/pdfs', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.BGT_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': 'example-document-0002'
  },
  body: JSON.stringify({ title: 'My collection', cards: [{ name: 'Example card' }] })
});
if (!response.ok) throw new Error(JSON.stringify(await response.json()));
await writeFile('collection.pdf', Buffer.from(await response.arrayBuffer()));
Python
Python
import os, requests
response = requests.post('https://europe-west1-bestgradingtools-prod.cloudfunctions.net/developerApi/v1/pdfs',
    headers={'Authorization': 'Bearer ' + os.environ['BGT_API_KEY'],
             'Idempotency-Key': 'example-document-0003'},
    json={'title': 'My collection', 'cards': [{'name': 'Example card'}]},
    timeout=180)
response.raise_for_status()
with open('collection.pdf', 'wb') as output:
    output.write(response.content)
Integrate with AI

From photos to a report

Follow the complete grading journey, including recapture, recovery and token settlement. Identity and visible condition are separate questions.

Every report starts with your card.

Original photos. Visible evidence. An independent estimate.

Illustrated journey from card photographs through inspection to a report.

Conceptual illustration, not a real report or an internal system diagram.

Computer vision and AI, working together.

BGT combines image measurements, capture checks and AI-assisted evaluation. Focus, exposure and geometry help select useful evidence before analysis.

Capture originals underpin the evaluation. Presentation cutouts and reduced-glare viewer images do not replace that evidence.

Our approach draws on techniques studied in computational photography and image analysis. It is an independent BGT estimate: scientific references do not certify product accuracy.

  1. Capture

    Front and back, with the complete card visible.

    Front
    Back
    Sample artwork. Use your original photos.

    Original photos are the evidence. Catalog artwork cannot replace them.

  2. Prepare & submit

    Review both photos and confirm the evaluation.

    Preparation uses no tokens. An accepted submission reserves 1 G; an identical retry retains the original request.

  3. Evaluate

    Identity and condition answer different questions.

    Which card?
    Identity and printing, when they can be resolved.
    What is visible?
    Visible centering, corners, edges and surface.

    Unresolved identity is not a defect. Reflections and hidden areas limit what can be concluded.

  4. Retrieve

    Follow the status and open the report when available.

    The estimate, observations and limitations remain private. Sharing is a separate action by the owner.

Report completed

The evaluation consumes 1 G. You receive an independent BGT estimate.

1 G consumed

New photos needed

The reservation is refunded. Repeat the requested capture and submit a new evaluation.

1 G returned

Terminal failure

The reservation is refunded. A lost connection alone does not confirm failure: check status first.

1 G returned
Read left to right; on mobile, top to bottom. This is a conceptual service map, not an internal execution sequence. A recapture request returns the flow to the photos.
Read the technical note

Find a card or set.

GET/v1/catalog/cards/searchPublic

Public metadata for Pokémon, Magic, One Piece and Lorcana. No key or subscription is required. Photos stay in the app: these endpoints accept text and identifiers only.

GET
https://api.bestgradingtools.com/v1/catalog/cards/search?game=pokemon&q=Pikachu&locale=en&pageSize=20
GET /v1/catalog/coverage
Available card counts by game and printed language, pending sets and last successful update. Completeness covers registered sets only.
GET /v1/catalog/status
Import history, source URLs, failures and overall coverage.
GET /v1/catalog/sets
Available physical sets, languages, source dates and source status.
GET /v1/catalog/sets/{setId}/cards
Cards in a set. Example: pokemon:base1. Send locale, page and pageSize. Defaults to 20 cards per page.
GET /v1/catalog/cards/search
Search by name or printed number with game and printed card locale. Follow data.nextCursor as the next page. Defaults to 5 results; a one-digit card number is valid.
GET /v1/catalog/cards/{id}
Printing details, source-reported finishes and optional rarity, illustrators and card types. Each attribute group links to its source. Send the same game and locale as the search.

Games: pokemon, magic, one_piece, lorcana. Pages contain up to 20 items, with a maximum of 100 pages. If data.truncated is true, narrow the search or use pageSize=20; a null cursor alone does not imply a complete inventory in that case. Respect the response Cache-Control, HTTP 429 and Retry-After. Limits apply per network address and Cloudflare location.

Coverage depends on the source and printed language. One Piece and Lorcana currently return English records. An empty result or missing finish is not proof that a card or variant does not exist.

Set metadata refreshes monthly and keeps the last validated snapshot if a source fails. Card details come from our stored catalog; searches never trigger a provider request. A missing printing returns CARD_NOT_IMPORTED. Optional attributes appear as imports refresh; missing fields stay absent. Rarity is not a finish or condition. This catalog does not provide market prices or a BGT grade.

Download catalog OpenAPI 3.1 ↓ Integrate with AI

Cut out a card.

POST/v1/cutoutsPNG

Requires cutouts:write. Returns a PNG with real alpha. Send one complete card, with a little space around every edge and a contrasting background. A sleeve, heavy glare or a damaged outline can make segmentation uncertain; inspect results before commercial use.

JSON
{
  "imageBase64": "BASE64_JPEG_PNG_OR_WEBP",
  "bounds": {
    "x": 0.05,
    "y": 0.04,
    "width": 0.9,
    "height": 0.92
  },
  "width": 960,
  "height": 1344
}

bounds is optional. It is a normalized guide in the EXIF-corrected image: x/y/width/height from 0 to 1, entirely inside the image. Do not place it inside the printed artwork. The output keeps the card's aspect ratio within the requested canvas. Width and height: 64–1,600 pixels. No fixed rounding or inward erosion is applied.

In the playground, inspect edges on light or dark backgrounds and zoom to 200%. Choose Use in PDF to add the exact PNG to a front or back photo slot. This prepares your draft; only running the PDF consumes a PDF request.

Integrate with AI

Create a document.

POST/v1/pdfsPDF

Requires pdfs:write. Available in Sandbox and Pro. Returns a custom document using client-supplied data. It does not run an AI analysis or produce a BGT grade. Try the PDF form to add front and back photos, then use its Integrate tab to download the request and copy a Node.js example.

JSON
{
  "title": "Collection record",
  "brand": "Your studio",
  "accent": "#183E63",
  "locale": "en",
  "cards": [
    {
      "name": "Card name",
      "details": "Set · number · language",
      "score": 8.5,
      "frontImageBase64": "OPTIONAL_BASE64_IMAGE",
      "backImageBase64": "OPTIONAL_BASE64_IMAGE"
    }
  ],
  "notes": "Your notes."
}

Up to 12 cards per document, title/brand 100 characters, card name 180, details 300 and notes 1,200. Score is optional, from 0 to 10. Locales: en, es, de. Text in supported writing systems is embedded using local fonts. Unsupported glyphs return an error. Images are optional and embedded as supplied; call the cutout endpoint first if you want transparent images.

Integrate with AI

One grading. One token.

POST/v1/gradingsLive · 1 G

Live grading uses the same BGT wallet and evaluation engine as the app. The project owner pays one G per completed evaluation; recaptures and terminal failures return the reservation. A cutout or PDF subscription is not required. Sandbox keys cannot spend real tokens.

  1. In the console, choose Production and create a key with gradings:write, gradings:read and optionally wallet:read. Accept the grading terms. Existing keys gain no new permissions.
  2. Read GET /v1/gradings/contract for the current product and capture versions. Generate one UUID clientRequestId for the evaluation.
  3. Upload the front and back separately through POST /v1/gradings/photos. Send clientRequestId, side (front or back), revision: 1 and imageBase64. Use opaque JPEG, PNG or WebP up to 4 MB / 12 MP, with the whole card and visible background. Optional normalized bounds describe its outline. The server prepares the two photo captures; no token is reserved yet. Advanced clients can still use /v1/gradings/captures with the complete capture metadata contract.
  4. Submit the selected revisions with POST /v1/gradings. Set Idempotency-Key to the same UUID. Poll the returned statusUrl with the same project’s key, at most once every 15 seconds. Grading and wallet requests share a limit of ten per minute; respect Retry-After.
JSON · grading request
{
  "schemaVersion": "1.0.0",
  "clientRequestId": "b6c6de42-795e-4aca-b4af-519d96e4bf5c",
  "productId": "pokemon-card-grading",
  "productVersion": "VERSION_FROM_CONTRACT",
  "captureManifestVersion": "VERSION_FROM_CONTRACT",
  "locale": "en",
  "captureUploadRevisions": {
    "front_ambient": 1,
    "back_ambient": 1
  }
}
Send both sides, with distinct original photos. Reported bounds and metrics do not override server quality or eligibility checks. BGT results are independent estimates, never an official certification.

GET /v1/wallet returns available and reserved tokens. It cannot choose another user’s wallet. Buy packs of 5, 15 or 40 G in the console when Stripe checkout is enabled, or through Apple in the app. The selected checkout shows the actual price and taxes. Grades do not incur a second media quota charge.

Upload both photos in the web grading workspace to try the same flow without writing a client.

Retry the exact request with the same UUID after a lost connection. A different submission using that UUID returns 409. Read tokenState to distinguish reserved, consumed and refunded. Photos and reports are private account records, unlike the temporary cutout/PDF outputs. Grading terms and retention.

Integrate with AI

Usage and saved results

  • GET /v1/usage requires usage:read and returns the current UTC month, plan, limits and counters for this key's environment.
  • GET /v1/requests/{requestId} retrieves a completed result for the same project and environment, using the original operation's permission.
  • GET /v1/health is public and reports the API version.

Retries without duplicate work

For cutouts and PDFs, every POST needs an Idempotency-Key of 16–128 letters, digits, hyphens or underscores. Keep it with the request in your own system. If a connection drops, repeat the identical body with the same key. Completed work returns the saved result and does not consume another operation.

For these media operations, a different body with the same key returns 409. In-progress requests return 409 with Retry-After. A terminal failed request keeps its failure; correct the input and use a new key. Results are downloadable for 24 hours. A compact request record is retained for a further seven days; never deliberately reuse old idempotency keys.

Errors you can act on

StatusMeaningNext step
400 / 415Invalid input or content typeCheck the schema; send JSON and base64 raster images.
401 / 403Key, permission or plan restrictionCheck expiration, scope and environment.
402Insufficient G or no active media planFor grading, add tokens in the app. For media, check your subscription.
409Processing or idempotency conflictRespect Retry-After; never change the original request body.
410Result expired or removedCreate a new request if you still need the file.
413 / 422File limit or unusable inputReduce size or use a clearer complete card photo.
429Rate or monthly quota exceededWait for the stated reset; no overage is charged.
500 / 503Temporary processing failureRetry the same idempotency key to resolve its status.
JSON
{
  "error": {
    "code": "outline_uncertain",
    "message": "Use one complete card on a contrasting background, with space around every edge."
  },
  "requestId": "…"
}

Private files. Explicit limits.

  • Production keys belong on your server, never in an app binary, public JavaScript, URLs or source control. The playground accepts sandbox keys only and keeps them in memory.
  • Keys expire after 90 days, are stored as hashes and can be revoked. Each project can have up to ten active keys.
  • Test and live use separate keys, counters and result paths. A test subscription never unlocks live access.
  • Request body: 6 MB. Each raster: 5 MB / 12 megapixels. Media inputs accept static JPEG, PNG and WebP; grading accepts upright JPEG only. No remote URLs, SVG, HTML or executable templates.
  • Every authenticated request has a per-minute limit. New cutout/PDF attempts also count against the monthly media request budget; only successful output consumes an operation credit. Grading uses 1 G from your wallet instead of a monthly media credit.
  • Cutout/PDF outputs expire after 24 hours and are deleted by recurring cleanup; their inputs are processed in memory. Grading originals and reports remain private account records until deletion under the account policy. Downloaded copies are your responsibility.
  • Media subscriptions and web token packs use Stripe; token purchases in the app use Apple. Redirects and client claims never credit access or tokens; verified server records do.
  • Availability and segmentation quality have limits. No system can guarantee a perfect mask for every photo or absolute security. Use timeouts, backoff and human review where your workflow needs it.

For private BGT app reports, the app uses its own authenticated API and ownership checks. Developer keys cannot access app-created reports, admin data or another customer's files. Explicit live scopes permit reading this project's API gradings and the owner's wallet, or reserving 1 G for a new evaluation. These permissions require separate consent.