Documentation
Everything you need to find cards, process images and build with BGT.
Your first request
- Create a project in the console.
-
Create a sandbox key with
pdfs:writeandusage:read. - Store the key in your server environment as
BGT_API_KEY. - Run this example. It returns a PDF with test data and a test watermark.
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 JavaScript / Node.js
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
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) 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.
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.
-
Capture
Front and back, with the complete card visible.
Sample artwork. Use your original photos.
Front
Back Original photos are the evidence. Catalog artwork cannot replace them.
-
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.
-
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.
-
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 consumedNew photos needed
The reservation is refunded. Repeat the requested capture and submit a new evaluation.
1 G returnedTerminal failure
The reservation is refunded. A lost connection alone does not confirm failure: check status first.
1 G returnedFind a card or set.
/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.
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. Sendlocale,pageandpageSize. Defaults to 20 cards per page. GET /v1/catalog/cards/search-
Search by name or printed number with
gameand printed cardlocale. Followdata.nextCursoras the nextpage. 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
gameandlocaleas 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.
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.
Cut out a card.
/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.
{
"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 AICreate a document.
/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.
{
"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.
One grading. One token.
/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.
-
In the console, choose Production and create a key with
gradings:write,gradings:readand optionallywallet:read. Accept the grading terms. Existing keys gain no new permissions. -
Read
GET /v1/gradings/contractfor the current product and capture versions. Generate one UUIDclientRequestIdfor the evaluation. -
Upload the front and back separately through
POST /v1/gradings/photos. SendclientRequestId,side(frontorback),revision: 1andimageBase64. Use opaque JPEG, PNG or WebP up to 4 MB / 12 MP, with the whole card and visible background. Optional normalizedboundsdescribe its outline. The server prepares the two photo captures; no token is reserved yet. Advanced clients can still use/v1/gradings/captureswith the complete capture metadata contract. -
Submit the selected revisions with
POST /v1/gradings. SetIdempotency-Keyto the same UUID. Poll the returnedstatusUrlwith the same project’s key, at most once every 15 seconds. Grading and wallet requests share a limit of ten per minute; respectRetry-After.
{
"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
}
} 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.
Usage and saved results
-
GET /v1/usagerequiresusage:readand 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/healthis 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
| Status | Meaning | Next step |
|---|---|---|
| 400 / 415 | Invalid input or content type | Check the schema; send JSON and base64 raster images. |
| 401 / 403 | Key, permission or plan restriction | Check expiration, scope and environment. |
| 402 | Insufficient G or no active media plan | For grading, add tokens in the app. For media, check your subscription. |
| 409 | Processing or idempotency conflict | Respect Retry-After; never change the original request body. |
| 410 | Result expired or removed | Create a new request if you still need the file. |
| 413 / 422 | File limit or unusable input | Reduce size or use a clearer complete card photo. |
| 429 | Rate or monthly quota exceeded | Wait for the stated reset; no overage is charged. |
| 500 / 503 | Temporary processing failure | Retry the same idempotency key to resolve its status. |
{
"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.