---
name: silph-public-api
description: >-
  SilphCo public TCG API — Midprice/Last quote, set trending-cards, chart-series history.
  Use when you need the same dollars the card page shows, or a tcg_card_id / productId.
---

<!-- Generated by api/scripts/gen_api_docs.py — do not edit by hand. -->

# SilphCo public API (agent getting started)

Base: `https://silphcoanalytics.xyz/api/v3`
Auth: `Authorization: Bearer <key>` from https://silphcoanalytics.xyz/dashboard
Playground (no key): 50 ids, 50-row cap, 1 req/s. Keyed GET: 250 ids. Keyed JSON POST and MCP: 1000 ids.
Cost = unique resolved ids.
Playground keyless responses include `X-LOR-Tier: playground`.
`/sets/{id}/trending-cards` is keyless cached product UI, not playground. The global `/trending` leaderboard is shelved (HTTP 410); use `GET /sets/{id}/trending-cards` for a set's movers.

## MCP (optional)

REST is the primary surface; MCP exposes the same product jobs as typed tool
calls for tool-using agents. Point a Streamable-HTTP client (not legacy SSE;
must send custom headers and follow redirects — bare `/api/v3/mcp` 307s) at
`https://silphcoanalytics.xyz/api/v3/mcp/` with `Authorization: Bearer <key>`
on every request. A free `sk_live_...` dashboard key works; no anonymous MCP —
missing or invalid credentials return `401`. After `initialize`, send the
returned `mcp-session-id` header on subsequent calls (SDK clients handle it).
Public MCP version: **1.1.0**.

Public keys receive exactly these product jobs: `search`, `quote`, `get_prices`, `get_sales`, `get_listings`, `batch_grade_ladder`, `compare_set_finish`, `pin_cohort`, `get_cohort`, `rank_set_sales`.
`execute_sql` is not available. Neither are `describe_schema` or `query_gold_sql`.

Batch first: `quote`, `get_prices`, `get_sales`, `get_listings`,
`batch_grade_ladder`, `compare_set_finish`, `rank_set_sales`, and
`search` (`ids` mode) take `ids` lists — never loop single-id calls.
Always bound `get_prices` with `limit`/`since` — unbounded returns each id's
full series (hundreds of KB). Tool failures return JSON-RPC HTTP 200 with
`result.isError: true` — check `isError`, not the status code. Client config
JSON, Python SDK snippet, and the curl handshake live in
https://silphcoanalytics.xyz/docs/reference/mcp.md

### MCP agent patterns

- **Identity then finish:** `search(q="Nidoking")` → `quote` / `get_listings` /
  `batch_grade_ladder` with `finish=reverse_holo`. Do not put finish in `search.q`.
- **δ-era commons:** `batch_grade_ladder(era=delta_species, rarity=Common,
  finish=reverse_holo)` or `pin_cohort` → `batch_grade_ladder(cohort_handle=…)`.
- **Gem-rate questions:** `batch_grade_ladder` on the cohort (or pin first) —
  no separate gem-rank public tool.

## First call

`42382` is TCGPlayer productId for Base Set Charizard (`base1-4`).

```
GET /api/v3/quote?q=42382
```

`data.status` is identity: `resolved`, `ambiguous`, or `unmapped`.
When resolved, speak `data.label` (**Midprice**, **Last**, or **Ask**) and `data.price_usd` —
always read `data.price_basis` (`midpoint`|`last`|`ask`|`unavailable`) first;
only about 23% of cards resolve to a midpoint. `data.trust` (`ok`|`thin`, midpoint
only) and `data.mark.support` (`{n_asks, n_sales, trust, extrapolated}`) explain how
solid the number is;
`data.as_of` is its freshness date.
`data.kind` is `midprice`, `chart_last`, or `book_ask` — same gate as the card hero:
usable Midprice is status in {ok, thin} and midprice_usd > 0;
inverted / wide / one_sided_* / blended / missing falls back to tape Last, then book Ask.
`GET /quote` is the card quote (`?include=last` for the last sale).
`/oracle_fmv` is retired (HTTP 410); successor is `/quote`, not `include=fmv`.
Do not teach Fair or FMV as a current price.
Per-slot Midprice is `GET /cards/{id}/midprice`.
`include=grade_breakdown` cohorts carry `window_days`/`as_of`.

## Three product jobs (same as the site)

| Job | Path / MCP |
|-----|------------|
| Quote | `GET /quote?q=` / MCP `quote` (`ids` list) — card hero Midprice, Last, or Ask (`?include=last`) |
| Screen | `GET /sets/{id}/trending-cards` — the global `/trending` leaderboard is shelved (410) |
| History | `GET /cards/{id}/chart-series` (`days`, `grades`, `finish`) — REST only |

Δ is open/close on chart-series daily mids, not Midprice vs last sale.

## Batch first

Never loop single-id calls when a list-taking endpoint exists. Cost is unique resolved ids either way (a 40-id batch costs 40) — batching saves round trips, not cost.

| Job | Batch call | Cap |
|-----|-----------|-----|
| Identity (name) | `GET /search` or `GET /quote?q=` (single `q`) | no batch name resolve |
| Core-card rows | experimental multi-id lookup on the matrix — hyphenated `tcg_card_id` only | keyed; not productIds |
| Sales | `GET /sales?ids=` | keyed batch |
| Listings | `GET /listings?ids=` | keyed batch |
| History (exception) | `GET /cards/{id}/chart-series` — single-id only | fan out, cap concurrency ~4 |

Id-batch core-card lookup and price-batch lookup exist too (MCP `search` with `ids`, `get_prices`) — see the API matrix for the underlying experimental routes; don't loop `search`/`quote` one id at a time either way. The core-card POST takes hyphenated `tcg_card_id` only (not TCGPlayer productIds). `missing[]` means no core-card row — quote can still return a price for that id. Empty/unreadable rollup is 503, not all-missing. Curl example: https://silphcoanalytics.xyz/docs/api/getting-started#batch-core-card-lookup

Cohort axes (`grades`, `finish`) on `chart-series`/`/sales`/`/listings` are validated, not best-effort: `grade=`/`grade_key=` are accepted aliases for `grades=`, but an unrecognized value or an unregistered cohort-axis param name (`grade_num=`, `grader=`, `slab_only=`, ...) is `400 invalid_query` — never a silent fall-back to the default cohort (#3842). Every response echoes `meta.cohort.<axis>.resolved_by` (`explicit`/`default`/`none`).

## Research sidecar

| Job | Path |
|-----|------|
| Per-slot Midprice | `GET /cards/{id}/midprice` — `ok`/`thin` slots for a grade/finish |
| Sales | `GET /sales?ids=` (`agg=day`; `include=outliers` raw — lor v1 name: `include_filtered=true`; `since`/`until`) |
| Asks | `GET /listings?ids=` or `set_id=` (`agg=book` optional; default drops `include_in_book=false`; `include=all` raw — lor v1 name: `include_all=true`; `marketplace=`) |
| Catalog dump | `GET /catalog` (`game=pokemon\|onepiece`; `set_id=` ignores game) |

Name → id: `GET /search?q=base+set+charizard`.
Full id list: keyed `GET /catalog` — do not paginate `/search`.
Identity / headline $: `GET /cards/{id}` (digits still resolve as a productId alias; talk in `tcg_card_id`). Multi-id core-card lookup is `tcg_card_id` only.

## Id grammar

| Input | Meaning |
|-------|---------|
| Digits (`42382`) | TCGPlayer productId — quote, collections, `GET /cards/{id}` |
| Hyphenated (`base1-4`, `cel25c-17_A`, `ex10-!`) | our `tcg_card_id` |
| Name mixed into a valid collection batch | skipped — `data.invalid[]` |
| Name-only collection `ids=` | **400** — use `/search` |
| ProductId on the experimental core-card POST | **400 invalid_ids** |

Unmapped productId alone on collections → `400` with `details.invalid`. Mixed collection batches stay 200.
Missing sidecar / empty core-card rollup → `503`. Throughput: https://silphcoanalytics.xyz/docs/api/throughput

`GET /cards/42382` resolves to `base1-4`. Still talk in `tcg_card_id`. Do not send `42382` to the experimental multi-id core-card lookup.

## Do not quote a research ladder

`include=fmv` is gone. `/oracle_fmv` is retired (HTTP 410); successor is `/quote`.
The card quote is `GET /quote` — Midprice, else Last, else Ask.
Per-slot Midprice is `GET /cards/{id}/midprice`.
Grade keys use colons (`PSA:10`).

`GET /cards/{id}` no longer returns bare `nm_price_usd` / `raw_median_price_usd` /
`avg_price_usd` / `top_ungraded_price_usd`, and does not nest them under `data.fmv`.
The hero dollar for a card is `GET /quote` `data.price_usd`, never a `/cards/{id}` scalar.
Portfolio `unit_marks` is holdings MTM, not the quote.

## Do not

- Use `/sales?agg=day` as card history — use `chart-series`
- Call `bundle`, `analytics`, or `price-history` as the product
- Treat `/cards` list as playground (key required)
- Paginate `/search` for a full catalog — use `GET /catalog`
- Rekey gold on `tcgplayer_id`
- Treat a name as an `ids=` token

Docs: https://silphcoanalytics.xyz/docs/api/getting-started
MCP docs: https://silphcoanalytics.xyz/docs/reference/mcp
OpenAPI: https://silphcoanalytics.xyz/openapi-public.json
This skill: https://silphcoanalytics.xyz/skill-api.md
Machine index: https://silphcoanalytics.xyz/llms.txt
