Skip to main content

Bot Collection API

:::note Power-user feature This page documents an optional integration API for bots and scripts. You do not need it for normal scanning and collection management in the app. :::

Token-protected REST API that exposes your Magic: The Gathering collection using Scryfall-style search syntax and response shapes.

Base path: https://www.tcg-inventory.com/api/v1/mtg

Getting a token

  1. Create an account and sign in at tcg-inventory.com.
  2. Open Settings → API.
  3. Generate a Bot API Token.

Use it on every request:

Authorization: Bearer cbtk_live_…
  • One active token per user
  • Rotate or revoke anytime from Settings
  • The plaintext token is shown only once when you generate or rotate it

Collection scope

Results only include cards that are:

  1. Linked to your scanning machines
  2. Approved
  3. Filed in a box section (not left unassigned)

Unapproved or unfiled cards will not appear in API results.

Endpoints

GET /api/v1/mtg/cards/search

ParamDescription
qScryfall fulltext query (required, max 1000 chars)
uniquecards (default) | prints | art
ordername, set, released, rarity, color, cmc, power, toughness, artist, usd, eur
dirauto | asc | desc
include_extrasInclude tokens/planes/etc.
page1-based page (175 cards per page)

Empty results return HTTP 404 with a Scryfall-style error object (same as Scryfall).

To list every owned printing (not collapsed by oracle identity), use unique=prints and follow next_page until has_more is false.

curl -H "Authorization: Bearer $TOKEN" \
"https://www.tcg-inventory.com/api/v1/mtg/cards/search?q=c%3Ar+t%3Acreature&unique=prints"

GET /api/v1/mtg/cards/named

  • exact= — exact name match (case-insensitive)
  • fuzzy= — exact → prefix → contains fallback

GET /api/v1/mtg/cards/autocomplete?q=

Returns { "object": "catalog", "data": ["…"] } (up to 20 owned names).

GET /api/v1/mtg/cards/random?q=

One random owned card (optional filter).

POST /api/v1/mtg/cards/collection

Body: { "identifiers": [ { "id" }, { "name" }, { "set", "collector_number" } ] } (max 75).

Response includes not_found for misses.

GET /api/v1/mtg/cards/:id

Internal id or Scryfall UUID.

GET /api/v1/mtg/cards/:set/:number(/:lang)

Set code + collector number (+ optional language).

Response shape

Successful search responses look like Scryfall lists:

{
"object": "list",
"total_cards": 12111,
"has_more": true,
"next_page": "https://www.tcg-inventory.com/api/v1/mtg/cards/search?q=…&page=2",
"data": [ /* card objects */ ]
}

Each card uses Scryfall field names (oracle_id, mana_cost, type_line, image_uris, prices, …). Unsupported fields are omitted or null (never fabricated).

Collection extension

Each card may also include inventory metadata:

"collection": {
"quantity": 3,
"conditions": [{ "condition": "NEAR_MINT", "quantity": 2 }],
"foil_quantity": 1,
"nonfoil_quantity": 2,
"locations": [{ "box": "Binder 1", "section": "Rares" }],
"scanned_card_ids": ["…"]
}

prices.usd maps to TCGPlayer market; prices.eur to Cardmarket trend; tix is always null.

Errors

{
"object": "error",
"code": "not_found",
"status": 404,
"details": "…"
}

Common codes: unauthorized (401), rate_limit (429), bad_request (400), not_found (404), unrecognized_keyword (404), invalid_query (400).

Rate-limit headers (when enforced): X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and Retry-After on 429. Default limit is 60 requests per minute per token.

Scryfall syntax support

Fully supported (Tier 1)

Colors / identity (c:, id: + nicknames), types (t:), oracle text (o:, fo: ≈ oracle), keywords (kw:), mana (m:, mv:/cmc:), power/toughness/loyalty, layouts (is:split|flip|transform|mdfc|…), rarity, sets (e:/s:), collector number (cn:), set type (st:), format legality (f:, banned:, restricted:), artist / flavor, print flags (is:foil, is:reprint, …), frame, year/date, name / exact !, OR / parentheses / negation, order / unique / include:extras, usd / eur comparisons.

Partial (Tier 2)

is:hybrid / is:phyrexian / devotion: (from mana cost text), produces: (oracle heuristics), commander-like is: flags, vanilla/bear/land nicknames (heuristics).

Unsupported (Tier 3) — returns unrecognized_keyword

cube:, Tagger (art:/otag:), edhrec/penny ranks, watermark:, border:, stamp:, game:/in:, tix, new:*, print/set counts, Universes Beyond flags, etc.

Collection extensions (beyond Scryfall)

KeywordMeaning
box:"Name"Physical box name
section:"Name"Section name
condition:nm (etc.)Physical condition
qty>=2 / quantity>=2Owned quantity
is:indeckIn a DECK-kind box

These may only appear at the top level with implicit AND (not inside OR / parentheses).

Example queries

c:rg t:creature
id<=esper t:instant
o:draw t:creature
pow>=8
e:war is:booster
f:pauper c:g
-fire c:r t:instant
t:legendary (t:goblin or t:elf)
!"Lightning Bolt" unique:prints
box:"Main" condition:nm c:u
cmc>=0 unique:prints