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
- Create an account and sign in at tcg-inventory.com.
- Open Settings → API.
- 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:
- Linked to your scanning machines
- Approved
- 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
| Param | Description |
|---|---|
q | Scryfall fulltext query (required, max 1000 chars) |
unique | cards (default) | prints | art |
order | name, set, released, rarity, color, cmc, power, toughness, artist, usd, eur |
dir | auto | asc | desc |
include_extras | Include tokens/planes/etc. |
page | 1-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)
| Keyword | Meaning |
|---|---|
box:"Name" | Physical box name |
section:"Name" | Section name |
condition:nm (etc.) | Physical condition |
qty>=2 / quantity>=2 | Owned quantity |
is:indeck | In 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