Skip to main content

valotcg: Python client for Valo.Data

Official Python client for Valo.Data, the ValoTCG trading card price API: catalogue, prices, price history and analysis for 14 TCGs (Pokémon, One Piece, Yu-Gi-Oh!, Magic, Lorcana and more), with Cardmarket, US market and eBay sources.

  • Sync (ValoData) and async (AsyncValoData) clients on httpx
  • Typed pydantic v2 models generated from the OpenAPI document
  • Credits and request id on every response, typed errors, automatic retry on transient rate limits
  • Cursor pagination helpers

Python 3.10 or later.

Install

pip install valotcg
# or
uv add valotcg

API key

Create a free Sandbox key at valotcg.com/developers/account: 500 credits and 250 distinct cards per month, 100 billed requests per day, no credit card. Plans and credit costs: valotcg.com/developers/pricing.

The client reads the key from api_key= or from the VALO_DATA_API_KEY environment variable and sends it as Authorization: Bearer <key>.

export VALO_DATA_API_KEY=vd_test_...

Identify a card, then get its price summary

from valotcg import ValoData

with ValoData() as client:
    found = client.analysis.identify("charizard 4/102", game="pokemon")
    card = found.data.candidates[0].card
    summary = client.analysis.card_summary(card.card_id)
    print(card.name, summary.data.recommended)
    print("credits used:", summary.meta.credits_used, "remaining:", summary.meta.credits_remaining)

Batch prices

Up to 100 ids per call; sealed products are written "sealed:<id>".

batch = client.cards.batch([1234, 5678, "sealed:42"])
for item in batch.data.items:
    if item.status == "ok":
        for quote in item.prices or []:
            print(item.id, quote.source, quote.metric, quote.amount, quote.currency)

Pagination

Search endpoints return one page and a next_cursor. The iterators fetch the next pages lazily (each page is a billed request, stop iterating to stop fetching):

for card in client.cards.iter_search("pokemon", q="pikachu", language="fr"):
    print(card.card_id, card.name)

# Any paginated method, sync or async:
from valotcg import apaginate, paginate

for edition in paginate(client.editions.list, "onepiece"):
    print(edition.name)

Available iterators: cards.iter_search, sealed.iter_search, editions.iter_list.

Async

import asyncio
from valotcg import AsyncValoData


async def main() -> None:
    async with AsyncValoData() as client:
        movers = await client.analysis.top_movers("pokemon", period=7, direction="up")
        for mover in movers.data.items:
            print(mover)
        async for card in client.cards.iter_search("lorcana", q="elsa"):
            print(card.name)


asyncio.run(main())

Responses

Every method returns a Response[T]:

  • response.data: the typed model (valotcg.models)
  • response.meta: credits_used, credits_remaining, request_id (headers X-Credits-Used, X-Credits-Remaining, X-Request-Id), plus rate_limit_limit, rate_limit_remaining, rate_limit_reset, status_code and raw headers
  • shortcuts: response.credits_used, response.credits_remaining, response.request_id, and attribute access falls through to .data (response.candidates is response.data.candidates)

Free routes (games.list, games.rarities, usage) may return no credit headers; the fields are then None.

Routes

Method HTTP route
client.games.list() GET /data/v1/games
client.games.rarities(game) GET /data/v1/games/{game}/rarities
client.editions.list(game, q=, language=, cursor=, page_size=) GET /data/v1/editions
client.cards.search(game, q=, edition_id=, language=, rarity=, cursor=, page_size=) GET /data/v1/cards
client.cards.get(card_id) GET /data/v1/cards/{card_id}
client.cards.prices(card_id, include=) GET /data/v1/cards/{card_id}/prices
client.cards.batch(ids, include=) POST /data/v1/cards/batch
client.cards.price_history(card_id, source=, variant=, from_=, to=, market_language=, condition=) GET /data/v1/cards/{card_id}/price-history
client.sealed.search(game, q=, edition_id=, product_type=, language=, cursor=, page_size=) GET /data/v1/sealed
client.sealed.get(sealed_id) GET /data/v1/sealed/{sealed_id}
client.sealed.prices(sealed_id) GET /data/v1/sealed/{sealed_id}/prices
client.sealed.price_history(sealed_id, source=, from_=, to=) GET /data/v1/sealed/{sealed_id}/price-history
client.analysis.identify(q, game=, language=) GET /data/v1/analysis/identify
client.analysis.card_summary(card_id, include=) GET /data/v1/analysis/cards/{card_id}/summary
client.analysis.sealed_summary(sealed_id) GET /data/v1/analysis/sealed/{sealed_id}/summary
client.analysis.compare(ids, include=) POST /data/v1/analysis/compare
client.analysis.top_movers(game, period=, direction=, edition_id=, language=, limit=, reliable=) GET /data/v1/analysis/top-movers
client.analysis.top_priced(game, kind=, language=, edition_id=, product_type=, limit=) GET /data/v1/analysis/top-priced
client.analysis.edition_overview(edition_id) GET /data/v1/analysis/editions/{edition_id}/overview
client.usage(product=) GET /developer/v1/usage

from_ maps to the from query parameter. include accepts a list (["graded", "population"]) or a comma separated string. Price sources are cardmarket, us_market and ebay.

Errors

Error bodies {"error": {"code", "message", "request_id", "docs_url"}} raise typed exceptions, all subclasses of valotcg.ValoDataError with status_code, code, message, request_id and docs_url:

Exception Status Example codes
AuthenticationError 401 invalid_api_key, api_key_expired
PermissionDeniedError 403 insufficient_scope, plan_feature_unavailable, ip_not_allowed
NotFoundError 404 card_not_found, sealed_not_found, edition_not_found
ValidationError 400, 422 invalid_request, invalid_cursor, range_exceeds_plan
RateLimitError 429 rate_limited, quota_exceeded, daily_limit_reached, catalog_limit_reached
ServerError 5xx quota_unavailable
APIConnectionError none network failure or timeout

RateLimitError also carries retry_after (seconds, from Retry-After) and resets_at (when a credit limit resets). valotcg.ValidationError is distinct from pydantic.ValidationError.

from valotcg import NotFoundError, RateLimitError

try:
    client.cards.get(999999999)
except NotFoundError as exc:
    print(exc.code, exc.request_id)
except RateLimitError as exc:
    print(exc.code, exc.resets_at)

Retries

A 429 with code rate_limited (or concurrency_limited) is retried after Retry-After seconds (capped at 60), up to max_retries times (default 2). Credit limits (quota_exceeded, daily_limit_reached, catalog_limit_reached, key_credit_cap_reached) are never retried. Disable retries with ValoData(max_retries=0).

Configuration

ValoData(
    api_key=None,  # default: VALO_DATA_API_KEY
    base_url=None,  # default: VALO_DATA_BASE_URL or https://api.valotcg.com
    timeout=30.0,  # seconds, or an httpx.Timeout
    max_retries=2,
    http_client=None,  # your own httpx.Client (AsyncValoData: httpx.AsyncClient)
)

Attribution

The terms of use require an attribution wherever the data is shown: "Data: ValoTCG".

Contributing

See CONTRIBUTING.md, including how to regenerate the models from the OpenAPI document.

License

MIT, see LICENSE.

Metadata

Release files for valotcg 1.0.1

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

Source distribution (sdist)

Source distribution for valotcg 1.0.1
File Size Uploaded Provenance Actions
valotcg-1.0.1.tar.gz 45.3 kB With provenance Details for valotcg-1.0.1.tar.gz

Built distribution (wheel)

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

Total release size: 69.0 kB

Release files / valotcg-1.0.1.tar.gz

Download URL valotcg-1.0.1.tar.gz
Size 45.3 kB
Tags Source
SHA-256 checksum
How to use checksums
23ebd1955725fc6250b7817d54ab33770190b5e761bb016b0cc9a3f580b92ed3
BLAKE2b-256 checksum
How to use checksums
b024abc4fc362e6618b3b605934eb529b06047ece13e5b22bb50914e5ce1ecae
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 Nov 7, 2026.

Transparency log

Release files / valotcg-1.0.1-py3-none-any.whl

Download URL valotcg-1.0.1-py3-none-any.whl
Size 23.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
afb7f71836fe7a7a78d79e1b96b2a68a8d136eb232dc81dc5ef25f1b78384c31
BLAKE2b-256 checksum
How to use checksums
5e29637297dae4fc6c87cf3c32ad5f4cba321446c350853825aa9891b05a519d
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 Nov 7, 2026.

Transparency log

Security for valotcg 1.0.1

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 valotcg-1.0.1.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 Nov 7, 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.

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files Full provenance

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