What it does

Send a string. Get back a structured card object.

curl -X POST https://x402.agentutility.ai/card-resolve \
  -d '{"card":"2018 Topps Update Juan Soto RC PSA 9"}'
{
  "input": "2018 Topps Update Juan Soto RC PSA 9",
  "canonical": {
    "sport_or_tcg": "sports",
    "year": 2018,
    "set": "Topps Update",
    "player_or_card_name": "Juan Soto",
    "parallel": "RC",
    "grade": 9,
    "grader": "PSA",
    "cert_number": null
  },
  "confidence": 0.95,
  "search_key": "sports:2018:topps-update:juan-soto:rc:psa9"
}

That's it. $0.005 USDC per call, settled on Base. Works on sports cards, Pokemon, Magic, Yu-Gi-Oh — anything with a year + set + name + optional grade.

Why this exists

Agents that browse e-commerce listings see graded-card titles in the wild. Every listing is a different shape. "Pikachu Illustrator PSA 10". "1986 Fleer Michael Jordan #57 SGC 8.5". "MTG Black Lotus Alpha BGS 8.5 cert 8765432". Before you can do anything useful with that string (look up a comp, file it in a portfolio, search eBay, post a buy order), you need it normalized.

So you reach for an LLM. Cool. Now you're writing a 60-line prompt, picking a model, handling retries, parsing the JSON, validating that PSA 11 didn't sneak through. Every agent that touches cards reinvents the same wheel.

card-resolve is that wheel, mounted, balanced, priced per call. The endpoint runs Morpheus hermes-3-llama-3.1-405b as primary with Venice mistral-small as automatic fallback. It enforces field ranges (grade 1-10, year 1800-2099). It returns a search_key that's deterministic — "1986 Topps Bo Jackson RC PSA 9" and "Bo Jackson 1986 Topps rookie PSA 9" both produce sports:1986:topps:bo-jackson:rc:psa9. Use that as a cache key downstream and you get free deduplication.

Why it's shipping as a Wordmint endpoint, not a Comppoint endpoint

Original plan: an 8-endpoint Comppoint cluster covering card resolution, sold-comps, pop reports, liquidity scoring, trends, and a portfolio aggregator.

Research said no.

eBay's 2025 API License Agreement explicitly prohibits commercial redistribution of "market trends, pricing strategies, sales volumes" data. Sold-listings are gated behind the Marketplace Insights API, partner-only. PSA's submission terms assign rights to PSA and grant only a limited revocable license back. Scryfall's terms forbid "requiring payments... in exchange for access to Scryfall data" — a paid per-call proxy is exactly the prohibited pattern. Pokemon TCG API's price fields are TCGplayer-derived and inherit TCGplayer's "no commercial redistribution" clause. TCGplayer's own API is closed.

We carry an ERC-8004 identity on Base (agentId 47167) covering 245 paid endpoints. A single upstream ToS strike could land on the wrong endpoint and spill into the identity. The cost of being wrong is the whole portfolio. So everything that touched a price field got cut.

card-resolve doesn't touch a price field. It's pure LLM extraction — input is the user's text, output is a structured object. Zero upstream data dependencies. No ToS exposure. It ships.

The rest of Comppoint stays spec in our cluster taxonomy. If a partnership lands with PriceCharting or GemRate, or if card-resolve gets enough traffic to justify a paid upstream license, the cluster wakes up. Until then it waits.

Who should call this

  • AI shopping agents that encounter graded-card listings on eBay, Goldin, Heritage, MySlabs
  • Portfolio trackers that ingest user-typed inventory ("I own a 1986 Fleer Jordan PSA 8 and a 1989 Upper Deck Griffey PSA 9")
  • Marketplace listing automations that need to validate seller-supplied titles before posting
  • Card-shop pricing engines that get text from a phone call or chat
  • Anything that takes a free-form card string and needs the structured equivalent

The output you actually get

Eight fields per card. Three are nullable on purpose: parallel is null for base cards, grade and grader are null for raw, cert_number is null when not explicitly stated. confidence runs 0-1; treat anything below 0.5 as worth re-validating. search_key is the cache hint.

Limits: 500 chars in (long enough for any real card string, short enough to keep latency under a second), 0.95-confidence median on a 50-card test set across sports + Pokemon + MTG.

Call it or grep the catalog for the slug.