Card catalogBetaRequest access →

Changelog

New fields, capabilities, and improvements. We ship every few days.

June 27, 2026API

CSV export now returns rate-limit headers

No breaking changes. Headers appear automatically on all CSV responses.

GET /v1/market/sales/export/csv now returns X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers alongside the file download — the same headers you already see on JSON responses.

X-RateLimit-Remaining reflects your remaining daily budget after the download is charged, so you can tell exactly how much headroom you have left without making an extra API call.

FieldDescription
X-RateLimit-LimitYour total daily row budget (e.g. 100000 on Starter). "unlimited" for plans without a cap.
X-RateLimit-RemainingRows remaining for today after this download. Deducted at the time the file is served.
X-RateLimit-ResetUnix timestamp (UTC) when the budget resets — midnight UTC of the current day.
Example (new fields only)
GET /v1/market/sales/export/csv?q=ohtani&date_from=2026-01-01
  -H "x-market-api-key: tca_..." -o ohtani_sales.csv

Response headers:
  X-RateLimit-Limit:     100000
  X-RateLimit-Remaining: 62000
  X-RateLimit-Reset:     1751155200
June 21, 2026API

One daily budget — 100K rows, shared across JSON calls and CSV downloads

Starter: 100K rows/day · JSON calls and CSV downloads share the same budget · no breaking changes

Starter plan now has a single shared daily budget of 100,000 rows. Every row you receive counts toward the same pool — whether it comes from a paginated JSON call or a CSV file download. Pull 60,000 rows today and you have 40,000 left, available as more API calls or a CSV download.

CSV downloads are now counted toward your budget. When you call GET /v1/market/sales/export/csv, the number of rows in the file is deducted from your daily total. Check X-RateLimit-Remaining after any call — it always reflects your true remaining budget.

FieldDescription
GET /salesEach row returned counts against your daily budget. X-RateLimit-Remaining updates after every response.
GET /sales/export/csvRows in the downloaded file count against the same daily budget. Same filter params as /sales.
X-RateLimit-RemainingYour remaining rows for the day — updated after every JSON call and every CSV download.
Example (new fields only)
// JSON call: 1,000 rows returned
GET /v1/market/sales?q=ohtani&limit=1000
→ X-RateLimit-Limit: 100000
→ X-RateLimit-Remaining: 99000

// CSV download: 40,000 rows in the file
GET /v1/market/sales/export/csv?q=ohtani&date_from=2026-01-01
  -H "x-market-api-key: tca_..." -o ohtani_sales.csv

// Next JSON call: budget reflects both
→ X-RateLimit-Remaining: 59000
June 20, 2026New

Webhooks add-on — $10/mo on Starter, 7-day free trial

$10/mo · Starter add-on · Up to 5 endpoints · 7-day free trial · HMAC-SHA256 signed · 3 retries with backoff

Webhooks are now available as a self-serve add-on for Starter subscribers. Register up to 5 HTTPS endpoints and we'll push every new card sale to them within ~30 seconds of indexing — no polling loop required.

Each delivery is a signed batch of up to 1,000 records in the same schema as GET /sales. We retry 3 times with backoff (0s / 5s / 30s) on failure. If all three fail, your cursor holds and you pick up exactly where you left off on the next cycle — no missed records, no duplicates.

Webhooks do not include NRT (near-real-time eBay data). NRT remains a separate add-on available on Custom plans.

FieldDescription
POST /webhookAdd an endpoint (max 5). Required: url, secret. Optional: label.
GET /webhookList all active endpoints for your key.
DELETE /webhook/{id}Remove an endpoint by ID.
X-Webhook-SignatureHMAC-SHA256 signature on every delivery. Verify against the raw request body.
Example (new fields only)
// Register an endpoint
POST /v1/market/webhook
{ "url": "https://your-server.com/hook", "secret": "your-secret", "label": "prod" }

// Delivery (POSTed to your URL every ~30s when new sales exist)
{
  "event":     "sales.batch",
  "timestamp": "2026-06-20T10:00:00Z",
  "count":     83,
  "data":      [ { "id": "ebay-...", "price": 312.00, ... } ]
}
June 20, 2026API

Cursor pagination on all plans · CSV export on Starter

Cursor pagination on all plans including Free · CSV export on Starter and above · no breaking changes

Cursor pagination is now available on every plan, including Free and Starter. Every response from /v1/market/sales now includes a next_cursor field in the pagination object when more results exist. Pass it as ?cursor= on your next request to fetch the next page — no offset drift, no missed or duplicated records as new data is indexed.

CSV export is now available on Starter and above. Hit GET /v1/market/sales/export/csv with the same filter params you'd use on /sales and receive a download-ready CSV file. Rows count against your shared daily budget (100K on Starter).

Both features require no integration changes if you're already on the API — just start using the new parameters.

FieldDescription
next_cursorOpaque string in pagination object. Present when has_more=true. Pass as ?cursor= on the next request.
cursorRequest param. Pass next_cursor from a previous response to continue from exactly where you left off.
GET /sales/export/csvSame filter params as /sales. Returns a CSV file download. Rows count against the shared daily budget.
Example (new fields only)
// Cursor pagination — page through large result sets
GET /v1/market/sales?q=psa+10+trout&limit=1000
→ pagination.next_cursor: "eyJwZ19pZCI6IDE4N..."

GET /v1/market/sales?q=psa+10+trout&limit=1000&cursor=eyJwZ19pZCI6IDE4N...
→ pagination.next_cursor: null   // last page

// CSV download
GET /v1/market/sales/export/csv?q=ohtani&date_from=2026-01-01
→ CSV file download
June 17, 2026New Platforms

Major auction house results — 175,000+ lots, 2012 to today

175,000+ lots · 3 auction houses · 2012–today · hammer price (add ~22% for all-in buyer cost) · use ?platform= to filter by house.

Sales data from three major card auction houses is now live in the API. Results appear automatically in any search alongside eBay data — no integration changes required. Use ?platform= to query a specific house or omit it entirely to search across all sources at once.

The combined dataset covers 175,000+ completed auction lots from 2012 through today — over a decade of high-value card sales. It includes bid counts, lot images, direct links to each lot page, and parsed grade/grader fields for slabbed cards. This is the same underlying data serious collectors and dealers use to establish market value.

One important distinction: auction house prices are hammer prices — the amount called at close by the auctioneer. Buyers pay an additional buyer's premium on top (typically 20–22%). eBay prices in the API are all-in. If you're comparing prices across platforms, account for this difference.

FieldDescription
platformFilter to a specific auction house with ?platform=<name>. Omit to search across all platforms.
priceHammer price for auction house lots — not all-in. Buyers pay an additional ~20–22% buyer's premium on top.
sold_atExact UTC close time — 100% populated for auction house lots.
listing_urlDirect link to the lot page.
feedbackAlways null — not applicable for auction houses.
Example (new fields only)
// Search across all platforms (eBay + auction houses)
GET /v1/market/sales?q=psa+10+mickey+mantle

// Auction house record
{
  "platform":     "goldin",
  "listing_type": "auction",
  "title":        "1952 Topps #311 Mickey Mantle — PSA VG-EX 4",
  "sale_date":    "2024-03-17",
  "sold_at":      "2024-03-17T02:30:00Z",
  "price":        75000.00,
  "bids":         18,
  "grader":       "PSA",
  "grade":        "4",
  "price_confirmed": true
}
June 14, 2026New Field

shipping_price — buyer shipping cost, separate from sale price

~67% of records have shipping_price populated. ?shipping_max=0 for free shipping only.

Every sale response now includes shipping_price — the amount the buyer paid for shipping, separate from the card price. A free-shipping listing returns 0.00. When shipping cost was not disclosed by the seller, the field is null.

Filter by shipping cost with ?shipping_max=0 (free shipping only) or ?shipping_max=10 (shipping ≤ $10). Combine with price filters to compare true all-in costs across listings.

Coverage is approximately 67% of records. The remaining ~33% of listings did not publish shipping cost and return null.

FieldDescription
shipping_pricenumber|null. Buyer shipping cost in USD. 0.00 = free shipping. Null when not disclosed by the seller.
shipping_maxFilter param. Only return records with shipping_price ≤ this value. Use shipping_max=0 for free shipping only. Records with null shipping_price are excluded.
Example (new fields only)
// Free shipping only
GET /v1/market/sales?q=psa+10+mike+trout&shipping_max=0

// ≤ $10 shipping
GET /v1/market/sales?q=psa+10+ohtani&shipping_max=10

// Response (each record)
{
  "id":             "123456789",
  "price":          312.00,
  "shipping_price": 0.00,
  ...
}
June 14, 2026Beta

Webhooks — delivery daemon deployed, multi-endpoint fanout

Auction close → delivery: 9 min median · 11 min 90th pct. Every POST signed with HMAC-SHA256.

The webhook delivery daemon shipped. It polls every 30 seconds and fans out to all registered endpoints per API key. Each batch is HMAC-SHA256 signed and retried three times with backoff (0s / 5s / 30s) on failure.

This update also added support for multiple endpoints per key (up to 5) via a new webhook_endpoints table — moving from a single URL column to a normalized per-endpoint model.

FieldDescription
event"sales.batch" — type identifier for the delivery
timestampISO 8601 UTC timestamp of the delivery
countNumber of records in this batch (up to 1,000)
dataArray of sale records — same schema as /v1/market/sales
Example (new fields only)
POST https://your-endpoint.com/webhook
Content-Type: application/json
X-Webhook-Signature: sha256=<hmac-sha256>

{
  "event":     "sales.batch",
  "timestamp": "2026-06-14T06:09:00Z",
  "count":     47,
  "data": [
    {
      "id":           "ebay-123456789",
      "price":        312.00,
      "listing_type": "auction",
      "sold_at":      "2026-06-14T06:00:24Z",
      "player":       "Shohei Ohtani",
      ...
    }
  ]
}
June 14, 2026Beta

Card catalog — 13.8M cards, sets, and metadata

The catalog API is now in beta. Search and browse 13.8M cards across sports, years, sets, and player names — with structured flags for rookies, autos, relics, short prints, print runs, and more. Card images are served from our own CDN.

The catalog is a complement to the sales API, not a replacement. Use it to build structured lookups, enrich your own records with card metadata, or power a type-ahead search by player or set name. The Catalog API is an add-on available to any plan. Access is currently invite-only while we finalize pricing. Email hello@thecardapi.com to join the beta.

FieldDescription
GET /v1/catalogSearch and filter cards by set, player, sport, year, variant flags
GET /v1/catalog/{id}Single card by ID
GET /v1/catalog/setsBrowse sets — filterable by sport, year, name
GET /v1/catalog/sets/{id}Single set with card count and image coverage
GET /v1/catalog/sportsList of distinct sports in the catalog
Example (new fields only)
{
  "id":              1042981,
  "set_id":          4821,
  "sport":           "Baseball",
  "year":            2011,
  "set_name":        "2011 Topps Update Series",
  "card_number":     "US175",
  "subject":         "Mike Trout",
  "is_rookie":       true,
  "is_auto":         false,
  "print_run":       null,
  "image_url_front": "https://cdn.thecardapi.com/cards/1042981_front.jpg",
  "has_front_image": true
}
June 14, 2026New Field

print_run field — filter by serial run, retrieve structured print-run value

~36% of records have print_run populated. /99 → 99. 1/1 → 1. Base cards → null.

Every sale response now includes a print_run field — the denominator of the serial fraction stamped on the card. A card serialized /99 returns "print_run": 99. A 1/1 returns "print_run": 1. A base card with no serial number returns null.

Filter results directly with ?print_run_max=99 (any card numbered /99 or lower) or ?print_run_min=1 (1/1s only). Combine both to target a range — e.g. print_run_min=1&print_run_max=10 for ultra-rare single-digit print runs.

Approximately 36% of all records (6.2 million rows) have print_run populated. Coverage grows automatically as historical data backfills.

FieldDescription
print_runInteger or null. Denominator of the serial fraction. /99 → 99. /10 → 10. 1/1 → 1. Null for unlisted base cards.
print_run_minFilter param. Only return records with print_run ≥ this value (inclusive).
print_run_maxFilter param. Only return records with print_run ≤ this value (inclusive).
Example (new fields only)
// Cards serialized /10 or lower
GET /v1/market/sales?q=mike+trout&print_run_max=10

// Response (each record)
{
  "id":           "ebay-387214905012",
  "title":        "2011 Topps Update Mike Trout RC /10 BGS 9.5",
  "price":        14500.00,
  "listing_type": "auction",
  "sold_at":      "2026-06-14T04:22:11Z",
  "print_run":    10
}
June 13, 2026New Fields

10 structured metadata fields added to the response schema

Every response from /v1/market/sales now includes 10 structured fields — player, sport, team, manufacturer, card_set, card_number, year, season, league, and features. These fields are populated where available from the original listing data. They will be null (or [] for features) when not present.

Coverage is currently limited to recent sales where structured listing data was provided by the seller. Coverage grows automatically as more listings include this data — no integration changes are required.

FieldDescription
playerPlayer name
sportSport (Baseball, Basketball, Hockey, …)
teamTeam name at time of card printing
manufacturerCard manufacturer (Topps, Panini, Bowman, …)
card_setSet name (e.g. 2022 Topps Update Series)
card_numberSet card number (e.g. #295 or BCP-42)
yearCard year
seasonSports season (e.g. 2024-25)
leagueLeague (e.g. Major League (MLB), NBA)
featuresArray of card attributes. e.g. ["Auto", "Rookie", "Patch"]. Empty array when not provided.
Example (new fields only)
{
  "player":       "Bobby Witt Jr.",
  "sport":        "Baseball",
  "team":         "Kansas City Royals",
  "manufacturer": "Topps",
  "card_set":     "2022 Topps Update Series",
  "card_number":  "SMLB-82",
  "year":         2022,
  "season":       "2022",
  "league":       "Major League (MLB)",
  "features":     ["Insert", "Rookie"]
}
June 12, 2026Search

Print-run and serial-number search — exact matching, no false positives

Previously /10 matched PSA 10 grades. Previously 47/100 matched any record containing 47. Both fixed.

Searching for /10 now returns cards from a 10-copy print run — not PSA 10 grades. Searching for 47/100 now matches the exact serial-numbered card stamped 47 out of 100, not any record containing the number 47.

Two distinct search intents are handled separately: N/M (e.g. 47/100) targets the specific physical card with that serial stamp. /N (e.g. /10) matches any card from that print run. Both work identically in the playground and the market API.

June 11, 2026New Field

price_confirmed — distinguish confirmed prices from early captures

Every record now includes price_confirmed. true means the price is the verified final transaction amount. false means the record was captured very shortly after close and the final price will be confirmed on our next daily run (within 24 hours).

Most use cases can ignore this. It matters most if you are building something that processes data continuously and needs to distinguish between an early capture and a settled transaction.

FieldDescription
price_confirmedtrue = verified final price. false = early capture, confirmed price available within 24 hours.
June 8, 2026Performance

3–5ms search across 17 million records

683ms → 3–5ms. No API changes required.

A full-text sales search — e.g. 'PSA 10 Mike Trout 2011 Topps Update' filtered by grade, grader, and date range — now returns in 3–5ms across 17 million records. The same query previously took 683ms.

This was a complete rewrite of the query backend. No API changes were required. All existing integrations benefit automatically.

Coming soon

  • Additional auction houses — PWCC, Heritage, and more
  • Historical bulk exports — full dataset downloads for companies that need years of data at once
  • Per-card price history — time-series comps by catalog ID

Questions or feedback? hello@thecardapi.com