Skip to main content

tcgapi

PyPI Python License: MIT

Official Python SDK for tcgapi.dev — a unified pricing API for 89+ trading card games, including:

  • Pokémon TCG (English + Japanese)
  • Magic: The Gathering
  • Yu-Gi-Oh!
  • Lorcana
  • One Piece Card Game
  • Flesh and Blood
  • Star Wars Unlimited
  • Digimon, Dragon Ball Super, Riftbound, Union Arena, Final Fantasy TCG, Weiss Schwarz, Cardfight!! Vanguard, and dozens more.

Real-time market prices, full price history, fuzzy search, bulk lookups, and exports — all from one HTTP API. Sync and async clients, fully typed with Pydantic.

Install

pip install tcgapi

Requires Python 3.9+.

Quickstart

Get a free API key at tcgapi.dev/dashboard (100 requests/day, no credit card).

from tcgapi import TCGApi

tcg = TCGApi(api_key="tcg_live_...")  # or set TCGAPI_KEY env var

# Look up a single card
card = tcg.cards.get(123456)
print(card.data.name)

# Get every printing's current price
prices = tcg.cards.prices(123456)
for p in prices.data:
    print(f"{p.printing}: ${p.market_price}")

If api_key is omitted, the client reads from TCGAPI_KEY.

Examples

Search across every game

results = tcg.search.cards(
    "charizard",
    game="pokemon",
    sort="price_desc",
    per_page=20,
)
for card in results.data:
    print(card.name, card.set_name, card.market_price)

Iterate without pagination boilerplate

for card in tcg.search.iter("lightning", game="magic"):
    # walks meta.has_more automatically — caps at the API's 200/page max
    ...

Browse sets

games = tcg.games.list()
pokemon_sets = tcg.games.sets("pokemon")
surging_sparks = next(
    (s for s in pokemon_sets.data if "Surging Sparks" in s.name), None
)

if surging_sparks:
    cards = tcg.sets.cards(surging_sparks.id, sort="price_desc")
    print(f"{surging_sparks.name}: {cards.meta.total} cards")

Bulk price lookup (Pro+)

# Auto-chunks if you pass more than 500 IDs.
bulk = tcg.bulk.prices([1, 2, 3, ...])  # thousands ok
print(f"Got prices for {len(bulk.data)} card-printings")
# include="ebay" adds each row's eBay summary (1 credit + 1 per card with eBay data)
with_ebay = tcg.bulk.prices([1, 2, 3], include="ebay")

Per-condition prices (Pro+)

# Price floors per (printing, condition) — Near Mint, Lightly Played, etc.
conditions = tcg.cards.conditions(13217, printing="Holofoil")
for row in conditions.data:
    # median_with_shipping is robust to $0.01 junk listings — prefer it when pricing inventory
    print(f"{row.printing} / {row.condition}: ${row.median_with_shipping}")
print(conditions.meta.cached, conditions.meta.condition_counts)

# Bulk variant — up to 500 cards per call, served from the nightly cache.
# Cards without condition data yet are absent; fetch them once via
# tcg.cards.conditions() to warm them.
bulk_conditions = tcg.bulk.conditions([13217, 13218, 13219])

Listing supply (Pro+)

# How much is for sale, from how many sellers, and how much sits near the market price.
supply = tcg.cards.supply(13118)
s = supply.data
share = s.largest_listing.share if s.largest_listing else None
print(f"{s.units} copies from {s.sellers} sellers; largest listing holds {share}")
if s.near_market:
    print(f"{s.near_market.units} copies within 10% of market: {s.near_market_days_of_supply} days of sales")

# One point per read (about every 3 days), oldest first. History starts 2026-10-27.
supply_history = tcg.cards.supply_history(13118, days=90)

# Bulk variant — up to 500 products per call, auto-chunks above that.
# Products with no supply recorded yet are absent.
bulk_supply = tcg.bulk.supply([13118, 13217, 13218])

Top movers

movers = tcg.prices.top_movers(
    game="pokemon",
    direction="up",
    period="7d",
    limit=10,
)
for m in movers.data:
    print(f"{m.name} ({m.set_name}): +{m.price_change}% — ${m.market_price}")

How old is a market price?

Every price row carries market_price_as_of: the UTC date TCGPlayer last reported that printing's market price. It is older than last_updated_at when a printing has stopped selling — the last price is kept and dated rather than dropped.

prices = tcg.cards.prices(123456)
for p in prices.data:
    print(p.printing, p.market_price, "as of", p.market_price_as_of)

Products TCGPlayer no longer prices

When TCGPlayer stops reporting any price for a product (typically out of print with no listings), its rows keep the last prices reported and are no longer refreshed daily. no_market_price_since says since when; it is None while the printing is priced.

prices = tcg.cards.prices(123456)
for p in prices.data:
    if p.no_market_price_since:
        print(p.printing, "unpriced on TCGPlayer since", p.no_market_price_since)

eBay sold prices (Pro+)

include="ebay" adds an ebay field to each printing: the 30-day median eBay sold price for ungraded copies plus a graded dict keyed by grade ("PSA 10", "BGS 9.5", ...), or None when there is no eBay data. include="ebay_sales" also returns the sold listings. Costs 2 credits (meta.credits_consumed); below Pro it raises TierError. ebay.days / ebay.graded_days say how many of the 30 window days the figures cover (30 = complete; lower in a card's first month of eBay tracking). On history rows after the card's latest eBay read, ebay.as_of is that read's date (the row carries its figures).

prices = tcg.cards.prices(123456, include="ebay")
for p in prices.data:
    if p.ebay:
        psa10 = p.ebay.graded.get("PSA 10")
        print(p.printing, p.ebay.median_30d, psa10.median_30d if psa10 else None)

# Daily 30-day eBay median alongside the TCGPlayer history
history = tcg.cards.history(123456, range="year", include="ebay")

Which cards have eBay data: tcg.ebay.coverage() (per game) or tcg.ebay.coverage("pokemon") (per set). Public: no key needed, not counted against quota.

Price history (Hobby+)

# Window scales with your tier: free=7d, hobby=30d, starter=90d, pro/business=full.
history = tcg.cards.history(123456, range="year")
for point in history.data:
    print(point.date, point.market_price)

Async client

The async API mirrors the sync surface verbatim:

import asyncio
from tcgapi import AsyncTCGApi

async def main():
    async with AsyncTCGApi() as tcg:
        resp = await tcg.search.cards("charizard", game="pokemon")
        async for card in tcg.search.iter("dragon", game="magic"):
            print(card.name)

asyncio.run(main())

Identify a card from a photo

identify.photo() reads one photo of a card, slab or sealed product and returns ranked catalog candidates. It uses one scan per photo, separate from your daily request limit: every account gets 25 free scans, then prepaid packs from the dashboard.

from tcgapi import TCGApi

with TCGApi() as tcg:
    result = tcg.identify.photo("card.jpg", include_prices=True)
    if result.data.status == "matched":
        top = result.data.candidates[0]
        print(top.name, top.set.name, top.prices)
    elif result.data.status == "retake":
        print("Retake:", result.data.message)
    print("scans left:", result.meta.scans_remaining)

Accepts raw bytes, a path, or an open binary file. A 402 with code SCAN_BALANCE_EMPTY means the balance is used up. AsyncTCGApi has the same method. include_ebay=True adds the prices with each printing's eBay sold prices (ebay, and on a graded slab ebay.slab_grade for the grade on the label), on every plan at no extra charge.

identify.usage() returns the balance, scans per day for the last 30 days by outcome and the trial and pack purchases. It is free: no scan, no daily quota.

usage = tcg.identify.usage().data
print(usage.balance, usage.days[-1].scans, usage.days[-1].matched)

Rate limits

Every successful response carries the live rate-limit budget:

resp = tcg.games.list()
print(resp.rate_limit)
# RateLimit(daily_limit=10000, daily_remaining=9871, daily_reset='2026-04-29T00:00:00.000Z')

When you exceed the daily limit you'll get a typed RateLimitError:

from tcgapi import RateLimitError

try:
    tcg.cards.get(123)
except RateLimitError as err:
    print(f"Hit the limit — retry in {err.retry_after}s")

Other error classes: AuthError (401), TierError (403), NotFoundError (404), TcgApiError (anything else). All extend Exception.

Tiers

Plan Daily requests History Bulk endpoints Sales velocity
Free 100 7 days — —
Hobby ($9.99/mo) 1,000 30 days — —
Starter ($19.99/mo) 2,500 90 days Limited —
Pro ($49.99/mo) 10,000 Full Yes Yes
Business ($99.99/mo) 50,000 Full Yes Yes

Sales velocity = sales_volume, avg_sales_price, and sales_as_of on price responses (Pro+). The fields are absent below Pro.

Or pay per request via x402 — no signup, USDC on Base or Solana.

API reference

Full endpoint reference: tcgapi.dev/api OpenAPI spec: tcgapi.dev/openapi.yaml Quickstart guide: tcgapi.dev/quickstart

License

MIT

Metadata

Release files for tcgapi 0.12.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tcgapi 0.12.0
File Size Uploaded Provenance Actions
tcgapi-0.12.0.tar.gz 19.5 kB With provenance Details for tcgapi-0.12.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for tcgapi 0.12.0
File Interpreter ABI Platform Actions
tcgapi-0.12.0-py3-none-any.whl Python 3 none any Details for tcgapi-0.12.0-py3-none-any.whl

Total release size: 46.9 kB

Release files / tcgapi-0.12.0.tar.gz

Download URL tcgapi-0.12.0.tar.gz
Size 19.5 kB
Tags Source
SHA-256 checksum
How to use checksums
cae3d602a4a1ee815d886dd549daeb1d82e8e9a0b74da769b561f9f9a6e830ee
BLAKE2b-256 checksum
How to use checksums
33d1ceb95e8a8df9a8d0e4f8869676591c0c38a45218375e0eca171425aa66ef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Release files / tcgapi-0.12.0-py3-none-any.whl

Download URL tcgapi-0.12.0-py3-none-any.whl
Size 27.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a6d5e42357b22be0309d6bfc6eeaa16632f192821b24bd2cc41b46aeed29957c
BLAKE2b-256 checksum
How to use checksums
554a7a8af9e36184f4613bce0d5260519764a5d921424bd5e153990237c9e87c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Security for tcgapi 0.12.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for tcgapi-0.12.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page