API Reference

Raw transaction-level access to trading card sales across all major platforms — via REST endpoints and an MCP server with 7 AI analysis tools.

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.

HTTP
# 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_here

Don't have a key? Get one free →

Base

Base URL

REST API

https://thecardapi.com/api/v1/market

All REST paths below are relative to this base.

MCP Server

https://thecardapi.com/api/mcp

JSON-RPC 2.0 over streamable HTTP. See the MCP Server section.

Endpoints

Endpoints

MethodPathDescription
GET/salesSearch and filter sales records
GET/sales/{id}Single sale by ID
GET/dailyAggregate stats for a date
GET/platformsPlatform list with last updated date
GET/coverageLatest data freshness status
GET/sales/export/csvDownload filtered sales as CSV
POST/webhookRegister a webhook URL (Pro/Enterprise)
GET/webhookGet current webhook config
DELETE/webhookRemove webhook registration

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.

ParameterTypeDescription
qstringoptionalFull-text search on listing title (min 4 chars). Supports eBay boolean syntax: (term1,term2) for OR, -term for NOT, "exact phrase" for phrase match.
platformstringoptionalComma-separated: ebay, goldin, heritage, fanatics-vault, fanatics-weekly, rea, alt, pristine, myslabs, sterlingsportsauctions
listing_typestringoptionalComma-separated: auction, fixed_price, best_offer
date_fromdateoptionalStart date YYYY-MM-DD. Clamped to your plan's lookback window.
date_todateoptionalEnd date YYYY-MM-DD
price_minnumberoptionalMinimum sale price (USD)
price_maxnumberoptionalMaximum sale price (USD)
sortstringoptionaldate_desc (default) | date_asc | price_desc | price_asc
pageintegeroptionalPage number (default: 1)
limitintegeroptionalResults per request (default: 25, max: 1,000). Same cap on all plans.
indexed_afterdatetimeoptionalISO 8601 UTC. Return only records indexed after this time. Useful for incremental sync.
cursorstringoptionalKeyset pagination cursor. Enterprise only.

eBay boolean syntax

(psa,bgs) — title contains "psa" OR "bgs"
-reprint — title does NOT contain "reprint"
"topps chrome" — exact phrase match
ohtani (psa,bgs) -rookie — combine all three

Response

Response schema

JSON
{
  "data": [
    {
      "id":                    "ebay-137222685761",
      "platform":              "eBay",
      "listing_type":          "auction",
      "title":                 "2021 Bowman Chrome Kyle Harrison Auto PSA 10",
      "sale_date":             "2026-05-14",
      "sold_at":               "2026-05-14T14:32:17Z",
      "price":                 47.50,
      "currency":              "USD",
      "seller":                "dcsports87",
      "bids":                  12,
      "feedback":              99.7,
      "image_url":             "https://i.ebayimg.com/...",
      "thumbnail_url":         "https://i.ebayimg.com/...",
      "listing_url":           "https://www.ebay.com/itm/137222685761",
      "card_description":      "Kyle Harrison Auto",
      "cert":                  "93265128",
      "condition":             null,
      "grade":                 "10",
      "grader":                "PSA",
      "grading_company":       "Professional Sports Authenticator",
      "has_autograph_grade":   false,
      "has_qualifier":         false,
      "label":                 null,
      "qualifier_type":        null,
      "slab_serial":           "93265128",
      "autograph_grade":       null
    }
  ],
  "pagination": {
    "total":       258817,
    "page":        1,
    "limit":       25,
    "pages":       10353,
    "next_cursor": null
  },
  "meta": {
    "coverage_date_from":  "2026-05-01",
    "coverage_date_to":    "2026-05-17",
    "platforms_covered":   ["Alt", "eBay", "Fanatics-Vault", "Fanatics-Weekly", "Goldin", "Heritage", "MySlabs", "Pristine", "REA", "SterlingSportsAuctions"],
    "generated_at":        "2026-05-17T10:00:00Z"
  }
}
FieldTypeCoverageDescription
idstring100%Unique sale identifier (platform-prefixed)
platformstring100%eBay · Goldin · Heritage · Fanatics-Vault · Fanatics-Weekly · REA · Alt · Pristine · MySlabs · SterlingSportsAuctions
listing_typestring100%auction · fixed_price · best_offer
titlestring100%Raw listing title as scraped
sale_datestring100%YYYY-MM-DD of the sale
sold_atstring100%ISO 8601 timestamp of sale (UTC)
pricenumber100%Final sale price in USD. For best_offer, the true negotiated price.
currencystring100%Always USD
sellerstring~95%Seller username
bidsinteger|null~60%Number of bids (auction only)
feedbacknumber|null~96%Seller feedback score (e.g. 99.7)
image_urlstring|null~85%Full-size listing image URL
thumbnail_urlstring|null~85%Thumbnail image URL
listing_urlstring|null~99%Original listing URL
card_descriptionstring|null~40%Parsed card description from grading label
certstring|null~12%Grading certificate number
conditionstring|null~8%Raw condition string from listing
gradestring|null~12%Numeric grade (e.g. "10", "9.5", "Auth")
graderstring|null~12%Grader abbreviation: PSA · BGS · CGC · SGC
grading_companystring|null~12%Full grading company name
has_autograph_gradeboolean|null~12%Whether the slab has a separate auto grade
has_qualifierboolean|null~12%Whether the grade has a qualifier (e.g. OC, MK)
labelstring|null~10%Grading label variant (e.g. "Gold Label")
qualifier_typestring|null~3%Qualifier description (e.g. "OC", "MK", "ST")
slab_serialstring|null~12%Slab serial / cert number (may match cert)
autograph_gradestring|null~4%Autograph sub-grade where graded separately
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.

Error

Error codes

StatusMeaning
401Invalid or missing API key
403Action requires a higher plan (e.g. cursor pagination, webhook management)
404Resource not found
422Validation error — check parameter types and ranges
429Daily sales limit reached. Resets at midnight UTC. Upgrade for more.
500Server error — try again shortly

Webhooks

Webhooks

Pro and Enterprise plans can register an HTTPS endpoint to receive a POST notification after each data refresh.

Register

HTTP
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"
}

Payload

JSON
{
  "event":     "data_refresh_complete",
  "date":      "2026-05-16",
  "records":   258817,
  "timestamp": "2026-05-16T10:05:00Z"
}

Verify the signature

Each request includes X-Webhook-Signature: sha256=<hex>. Compute HMAC-SHA256 over the raw body using your secret.

Python
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)

Rate

Rate limits

The only enforced limits are sales rows returned per day and how far back you can query. Counters reset at midnight UTC.

PlanSales/dayLookback
Free5,0003 days
Starter50,00014 days
Pro500,00090 days
Business1,000,0001 year
EnterpriseUnlimitedAll time

Max limit is 1,000 rows per request on all plans. View full pricing →

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

POST https://thecardapi.com/api/mcp

Protocol: JSON-RPC 2.0 · Transport: streamable HTTP

Discover available tools

JSON
{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "tools/list"
}

Claude Desktop

JSON
{
  "mcpServers": {
    "thecardapi": {
      "command": "npx",
      "args": ["mcp-remote", "https://thecardapi.com/api/mcp",
               "--header", "Authorization: Bearer YOUR_API_KEY"]
    }
  }
}

Claude Code

Shell
claude mcp add thecardapi \
  --transport http \
  --url https://thecardapi.com/api/mcp \
  --header "Authorization: Bearer YOUR_API_KEY"

Cursor / Windsurf

JSON
{
  "mcpServers": {
    "thecardapi": {
      "url": "https://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.

search_cards

Find recent sold prices for any card across eBay, Goldin, Heritage, Fanatics, and more. Returns individual sale records sorted by date. Supports filtering by platform, grader, grade, listing type, date range, and price range.

Parameters

querystringoptionalFull-text search — e.g. 'PSA 10 Luka Doncic 2018 Prizm Silver'
platformstringoptionaleBay | Goldin | Heritage | Fanatics-Vault | Fanatics-Weekly | REA | Pristine | Alt | MySlabs | SterlingSportsAuctions
graderstringoptionalpsa | cgc | beckett | sgc
gradestringoptional10 | 9.5 | 9 | 8.5 | 8 | 7 | auth | 10pristine
listing_typestringoptionalAuction | FixedPrice | BestOffer
date_fromstringoptionalStart date YYYY-MM-DD
date_tostringoptionalEnd date YYYY-MM-DD
price_minnumberoptionalMinimum sale price
price_maxnumberoptionalMaximum sale price
limitintegeroptionalResults to return (1–20, default: 10)

Example call

JSON
{
  "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)

JSON
{
  "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",
      "seller":       "pwcc_auctions",
      "feedback":     99.8,
      "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."
}
grade_impact_analysis

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

querystringrequiredCard to analyze — e.g. 'Luka Doncic 2018 Prizm Silver'
graderstringoptionalpsa (default) | cgc | beckett | sgc
lookback_daysintegeroptionalDays of history to include (default: 90)

Example call

JSON
{
  "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)

JSON
{
  "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."
  }
}
grader_comparison

PSA vs CGC vs SGC vs BGS for the same card at the same grade. Find which grader commands the highest market premium.

Parameters

querystringrequiredCard to compare — e.g. 'Wembanyama 2023 Prizm Silver'
gradestringrequiredGrade to compare across graders — e.g. 10 | 9.5 | 9 | 8.5 | 8
lookback_daysintegeroptionalDays of history (default: 90)

Example call

JSON
{
  "jsonrpc": "2.0", "id": "1",
  "method": "tools/call",
  "params": {
    "name": "grader_comparison",
    "arguments": {
      "query": "Wembanyama 2023 Prizm Silver",
      "grade": "9"
    }
  }
}

Response (abbreviated)

JSON
{
  "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 }
  ]
}
price_momentum

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

querystringrequiredCard to analyze — e.g. 'Prizm Silver Wembanyama'
lookback_daysintegeroptionalLength of each comparison window in days (default: 7)
graderstringoptionalOptional — filter by grader: psa | cgc | beckett | sgc
gradestringoptionalOptional — filter by grade (e.g. 10, 9.5)

Example call

JSON
{
  "jsonrpc": "2.0", "id": "1",
  "method": "tools/call",
  "params": {
    "name": "price_momentum",
    "arguments": {
      "query":         "Wembanyama Prizm Silver",
      "lookback_days": 14
    }
  }
}

Response (abbreviated)

JSON
{
  "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."
}
grading_value_calculator

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

querystringrequiredCard to evaluate — e.g. '1986 Fleer Jordan 57'
raw_purchase_pricenumberrequiredWhat you paid (or plan to pay) for the raw ungraded card
target_gradestringoptionalGrade you hope to achieve: 10 | 9.5 | 9 | 8.5 (default: 10)
graderstringoptionalpsa (default) | cgc | beckett | sgc
submission_tierstringoptionalbulk | economy | standard (default) | express

Example call

JSON
{
  "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)

JSON
{
  "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."
  ]
}
seller_lookup

Research any card seller — feedback score, total sales, average prices, which grades they specialize in, and a trust signal. Works across all platforms, not just eBay.

Parameters

sellerstringrequiredSeller name or partial name — e.g. 'probstein', 'dcsports87'
lookback_daysintegeroptionalDays of history to analyze (default: 90)

Example call

JSON
{
  "jsonrpc": "2.0", "id": "1",
  "method": "tools/call",
  "params": {
    "name": "seller_lookup",
    "arguments": {
      "seller":        "pwcc_auctions",
      "lookback_days": 90
    }
  }
}

Response (abbreviated)

JSON
{
  "seller":       "pwcc_auctions",
  "lookback_days": 90,
  "stats": {
    "total_sales":    847,
    "avg_price":      1240,
    "median_price":   680,
    "max_sale":       42000,
    "feedback_score": 99.8,
    "last_active":    "2026-05-16"
  },
  "top_platforms": [
    { "platform": "eBay", "sales": 847 }
  ],
  "top_grades": [
    { "grader": "PSA", "grade": "10", "sales": 312 },
    { "grader": "PSA", "grade": "9",  "sales": 198 },
    { "grader": "BGS", "grade": "9.5","sales": 87  }
  ],
  "trust_signal": "High-volume established dealer — very safe to buy from"
}
slab_lookup

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_serialstringrequiredThe serial or cert number on the graded slab label — e.g. '84566824'
lookback_daysintegeroptionalLimit to sales within this many days (default: all-time)

Example call

JSON
{
  "jsonrpc": "2.0", "id": "1",
  "method": "tools/call",
  "params": {
    "name": "slab_lookup",
    "arguments": {
      "slab_serial": "84566824"
    }
  }
}

Response (abbreviated)

JSON
{
  "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",   "seller": "cards4sale" },
    { "date": "2025-11-08", "price": 3850, "platform": "eBay", "listing_type": "BestOffer", "seller": "pwcc_auctions" },
    { "date": "2026-03-12", "price": 4200, "platform": "eBay", "listing_type": "Auction",   "seller": "goldenage_cards" }
  ],
  "appreciation_pct": 16.7,
  "trend":   "rising",
  "summary": "From $3600 → $4200 (16.7% rising)"
}

Code

Code examples

Python — REST API

Python
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 scraped 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

Python
import requests

MCP_URL = "https://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

Shell
# 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://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

JavaScript
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)

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://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.