Docs
Transaction-level trading card sales data, updated continuously. Access via REST endpoints and an MCP server with 7 AI analysis tools.
Quickstart
Quickstart
Get your first response in under a minute.
1. Get a free API key
Sign up at thecardapi.com → No credit card required. Your key arrives instantly.
2. Make your first request
curl "https://thecardapi.com/api/v1/market/sales?q=psa+10+ohtani&limit=5" \
-H "x-market-api-key: tca_your_key_here"3. Explore
Use the playground to build and test queries interactively before writing any code. The full parameter reference is in the GET /sales section below.
Authentication
Authentication
All requests require an x-market-api-key header (REST) or an Authorization: Bearer header (MCP). The same key works for both. Get one free — no credit card required.
# REST API
GET /api/v1/market/sales
x-market-api-key: tca_your_key_here
# MCP Server
POST /api/mcp
Authorization: Bearer tca_your_key_hereDon't have a key? Get one free →
Base
Base URL
REST API
https://thecardapi.com/api/v1/marketAll REST paths below are relative to this base.
MCP Server
https://www.thecardapi.com/api/mcpJSON-RPC 2.0 over streamable HTTP. See the MCP Server section.
Endpoints
Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /sales | Search and filter sales records |
| GET | /sales/{id} | Single sale by ID |
| GET | /daily | Aggregate stats for a date |
| GET | /platforms | Platform list with last updated date |
| GET | /coverage | Latest data freshness status |
| GET | /sales/export/csv | Download filtered sales as CSV |
| POST | /webhook | Add a webhook endpoint (max 5) — available on all paid plans |
| GET | /webhook | List active webhook endpoints |
| DELETE | /webhook/{endpoint_id} | Remove a webhook endpoint |
MCP tools are invoked via POST /api/mcp — see the MCP Tools section for individual tool references.
GET
GET /sales
Search and filter individual sale records. Results are ordered by date descending by default. Your plan's lookback window is enforced on date_from automatically.
| Parameter | Type | Description | |
|---|---|---|---|
| q | string | optional | Full-text search on listing title (min 4 chars). Supports boolean syntax: (term1,term2) for OR, -term for NOT, "exact phrase" for phrase match. |
| platform | string | optional | Filter by platform. Values: ebay · goldin. See GET /platforms for the full list. |
| listing_type | string | optional | Comma-separated: auction, fixed_price, best_offer |
| date_from | date | optional | Start date YYYY-MM-DD. Clamped to your plan's lookback window. |
| date_to | date | optional | End date YYYY-MM-DD |
| price_min | number | optional | Minimum sale price (USD) |
| price_max | number | optional | Maximum sale price (USD) |
| print_run_min | integer | optional | Minimum print run (e.g. 1 for 1/1 only) |
| print_run_max | integer | optional | Maximum print run (e.g. 99 to filter to /99 and lower numbered cards) |
| shipping_max | number | optional | Maximum buyer shipping cost in USD. Use shipping_max=0 for free-shipping listings only. Filters to records where shipping_price ≤ this value (null shipping_price records are excluded). |
| category | string | optional | Filter by card category: sports, tcg, non_sport. eBay records indexed from June 6, 2026 onward. Auction house sources (Goldin, REA, etc.) return null until backfilled. |
| sort | string | optional | date_desc (default) | date_asc | price_desc | price_asc |
| page | integer | optional | Page number (default: 1) |
| limit | integer | optional | Results per request (default: 25, max: 1,000). Same cap on all plans. |
| cursor | string | optional | Opaque cursor from a previous response's next_cursor field. Efficiently paginate large result sets without offset drift. When provided, page is ignored. Available on all plans. |
| indexed_after | datetime | optional | ISO 8601 UTC. Return only records indexed after this time. Useful for incremental sync. |
Cursor pagination
Every response includes a next_cursor field in pagination when more results exist. Pass it as ?cursor= on the next request to fetch the next page — no offset drift, no missed records. Available on all plans.
# Page 1 — no cursor needed GET /v1/market/sales?q=psa+10+trout&limit=1000 → pagination.next_cursor: "eyJwZ19pZCI6IDE4N..." # Page 2 — pass the cursor GET /v1/market/sales?q=psa+10+trout&limit=1000&cursor=eyJwZ19pZCI6IDE4N... → pagination.next_cursor: "eyJwZ19pZCI6IDE2N..." # or null if last page
CSV export
Download a filtered result set as a CSV file. Same filter params as GET /sales — no cursor or page. Available on Starter and above.
CSV rows count against your shared daily budget — the same pool as API calls. A Builder user who pulls 30K rows via the API has 20K remaining, usable via API or CSV.
curl "https://thecardapi.com/api/v1/market/sales/export/csv?q=psa+10+ohtani&date_from=2026-01-01" \ -H "x-market-api-key: tca_your_key_here" \ -o sales.csv
Search syntax
(psa,bgs) — title contains "psa" OR "bgs"-reprint — title does NOT contain "reprint"-(lot,album) — title contains neither "lot" nor "album""topps chrome" — exact phrase matchohtani (psa,bgs) -(lot,album) -reprint — combine all formsResponse
Response schema
{
"data": [
{
"id": "137222685761",
"platform": "eBay",
"listing_type": "auction",
"title": "2021 Bowman Chrome Kyle Harrison Auto PSA 10",
"sale_date": "2026-05-14",
"sold_at": "2026-05-14T00:00:00Z",
"price": 47.50,
"currency": "USD",
"price_confirmed": true,
"bids": 12,
"image_url": "https://i.ebayimg.com/...",
"thumbnail_url": "https://i.ebayimg.com/...",
"listing_url": "https://www.ebay.com/itm/137222685761",
"cert": "93265128",
"condition": null,
"grade": "10",
"grader": "PSA",
"grading_company": "Professional Sports Authenticator",
"has_autograph_grade": false,
"has_grade_qualifier": false,
"label": null,
"grade_qualifier": null,
"autograph_grade": null,
"player": "Kyle Harrison",
"manufacturer": "Bowman",
"card_set": "2021 Bowman Chrome",
"card_number": "BCP-42",
"year": 2021,
"season": "2021",
"league": "Major League (MLB)",
"sport": "Baseball",
"team": "San Francisco Giants",
"features": ["Auto", "Rookie"],
"print_run": null,
"shipping_price": 4.99,
"category": "sports"
}
],
"pagination": {
"total": 258817,
"page": 1,
"limit": 25,
"pages": 10353,
"has_more": true,
"next_cursor": "eyJwZ19pZCI6IDE4NzUwMDAwLCAic29ydCI6ICJkYXRlX2Rlc2MifQ=="
},
"meta": {
"coverage_date_from": "2026-05-01",
"coverage_date_to": "2026-05-17",
"platforms_covered": ["eBay", "Goldin", "Lelands", "SCP Auctions", "Hakes", "REA"],
"generated_at": "2026-05-17T10:00:00Z"
}
}| Field | Type | Coverage | Description |
|---|---|---|---|
| id | string | 100% | Unique sale identifier (platform-prefixed) |
| platform | string | 100% | Platform name. Values: eBay · Goldin · Lelands · SCP Auctions · Hakes · REA |
| listing_type | string | 100% | auction · fixed_price · best_offer |
| title | string | 100% | Raw listing title |
| sale_date | string | 100% | YYYY-MM-DD of the sale |
| sold_at | string | 100% | ISO 8601 timestamp (UTC). Day-boundary precision: ends in T00:00:00Z unless exact time was captured. |
| price | number | 100% | Final sale price in USD. For eBay: all-in buyer price. For Goldin: hammer price only — buyer also pays ~22% buyer's premium on top. For best_offer: the true negotiated price. |
| currency | string | 100% | Always USD |
| price_confirmed | boolean | 100% | true = confirmed final price. false = fast-settle estimate (auction BIN/BO, updated to true within minutes once confirmed). |
| bids | integer|null | ~60% | Number of bids (auction only) |
| image_url | string|null | ~85% | Full-size listing image URL |
| thumbnail_url | string|null | ~85% | Thumbnail image URL |
| listing_url | string|null | ~99% | Direct link to the sold listing on eBay (or other marketplace). Note: eBay may redirect logged-in users to a product catalog page. To view the original sold listing, open the URL in an Incognito/Private browsing window. This redirect does not affect programmatic/API access. |
| cert | string|null | ~12% | Grading certificate number |
| condition | string|null | ~8% | Raw condition string from listing |
| grade | string|null | ~12% | Numeric grade (e.g. "10", "9.5", "Auth") |
| grader | string|null | ~12% | Grader abbreviation: PSA · BGS · CGC · SGC |
| grading_company | string|null | ~12% | Full grading company name |
| has_autograph_grade | boolean|null | ~12% | Whether the slab has a separate auto grade |
| has_grade_qualifier | boolean|null | ~12% | Whether the grade has a qualifier (e.g. OC, MK) |
| grade_qualifier | string|null | ~3% | Qualifier type (e.g. "OC", "MK", "ST") |
| label | string|null | ~10% | Grading label variant (e.g. "Gold Label") |
| autograph_grade | string|null | ~4% | Autograph sub-grade where graded separately |
| player | string|null | ~0.3% | Player name. Populated for catalog-matched records. null if not yet matched. |
| manufacturer | string|null | ~0.4% | Card manufacturer (e.g. Topps, Panini, Bowman). Populated for catalog-matched records. |
| card_set | string|null | ~0.4% | Set name (e.g. 2022 Topps Update Series). Populated for catalog-matched records. |
| card_number | string|null | ~0.4% | Set card number (e.g. #295 or BCP-42). Distinct from print run (/299). |
| year | integer|null | ~0.3% | Card year. Populated for catalog-matched records. |
| season | string|null | ~0.3% | Sports season (e.g. 2024-25). Populated for catalog-matched records. |
| league | string|null | ~0.3% | League name (e.g. Major League (MLB), National Basketball Association (NBA)). |
| sport | string|null | ~0.4% | Sport (e.g. Baseball, Basketball, Hockey). Populated for catalog-matched records. |
| team | string|null | ~0.3% | Team name at time of card printing. Populated for catalog-matched records. |
| features | string[] | ~0.3% | Array of card features extracted from listing (e.g. ["Auto", "Rookie", "Patch"]). Empty array if not populated. |
| print_run | integer|null | ~36% | Print run (denominator of serial fraction). /99 → 99. /10 → 10. 1/1 → 1. Null for unlisted base cards. Filter with print_run_min / print_run_max. |
| shipping_price | number|null | ~67% | Buyer shipping cost in USD. 0.00 = free shipping. Null when not provided by the seller (eBay NRT only — always null for other sources). Filter with shipping_max. |
| category | string|null | ~99%* | Card category. Values: sports · tcg · non_sport. eBay records indexed June 6, 2026+. Auction house sources return null until backfilled. Filter with ?category=sports. (*eBay Jun 6, 2026+ only) |
listing_type: "best_offer" — the pricefield is the true final negotiated price, not the listing price. Most data providers don't expose this. We do.platform: "goldin" records, price is the hammer price— what the auctioneer called at close. The buyer also pays a buyer's premium (~22% current, ~20% pre-2022) on top. eBay prices are all-in. Factor this in when comparing values across platforms.Error
Error codes
| Status | Meaning |
|---|---|
| 401 | Invalid or missing API key |
| 403 | Action requires a higher plan or beta access |
| 404 | Resource not found |
| 422 | Validation error — check parameter types and ranges |
| 429 | Daily sales limit reached. Resets at midnight UTC. Upgrade for more. |
| 500 | Server error — try again shortly |
Webhooks
Webhooks
$9/mo add-on · Available on all paid plans · 7-day free trial. Get started →
Register up to 5 HTTPS endpoints and receive every new card sale pushed to them within seconds of indexing — no polling required. Sales are delivered as signed batches of up to 1,000 records. Your cursor advances on each successful delivery so you never miss a record and never receive the same one twice. NRT data (near-real-time eBay results) is not included — that is a separate Custom plan add-on.
Add an endpoint
POST /api/v1/market/webhook
x-market-api-key: tca_your_key_here
Content-Type: application/json
{
"url": "https://your-server.com/webhook",
"secret": "your-hmac-signing-secret",
"label": "prod-receiver"
}Max 5 active endpoints per key. label is optional.
List endpoints
GET /api/v1/market/webhook
x-market-api-key: tca_your_key_here{
"endpoints": [
{ "id": 1, "url": "https://your-server.com/webhook", "label": "prod-receiver", "created_at": "2026-06-20T10:00:00Z" },
{ "id": 2, "url": "https://your-server.com/backup", "label": "backup", "created_at": "2026-06-20T10:01:00Z" }
],
"count": 2,
"max": 5
}Remove an endpoint
DELETE /api/v1/market/webhook/{endpoint_id}
x-market-api-key: tca_your_key_hereDelivery payload
Each POST to your endpoint contains a batch of sale records — the same schema as GET /v1/market/sales.
POST https://your-endpoint.com/webhook
Content-Type: application/json
X-Webhook-Signature: sha256=<hmac-sha256>
{
"event": "sales.batch",
"timestamp": "2026-06-20T06:09:00Z",
"count": 47,
"data": [
{
"id": "ebay-387214905012",
"title": "2011 Topps Update Mike Trout RC BGS 9.5",
"price": 4200.00,
"listing_type": "auction",
"sold_at": "2026-06-20T06:00:24Z",
"print_run": null,
...
}
]
}Verify the signature
Every delivery includes X-Webhook-Signature: sha256=<hex>. Verify against the raw request body before processing.
import hashlib, hmac
def verify_webhook(body: bytes, secret: str, sig_header: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, sig_header)| Detail | Value |
|---|---|
| Price | $9/mo add-on · 7-day free trial · Available on all paid plans |
| Max endpoints | 5 active endpoints per API key |
| Delivery latency | ~30s from indexing (auction close → indexed → delivered) |
| Batch size | Up to 1,000 records per delivery |
| Retry policy | 3 attempts with backoff (0s / 5s / 30s). Cursor holds on all-fail. |
| Poll cadence | Every 30 seconds |
| Signature | HMAC-SHA256 — X-Webhook-Signature: sha256=<hex> |
| Event type | sales.batch |
| NRT data | Not included — NRT is a separate Custom plan add-on |
Rate
Rate limits
The only enforced limits are sales rows returned per day and how far back you can query.
| Plan | Sales/day | Lookback |
|---|---|---|
| Free | 5,000 | 3 days |
| Starter | 10,000 | 14 days |
| Builder | 50,000 | 30 days |
| Pro | 200,000 | 90 days |
| Enterprise | Custom | Unlimited |
Daily counters reset at 00:00:00 UTC each day. API calls and CSV exports draw from the same shared budget — a Builder user who downloads 30K rows via CSV has 20K remaining for API calls that day.
Max limit is 1,000 rows per request on all plans. View full pricing →
Pro add-ons
sale_date = yesterday. Your normal daily cap still applies to all other date ranges.Both add-ons require an active Pro subscription. See add-ons →
Every response from /v1/market/sales includes rate limit headers so you can track usage programmatically:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Your plan's daily sales cap |
| X-RateLimit-Remaining | Sales rows remaining today |
| X-RateLimit-Reset | Unix timestamp of next reset (00:00:00 UTC) |
MCP
MCP Server
The MCP (Model Context Protocol) server exposes 7 analysis tools over a single streamable HTTP endpoint. Any MCP-compatible client — Claude Desktop, Claude Code, Cursor, Windsurf, ChatGPT Desktop, LangChain — can connect with one URL.
Endpoint
Protocol: JSON-RPC 2.0 · Transport: streamable HTTP
Discover available tools
{
"jsonrpc": "2.0",
"id": "1",
"method": "tools/list"
}Claude Desktop
{
"mcpServers": {
"thecardapi": {
"command": "npx",
"args": ["mcp-remote", "https://www.thecardapi.com/api/mcp",
"--header", "Authorization: Bearer YOUR_API_KEY"]
}
}
}Claude Code
claude mcp add thecardapi \
--transport http \
--url https://www.thecardapi.com/api/mcp \
--header "Authorization: Bearer YOUR_API_KEY"Cursor / Windsurf
{
"mcpServers": {
"thecardapi": {
"url": "https://www.thecardapi.com/api/mcp",
"headers": { "Authorization": "Bearer YOUR_API_KEY" }
}
}
}See the full MCP integration guide → for all clients.
MCP
MCP Tools
Each tool is called via method: "tools/call" with a name and arguments object.
Find recent sold prices for any card. Returns individual sale records sorted by date. Supports filtering by grader, grade, listing type, date range, and price range.
Parameters
| query | string | optional | Full-text search — e.g. 'PSA 10 Luka Doncic 2018 Prizm Silver' |
| platform | string | optional | Filter by platform (e.g. ebay) |
| grader | string | optional | psa | cgc | beckett | sgc |
| grade | string | optional | 10 | 9.5 | 9 | 8.5 | 8 | 7 | auth | 10pristine |
| listing_type | string | optional | Auction | FixedPrice | BestOffer |
| date_from | string | optional | Start date YYYY-MM-DD |
| date_to | string | optional | End date YYYY-MM-DD |
| price_min | number | optional | Minimum sale price |
| price_max | number | optional | Maximum sale price |
| limit | integer | optional | Results to return (1–20, default: 10) |
Example call
{
"jsonrpc": "2.0", "id": "1",
"method": "tools/call",
"params": {
"name": "search_cards",
"arguments": {
"query": "PSA 10 Luka Doncic 2018 Prizm Silver",
"listing_type": "BestOffer",
"limit": 10
}
}
}Response (abbreviated)
{
"total_returned": 10,
"results": [
{
"id": "ebay-137222685761",
"title": "2018 Panini Prizm Silver Luka Doncic PSA 10",
"platform": "eBay",
"listing_type": "BestOffer",
"price": 4800.00,
"sale_date": "2026-05-16",
"sold_at": "2026-05-16T14:23:00Z",
"bids": null,
"grader": "PSA",
"grade": "10",
"slab_serial": "84566824",
"listing_url": "https://www.ebay.com/itm/137222685761"
}
],
"note": "BestOffer prices reflect the true final negotiated amount, not the list price."
}See exactly how PSA/BGS grade affects price for a specific card. Returns a full price ladder sorted grade-high to grade-low, plus the grade where the value jump is sharpest.
Parameters
| query | string | required | Card to analyze — e.g. 'Luka Doncic 2018 Prizm Silver' |
| grader | string | optional | psa (default) | cgc | beckett | sgc |
| lookback_days | integer | optional | Days of history to include (default: 90) |
Example call
{
"jsonrpc": "2.0", "id": "1",
"method": "tools/call",
"params": {
"name": "grade_impact_analysis",
"arguments": {
"query": "Luka Doncic 2018 Prizm Silver",
"grader": "psa",
"lookback_days": 90
}
}
}Response (abbreviated)
{
"query": "Luka Doncic 2018 Prizm Silver",
"grader": "PSA",
"lookback_days": 90,
"total_sales": 49,
"price_ladder": [
{ "grade": "10", "sales": 6, "avg_price": 9200, "median_price": 8750, "min_price": 7800, "max_price": 11200 },
{ "grade": "9", "sales": 28, "avg_price": 3400, "median_price": 3250, "min_price": 2800, "max_price": 4100 },
{ "grade": "8", "sales": 12, "avg_price": 1950, "median_price": 1875, "min_price": 1600, "max_price": 2300 },
{ "grade": "7", "sales": 3, "avg_price": 850, "median_price": 820, "min_price": 750, "max_price": 980 }
],
"best_value_grade": {
"grade": "9",
"reason": "Stepping up to 10 costs 171% more — this is the steepest value jump in the price ladder."
}
}PSA vs CGC vs SGC vs BGS for the same card at the same grade. Find which grader commands the highest market premium.
Parameters
| query | string | required | Card to compare — e.g. 'Wembanyama 2023 Prizm Silver' |
| grade | string | required | Grade to compare across graders — e.g. 10 | 9.5 | 9 | 8.5 | 8 |
| lookback_days | integer | optional | Days of history (default: 90) |
Example call
{
"jsonrpc": "2.0", "id": "1",
"method": "tools/call",
"params": {
"name": "grader_comparison",
"arguments": {
"query": "Wembanyama 2023 Prizm Silver",
"grade": "9"
}
}
}Response (abbreviated)
{
"query": "Wembanyama 2023 Prizm Silver",
"grade": "9",
"lookback_days": 90,
"by_grader": [
{ "grader": "PSA", "sales": 18, "avg_price": 1450, "median_price": 1380 },
{ "grader": "BGS", "sales": 7, "avg_price": 1210, "median_price": 1175 },
{ "grader": "CGC", "sales": 4, "avg_price": 980, "median_price": 950 },
{ "grader": "SGC", "sales": 2, "avg_price": 890, "median_price": 890 }
],
"takeaway": "PSA commands the highest avg price at $1450",
"comparisons": [
{ "grader": "BGS", "pct_cheaper_than_top": 17 },
{ "grader": "CGC", "pct_cheaper_than_top": 32 },
{ "grader": "SGC", "pct_cheaper_than_top": 39 }
]
}Is this card trending up or down? Compares a recent time window against the prior window of equal length, with volume data. Upper bound is always yesterday so partial-day data never skews the result.
Parameters
| query | string | required | Card to analyze — e.g. 'Prizm Silver Wembanyama' |
| lookback_days | integer | optional | Length of each comparison window in days (default: 7) |
| grader | string | optional | Optional — filter by grader: psa | cgc | beckett | sgc |
| grade | string | optional | Optional — filter by grade (e.g. 10, 9.5) |
Example call
{
"jsonrpc": "2.0", "id": "1",
"method": "tools/call",
"params": {
"name": "price_momentum",
"arguments": {
"query": "Wembanyama Prizm Silver",
"lookback_days": 14
}
}
}Response (abbreviated)
{
"query": "Wembanyama Prizm Silver",
"window_days": 14,
"recent_window": {
"from": "2026-05-03", "to": "2026-05-16",
"sales": 42, "avg_price": 1380
},
"prior_window": {
"from": "2026-04-19", "to": "2026-05-02",
"sales": 35, "avg_price": 1150
},
"price_change_pct": 20.0,
"volume_change_pct": 20.0,
"momentum": "rising",
"note": "'rising' means both price and volume increased vs the prior window of the same length."
}Should you grade this card? Real cost math (PSA/CGC/SGC/BGS fees + shipping, all tiers including bulk) vs actual market comps. Returns expected profit at each grade, break-even analysis, and honest caveats.
Parameters
| query | string | required | Card to evaluate — e.g. '1986 Fleer Jordan 57' |
| raw_purchase_price | number | required | What you paid (or plan to pay) for the raw ungraded card |
| target_grade | string | optional | Grade you hope to achieve: 10 | 9.5 | 9 | 8.5 (default: 10) |
| grader | string | optional | psa (default) | cgc | beckett | sgc |
| submission_tier | string | optional | bulk | economy | standard (default) | express |
Example call
{
"jsonrpc": "2.0", "id": "1",
"method": "tools/call",
"params": {
"name": "grading_value_calculator",
"arguments": {
"query": "1986 Fleer Jordan 57",
"raw_purchase_price": 6500,
"target_grade": "10",
"grader": "psa",
"submission_tier": "standard"
}
}
}Response (abbreviated)
{
"query": "1986 Fleer Jordan 57",
"raw_purchase_price": 6500,
"grader": "PSA",
"target_grade": "10",
"grading_costs": {
"service_tier": "standard",
"per_card_fee": "$79.99",
"turnaround": "25 days",
"shipping_roundtrip": "$40–$60 (continental US)",
"total_estimate": "$119.99–$139.99",
"total_mid_estimate": 130
},
"grade_scenarios": [
{ "grade": "10", "sales": 8, "avg_price": 42000, "expected_profit": 35370, "is_target": true },
{ "grade": "9", "sales": 22, "avg_price": 9800, "expected_profit": 3170, "is_target": false },
{ "grade": "8", "sales": 11, "avg_price": 4200, "expected_profit": -2330, "is_target": false }
],
"math": {
"if_card_grades_at_target": "$42000 (avg sale price)",
"minus_raw_cost": "-$6500",
"minus_grading_and_ship": "-$130 (midpoint estimate)",
"expected_profit": "$+35370",
"break_even_grade": "8"
},
"caveats": [
"Grading outcome is NOT guaranteed — these numbers assume the card achieves each grade.",
"Only 8 comps found at 10 — price estimate may be unreliable."
]
}Enter a PSA/BGS/SGC/CGC serial number and see every time that specific graded card sold. Like Carfax, but for slabs — full ownership price history with appreciation trend.
Parameters
| slab_serial | string | required | The serial or cert number on the graded slab label — e.g. '84566824' |
| lookback_days | integer | optional | Limit to sales within this many days (default: all-time) |
Example call
{
"jsonrpc": "2.0", "id": "1",
"method": "tools/call",
"params": {
"name": "slab_lookup",
"arguments": {
"slab_serial": "84566824"
}
}
}Response (abbreviated)
{
"found": true,
"slab_serial": "84566824",
"card": "2018 Panini Prizm Silver Luka Doncic PSA 10",
"grader": "PSA",
"grade": "10",
"total_sales": 3,
"sales": [
{ "date": "2025-07-22", "price": 3600, "platform": "eBay", "listing_type": "Auction" },
{ "date": "2025-11-08", "price": 3850, "platform": "eBay", "listing_type": "BestOffer" },
{ "date": "2026-03-12", "price": 4200, "platform": "eBay", "listing_type": "Auction" }
],
"appreciation_pct": 16.7,
"trend": "rising",
"summary": "From $3600 → $4200 (16.7% rising)"
}Code
Code examples
Python — REST API
import requests
API_KEY = "tca_your_key_here"
BASE = "https://thecardapi.com/api/v1/market"
HEADERS = {"x-market-api-key": API_KEY}
# Search recent Ohtani auctions
r = requests.get(f"{BASE}/sales", headers=HEADERS, params={
"q": "Shohei Ohtani",
"listing_type": "auction",
"price_min": 50,
"limit": 50,
})
for sale in r.json()["data"]:
print(sale["sale_date"], sale["price"], sale["title"][:60])
# Incremental sync — only records indexed since your last poll
r = requests.get(f"{BASE}/sales", headers=HEADERS, params={
"indexed_after": "2026-05-15T10:00:00Z",
"limit": 100,
})Python — MCP tools/call
import requests
MCP_URL = "https://www.thecardapi.com/api/mcp"
HEADERS = {"Authorization": "Bearer tca_your_key_here", "Content-Type": "application/json"}
def call_tool(name: str, arguments: dict) -> dict:
payload = {
"jsonrpc": "2.0", "id": "1",
"method": "tools/call",
"params": {"name": name, "arguments": arguments},
}
r = requests.post(MCP_URL, headers=HEADERS, json=payload)
result = r.json()
if result.get("error"):
raise RuntimeError(result["error"]["message"])
import json
return json.loads(result["result"]["content"][0]["text"])
# Grade ladder for Mantle cards over $1,000
data = call_tool("grade_impact_analysis", {
"query": "Mickey Mantle",
"grader": "psa",
"lookback_days": 30,
})
for row in data["price_ladder"]:
avg = "{:,.0f}".format(row['avg_price'])
print(f"PSA {row['grade']}: ${avg} avg ({row['sales']} sales)")cURL
# REST — search for PSA 10 cards
curl "https://thecardapi.com/api/v1/market/sales?q=psa+10&limit=25" \
-H "x-market-api-key: tca_your_key_here"
# MCP — call price_momentum tool
curl https://www.thecardapi.com/api/mcp \
-H "Authorization: Bearer tca_your_key_here" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":"1","method":"tools/call","params":{"name":"price_momentum","arguments":{"query":"Wembanyama Prizm Silver"}}}'Node.js
const res = await fetch(
"https://thecardapi.com/api/v1/market/sales?q=topps+chrome&limit=50",
{ headers: { "x-market-api-key": "tca_your_key_here" } }
);
const { data, pagination } = await res.json();
console.log(`${pagination.total} results`);LangChain (Python)
import asyncio
from langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent
from langchain_anthropic import ChatAnthropic
async def main():
async with MultiServerMCPClient({
"thecardapi": {
"url": "https://www.thecardapi.com/api/mcp",
"transport": "streamable_http",
"headers": {"Authorization": "Bearer tca_your_key_here"},
}
}) as client:
tools = await client.get_tools()
model = ChatAnthropic(model="claude-sonnet-4-6")
agent = create_react_agent(model, tools)
result = await agent.ainvoke({
"messages": "Is grading my 1986 Fleer Jordan worth it at $6,500?"
})
print(result["messages"][-1].content)
asyncio.run(main())Ready to start building?
Free tier includes 5,000 sales/day with 3-day lookback. No credit card required.