PriceDepth API

Real-time and historical pricing data for 64,000+ graded collectible cards.

Quickstart

Get your first price in under a minute.

Get a Free API Key Instantly

1
Sign up and get an API key Use the form above, or create an account at portal.html, then click "Generate API Key" in your dashboard.
2
Make your first request Try fetching a card's current price:
curl -H "X-Api-Key: YOUR_API_KEY" \
  https://pricedepth.com/v1/cards?limit=5
const resp = await fetch('https://pricedepth.com/v1/cards?limit=5', {
  headers: { 'X-Api-Key': 'YOUR_API_KEY' }
});
const { data } = await resp.json();
data.forEach(card =>
  console.log(card.name, card.grade)
);
import requests

resp = requests.get(
    'https://pricedepth.com/v1/cards',
    headers={'X-Api-Key': 'YOUR_API_KEY'},
    params={'limit': 5}
)
for card in resp.json()['data']:
    print(card['name'], card['grade'])
3
Explore endpoints Browse the reference below or try the interactive examples.

Authentication

All /v1/* endpoints require an API key passed via the X-Api-Key header.

Portal endpoints (/portal/*) use JWT tokens via Authorization: Bearer <token>.

Public endpoints like /api/search and /api/trends/* require no authentication.

Header format
X-Api-Key: tp_collector_abc123def456...

Keys are prefixed with the tier: tp_free_, tp_collector_, tp_dealer_, tp_api_, tp_enterprise_.

Rate Limits

Rate limits are enforced per API key using a sliding window. Every response includes rate limit headers:

HeaderDescription
X-RateLimit-LimitRequests allowed per minute
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when window resets
X-Monthly-QuotaTotal monthly calls allowed
X-Monthly-UsedCalls used this billing period
Retry-AfterSeconds to wait (only on 429)

Error Handling

Errors return JSON with error (human-readable) and code (machine-readable) fields:

{
  "error": "Invalid or missing API key",
  "code": "INVALID_API_KEY"
}
StatusCodeMeaning
401INVALID_API_KEYMissing or invalid API key
403TIER_REQUIREDEndpoint requires a higher tier
404CARD_NOT_FOUNDCard ID does not exist
429RATE_LIMIT_EXCEEDEDPer-minute rate limit hit
429MONTHLY_QUOTA_EXCEEDEDMonthly quota exhausted

Cards

GET /v1/cards API Key

Search and list cards in the catalog. Paginated.

ParamTypeDescription
qstringSearch query (max 200 chars). Supports synonym expansion and fuzzy matching.
pageintPage number (default: 1)
limitintResults per page (default: 50, max: 100)
gradestringFilter by grade (e.g. PSA 10)
categorystringFilter by category
product_typestringFilter by product type (e.g. pokemon-tcg)
languagestringFilter by language (e.g. EN, JP)
set_namestringFilter by set name
sportstringFilter by sport
yearstringFilter by year
grading_companystringFilter by grading company
Response
{
  "data": [
    {
      "card_id": "1999 Pokemon Base Charizard #4|10",
      "name": "1999 Pokemon Base Charizard #4",
      "set_name": "Base Set",
      "card_number": "4",
      "grade": "PSA 10",
      "language": "EN",
      "image_url": "https://images.pricedepth.com/base-charizard-4.jpg",
      "product_type": "pokemon-tcg"
    },
    {
      "card_id": "1998 Pokemon Illustrator Pikachu Promo|10",
      "name": "1998 Pokemon Illustrator Pikachu Promo",
      "set_name": "Promo",
      "card_number": null,
      "grade": "PSA 10",
      "language": "JP",
      "image_url": "https://images.pricedepth.com/illustrator-pikachu.jpg",
      "product_type": "pokemon-tcg"
    }
  ],
  "cards": "[deprecated mirror of data — sunset 2026-06-30]",
  "total": 64128,
  "page": 1,
  "limit": 50,
  "pages": 1199
}

Note: the legacy cards array is mirrored from data and is sunset on 2026-06-30. New integrations should read data. The response includes a Deprecation: true header until then.

GET /v1/cards/:id API Key

Get full details for a single card.

Response
{
  "card_id": "1999 Pokemon Base Charizard #4|10",
  "name": "1999 Pokemon Base Charizard #4",
  "set_name": "Base Set",
  "card_number": "4",
  "grade": "PSA 10",
  "language": "EN",
  "image_url": "https://images.pricedepth.com/base-charizard-4.jpg",
  "marketplace_url": "https://www.example.com/product/...",
  "product_type": "pokemon-tcg",
  "category": "pokemon-tcg",
  "slug": "1999-pokemon-base-charizard-4-psa-10",
  "distribution": null,
  "created_at": "2025-12-15T08:00:00.000Z",
  "updated_at": "2026-04-09T03:12:14.000Z"
}

Pricing

GET /v1/cards/:id/price API Key

Comprehensive pricing snapshot. Returns current FMV, all-time and 52-week highs/lows, price change deltas, TWAP, VWAP, moving averages, rate of change, risk analytics, and sales-based medians. Replaces the need to call /analytics separately. Optionally pass ?date=YYYY-MM-DD for historical.

ParamTypeDescription
datestringOptional. Historical price as of this date.
Response
{
  "card_id": "1999 Pokemon Base Charizard #4|10",
  "price_usd": 42000.00,
  "price_date": "2026-04-09",

  "all_time_high_usd": 52000.00,
  "all_time_high_date": "2021-02-15",
  "all_time_low_usd": 8500.00,
  "all_time_low_date": "2019-06-03",

  "high_52w_usd": 48000.00,
  "high_52w_date": "2025-11-20",
  "low_52w_usd": 31000.00,
  "low_52w_date": "2026-01-15",

  "change_pct_24h": -1.2,
  "change_pct_7d": 3.5,
  "change_pct_30d": -8.1,
  "change_pct_90d": 12.4,
  "change_pct_ytd": 15.7,

  "twap_7d": 41850.00,
  "twap_30d": 43020.00,
  "vwap_7d": 42010.00,
  "vwap_30d": 42875.00,

  "sma_7d": 41900.00,
  "sma_30d": 42530.00,
  "sma_90d": 41050.00,

  "roc_7d": 3.5,
  "roc_30d": -8.1,
  "roc_90d": 12.4,

  "volatility_annual": 34.52,
  "sharpe_ratio": 1.85,
  "max_drawdown_pct": 12.08,
  "return_90d_pct": 9.09,
  "data_points": 87,

  "median_sale_7d": 41500.00,
  "median_sale_30d": 40800.00,
  "sales_count_7d": 2,
  "sales_count_30d": 5
}
GET /v1/cards/:id/history API Key

Daily price time series for a card.

ParamTypeDescription
daysintNumber of days (default: 90, max: 365)
Response
{
  "card_id": "1999 Pokemon Base Charizard #4|10",
  "days": 90,
  "prices": [
    { "date": "2026-01-10", "price": 38500.00 },
    { "date": "2026-01-11", "price": 38750.00 },
    { "date": "2026-01-12", "price": 39200.00 },
    "...",
    { "date": "2026-04-09", "price": 42000.00 }
  ]
}
GET /v1/cards/:id/grade-prices Collector+

Grade-specific pricing with PSA population data. Shows prices across all grades (PSA 1-10) for a card.

Response
{
  "name": "1999 Pokemon Base Charizard #4",
  "set_name": "Base Set",
  "grades": [
    {
      "card_id": "1999 Pokemon Base Charizard #4|10",
      "grade": "PSA 10",
      "language": "EN",
      "price_usd": 42000.00,
      "price_date": "2026-04-09",
      "psa_pop": 122
    },
    {
      "card_id": "1999 Pokemon Base Charizard #4|9",
      "grade": "PSA 9",
      "language": "EN",
      "price_usd": 3800.00,
      "price_date": "2026-04-09",
      "psa_pop": 2150
    },
    {
      "card_id": "1999 Pokemon Base Charizard #4|0",
      "grade": "Raw",
      "language": "EN",
      "price_usd": 450.00,
      "price_date": "2026-04-08",
      "psa_pop": null
    }
  ],
  "grade_count": 3
}

Analytics

GET /v1/cards/:id/analytics API Key

Risk analytics: annualized volatility, max drawdown, Sharpe ratio, and 90-day return. Note: These fields are now included in /v1/cards/:id/price — prefer that endpoint to avoid an extra call.

Response
{
  "card_id": "1999 Pokemon Base Charizard #4|10",
  "data_points": 87,
  "volatility_annual": 34.52,
  "sharpe_ratio": 1.85,
  "max_drawdown_pct": 12.08,
  "return_90d_pct": 9.09
}

If fewer than 2 data points are available the response is {"card_id": "...", "message": "Insufficient data for analytics", "data_points": N}.

GET /v1/indexes/:slug/history API Key

Index value time series. Use from, to (YYYY-MM-DD) and interval (1d, 1w, 1m) query params. Slugs: pdi-100, cat-pokemon-tcg, cat-sports-baseball, etc.

Card Comparison

GET /v1/compare API Key

Compare 2-10 cards side-by-side with pricing, analytics, and liquidity data.

ParamTypeDescription
cardsstringRequired. Comma-separated card_ids (2-10).
Response
{
  "cards": [
    {
      "card_id": "1999 Pokemon Base Charizard #4|10",
      "name": "1999 Pokemon Base Charizard #4",
      "set_name": "Base Set",
      "grade": "PSA 10",
      "language": "EN",
      "image_url": "https://images.pricedepth.com/base-charizard-4.jpg",
      "current_price": 42000.00,
      "price_date": "2026-04-09",
      "analytics": {
        "volatility_annual": 34.52,
        "sharpe_ratio": 1.85,
        "max_drawdown_pct": 12.08,
        "return_90d_pct": 9.09
      },
      "liquidity": {
        "sales_30d": 5,
        "avg_daily_volume": 0.2
      }
    }
  ],
  "compared_at": "2026-04-10T15:00:00.000Z"
}

Comps & Liquidity

GET /v1/cards/:id/comps API Key

Unified comp data: recent sales, median prices, liquidity score, and PSA population — everything needed to value a card.

ParamTypeDescription
daysintLookback window (default: 30, max: 90)
gradestringOptional. Filter sales by grade.
Response
{
  "card_id": "1999 Pokemon Base Charizard #4|10",
  "card": {
    "name": "1999 Pokemon Base Charizard #4",
    "set_name": "Base Set",
    "card_number": "4",
    "grade": "PSA 10",
    "language": "EN",
    "image_url": "https://images.pricedepth.com/base-charizard-4.jpg"
  },
  "pricing": {
    "latest_price_usd": 42000.00,
    "price_date": "2026-04-09",
    "median_sale_7d": 41500.00,
    "median_sale_30d": 40800.00,
    "sales_count_7d": 2,
    "sales_count_30d": 5,
    "fair_price_usd": 41200.00,
    "outliers_removed": 1,
    "std_dev_7d": 1200.00,
    "std_dev_30d": 1850.00,
    "coefficient_of_variation_7d": 0.029,
    "coefficient_of_variation_30d": 0.045
  },
  "liquidity": {
    "score": 72,
    "sales_count_30d": 5,
    "days_since_last_sale": 3,
    "unique_sources": 3
  },
  "population": {
    "psa_10_pop": 122,
    "total_graded": 15200,
    "pop_ratio": 0.008
  },
  "sales": [
    { "sale_date": "2026-04-07", "price_usd": 42500.00, "source": "marketplace", "sale_type": "sold" },
    { "sale_date": "2026-04-02", "price_usd": 41200.00, "source": "auction_house", "sale_type": "sold" }
  ],
  "sales_capped": false,
  "meta": {
    "days": 30,
    "grade_filter": null,
    "generated_at": "2026-04-10T15:00:00.000Z"
  }
}

Population Data

GET /v1/cards/:id/population API Key

PSA population report for a card — total graded, grade distribution, and report dates.

ParamTypeDescription
limitintMax results (default: 50, max: 200)
graderstringOptional. Filter by grading company.
Response
{
  "card_id": "1999 Pokemon Base Charizard #4|10",
  "population": [
    { "report_date": "2026-04-01", "grader": "PSA", "grade": "10", "pop_count": 122, "total_graded": 15200 },
    { "report_date": "2026-04-01", "grader": "PSA", "grade": "9",  "pop_count": 2150, "total_graded": 15200 }
  ],
  "total": 2
}

Portfolio Valuation

POST /v1/portfolio/value API Key

Batch valuation for up to 500 card positions.

Request body
{
  "positions": [
    { "card_id": "1999 Pokemon Base Charizard #4|10", "quantity": 2 },
    { "card_id": "1999 Pokemon Jungle Pikachu #60|9", "quantity": 1 }
  ]
}
Response
{
  "positions": [
    {
      "card_id": "1999 Pokemon Base Charizard #4|10",
      "quantity": 2,
      "price_usd": 42000.00,
      "value_usd": 84000.00
    },
    {
      "card_id": "1999 Pokemon Jungle Pikachu #60|9",
      "quantity": 1,
      "price_usd": 85.00,
      "value_usd": 85.00
    }
  ],
  "total_value_usd": 84085.00
}
POST /v1/portfolio/pnl API Key

Portfolio P&L summary with cost basis. Returns per-position gains/losses and aggregate summary.

Request body
{
  "positions": [
    { "card_id": "1999 Pokemon Base Charizard #4|10", "quantity": 1, "purchase_price": 35000 },
    { "card_id": "1999 Pokemon Base Charizard #4|9", "quantity": 2, "purchase_price": 3200 }
  ]
}
Response
{
  "summary": {
    "total_invested": 41400.00,
    "total_current_value": 49600.00,
    "total_pnl": 8200.00,
    "total_pnl_pct": 19.81,
    "winners": 2,
    "losers": 0,
    "best_performer": { "card_id": "1999 Pokemon Base Charizard #4|10", "pnl_pct": 20.0 },
    "worst_performer": { "card_id": "1999 Pokemon Base Charizard #4|9", "pnl_pct": 18.75 }
  },
  "positions": [
    {
      "card_id": "1999 Pokemon Base Charizard #4|10",
      "quantity": 1,
      "purchase_price": 35000,
      "current_price": 42000.00,
      "cost_basis": 35000.00,
      "current_value": 42000.00,
      "pnl": 7000.00,
      "pnl_pct": 20.0
    }
  ]
}

purchase_price is required for each position. Max 500 positions per request.

Batch Pricing

POST /v1/prices/batch API Key

Look up the latest price for up to 500 cards in a single request.

Request body
{
  "card_ids": [
    "1999 Pokemon Base Charizard #4|10",
    "1999 Pokemon Jungle Pikachu #60|9"
  ]
}
Response
{
  "prices": {
    "1999 Pokemon Base Charizard #4|10": { "price_usd": 42000.00, "price_date": "2026-04-09" },
    "1999 Pokemon Jungle Pikachu #60|9": { "price_usd": 85.00, "price_date": "2026-04-09" }
  },
  "found": 2,
  "missing": []
}
GET /v1/prices/all Enterprise

Paginated bulk export of all latest card prices. Available on the Enterprise plan.

ParamTypeDescription
pageintPage number (default: 1)
limitintResults per page (default: 100, max: 1000)

Price Alerts

POST /v1/alerts API Key

Create a price alert. Triggers email when condition is met.

FieldTypeDescription
card_idstringRequired. Card to monitor.
alert_typestringabove, below, or percent_change
threshold_valuenumberPrice threshold (USD) or percentage.
emailstringOptional. Notification email.
webhook_urlstringOptional. Webhook to POST on trigger.
Response — 201 Created
{
  "message": "Alert created for \"1999 Pokemon Base Charizard #4\"",
  "alert": {
    "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "card_id": "1999 Pokemon Base Charizard #4|10",
    "alert_type": "above",
    "threshold_value": 50000,
    "webhook_url": null,
    "email": "[email protected]",
    "is_active": true,
    "created_at": "2026-04-10T12:00:00.000Z"
  }
}
GET /v1/alerts API Key

List all alerts for your API key.

Response
{
  "alerts": [
    {
      "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
      "card_id": "1999 Pokemon Base Charizard #4|10",
      "card_name": "1999 Pokemon Base Charizard #4",
      "alert_type": "above",
      "threshold_value": 50000,
      "email": "[email protected]",
      "is_active": true,
      "last_triggered_at": null,
      "trigger_count": 0,
      "created_at": "2026-04-10T12:00:00.000Z"
    }
  ],
  "count": 1
}
DELETE /v1/alerts/:id API Key

Delete a price alert.

Arbitrage

GET /v1/arbitrage Enterprise

Cross-platform arbitrage opportunities. Compares prices across multiple marketplace sources, net of platform-specific fees.

ParamTypeDescription
min_spreadnumberMinimum profit spread % (default: 5)
limitintMax results (default: 20, max: 50)
categorystringFilter by category (optional)
Response
{
  "opportunities": [
    {
      "card_id": "1999 Pokemon Base Charizard #4|10",
      "buy": { "source": "marketplace_a", "avg_price": 39500.00, "sale_count": 5 },
      "sell": { "source": "marketplace_b", "avg_price": 44200.00, "sale_count": 3, "fee_pct": 10 },
      "net_profit_usd": 280.00,
      "spread_pct": 0.71,
      "name": "1999 Pokemon Base Charizard #4",
      "set_name": "Base Set",
      "grade": "PSA 10",
      "language": "EN",
      "image_url": "https://images.pricedepth.com/base-charizard-4.jpg"
    }
  ],
  "count": 1,
  "min_spread_pct": 5,
  "platform_fees": "platform-specific fee rates applied automatically",
  "as_of": "2026-04-10T15:00:00.000Z"
}

Live Pricing

GET /v1/cards/:id/live API Key

Real-time price + WebSocket channel info for streaming updates.

Response
{
  "card_id": "1999 Pokemon Base Charizard #4|10",
  "price_usd": 42000.00,
  "price_date": "2026-04-09",
  "ws_channel": "card:1999 Pokemon Base Charizard #4|10",
  "freshness": "daily"
}

Subscribe to the ws_channel via WebSocket at wss://pricedepth.com/ws for real-time price events.

GET /api/search No Auth

Search 64,000+ cards by name, set, or number. Public endpoint (30 req/min per IP).

ParamTypeDescription
qstringSearch query (max 100 chars)
pageintPage number (default: 1)
limitintResults per page (default: 20, max: 50)
gradestringFilter by grade
sortstringrelevance (default), price_asc, price_desc, name_asc, change_7d_asc, change_7d_desc
price_minnumberMinimum price filter (USD)
price_maxnumberMaximum price filter (USD)
verticalstringCategory filter (e.g. pokemon-tcg, sports-baseball)
product_typestringProduct type filter
groupstringSet to true to group results by card name
Response
{
  "data": [
    {
      "card_id": "1999 Pokemon Base Charizard #4|10",
      "name": "1999 Pokemon Base Charizard #4",
      "set_name": "Base Set",
      "card_number": "4",
      "grade": "PSA 10",
      "image_url": "https://images.pricedepth.com/base-charizard-4.jpg",
      "product_type": "pokemon-tcg",
      "fmv": 42000.00,
      "change_7d_pct": 3.2
    },
    {
      "card_id": "1999 Pokemon Base Charizard #4|9",
      "name": "1999 Pokemon Base Charizard #4",
      "set_name": "Base Set",
      "card_number": "4",
      "grade": "PSA 9",
      "image_url": "https://images.pricedepth.com/base-charizard-4.jpg",
      "product_type": "pokemon-tcg",
      "fmv": 3800.00,
      "change_7d_pct": -1.5
    }
  ],
  "cards": "[deprecated mirror of data — sunset 2026-06-30]",
  "total": 24,
  "page": 1,
  "limit": 20,
  "pages": 2,
  "query": "charizard"
}
GET /api/trends/indices No Auth

Latest market index snapshot for all categories. Data sourced from unified index_history table (category aggregates use cat-* slugs).

Response
{
  "categories": [
    {
      "category": "pokemon-tcg",
      "total_market_cap": 24500000.00,
      "avg_price": 712.50,
      "median_price": 85.00,
      "card_count": 34400,
      "return_30d": 2.15,
      "return_90d": 8.42,
      "snapshot_date": "2026-04-09"
    },
    {
      "category": "sports-baseball",
      "total_market_cap": 3200000.00,
      "avg_price": 245.30,
      "median_price": 42.00,
      "card_count": 13040,
      "return_30d": -0.85,
      "return_90d": 1.20,
      "snapshot_date": "2026-04-09"
    }
  ],
  "count": 2,
  "as_of": "2026-04-10T15:00:00.000Z"
}
GET /api/trends/movers No Auth

Top gainers and losers by 7-day price change.

Response
{
  "gainers": [
    {
      "card_id": "2002 Pokemon Expedition Charizard #6|10",
      "current_price": 5200.00,
      "previous_price": 4400.00,
      "return_7d": 18.18,
      "abs_change": 800.00,
      "name": "2002 Pokemon Expedition Charizard #6",
      "set_name": "Expedition",
      "grade": "PSA 10",
      "image_url": "https://images.pricedepth.com/expedition-charizard.jpg"
    }
  ],
  "losers": [
    {
      "card_id": "2000 Pokemon Neo Genesis Lugia #9|9",
      "current_price": 620.00,
      "previous_price": 680.00,
      "return_7d": -8.82,
      "abs_change": -60.00,
      "name": "2000 Pokemon Neo Genesis Lugia #9",
      "set_name": "Neo Genesis",
      "grade": "PSA 9",
      "image_url": null
    }
  ],
  "count": 2,
  "as_of": "2026-04-10T15:00:00.000Z"
}
GET /api/trends/summary No Auth

Market-wide stats: total cards, market value, average price. Data sourced from unified index_history (cat-all aggregate).

Response
{
  "total_cards": 64128,
  "cards_with_prices": 41205,
  "total_market_value": 28450320.50,
  "avg_price": 690.47,
  "as_of": "2026-04-10T15:00:00.000Z"
}

How card_ids Work

Every card in the PriceDepth database is identified by a card_id string. Understanding this format is essential for using the API effectively.

Format

Card IDs follow the pattern:

{psa_title}|{grade}

Where psa_title is the card's PSA certification title and grade is the numeric grade value.

Grade Values

GradeMeaning
0Raw / Ungraded
1–8PSA 1 through PSA 8
9PSA 9 (Mint)
10PSA 10 (Gem Mint)

Example card_ids

card_idDescription
1999 Pokemon Base Charizard #4|10Charizard, Base Set, PSA 10
1999 Pokemon Base Charizard #4|9Charizard, Base Set, PSA 9
1998 Pokemon Illustrator Pikachu Promo|10Pikachu Illustrator Promo, PSA 10
2000 Pokemon Neo Genesis Lugia #9|0Lugia, Neo Genesis, Raw/Ungraded

Discovering card_ids

Use the public search endpoint to find card_ids for any card. No authentication required:

cURL
curl "https://pricedepth.com/api/search?q=charizard&limit=5"

The card_id field in each result is the value you pass to all other API endpoints. For example, after finding a card via search, fetch its price:

cURL
# URL-encode the card_id (pipe character becomes %7C)
curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://pricedepth.com/v1/cards/1999%20Pokemon%20Base%20Charizard%20%234%7C10/price"

Tip: Card IDs contain special characters (|, #, spaces). Always URL-encode them when passing in URL paths or query parameters.

Tier Comparison

PlanMonthly QuotaRate LimitFeatures
Free free10010 req/min Card search, multi-source FMV, confidence scoring, 30-day history, predictions.
Collector collector1,00020 req/min Portfolio tracking, price alerts, full history, forecasts, momentum, collections, stateful portfolio CRUD.
Dealer dealer10,00060 req/min Batch matching, screener, arbitrage, multi-marketplace availability, embeddable widgets.
API api50,000120 req/min ML price predictions, risk signals, bulk lookup, white-label pricing.
Enterprise enterpriseUnlimited300 req/min ECDSA-signed feeds, fund NAV, prediction market resolver, custom SLA, bulk export, dedicated support.

Contact [email protected] to scope an institutional plan. Additional tiers (index, internal) available on request.

Embed Widget

Embed live PriceDepth data on any website with our Shadow DOM widget. No conflicts with your CSS.

HTML
<!-- Add the widget script -->
<script src="https://pricedepth.com/js/widget.js"></script>

<!-- Embed a price widget -->
<tp-price card-id="1999 Pokemon Base Charizard #4|10"></tp-price>

<!-- Compact mode -->
<tp-price card-id="1999 Pokemon Base Charizard #4|10" compact></tp-price>

<!-- Dark theme -->
<tp-price card-id="1999 Pokemon Base Charizard #4|10" theme="dark"></tp-price>

Widget Attributes

AttributeDescription
card-idRequired. Card ID or slug.
themeOptional. light (default) or dark.
compactOptional. Renders a smaller version.

Code Recipes

Copy-paste examples for common workflows. Each snippet is self-contained and runnable.

Portfolio Tracker

Search for cards, build a portfolio, and get the total value using the batch valuation endpoint.

const API_KEY = 'YOUR_API_KEY';
const BASE = 'https://pricedepth.com';

// Step 1: Search for cards to add to your portfolio
const search = await fetch(`${BASE}/api/search?q=charizard&limit=3`);
const { data } = await search.json();

// Step 2: Build positions array
const positions = data.map(card => ({
  card_id: card.card_id,
  quantity: 1
}));

// Step 3: Get total portfolio value
const valuation = await fetch(`${BASE}/v1/portfolio/value`, {
  method: 'POST',
  headers: {
    'X-Api-Key': API_KEY,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ positions })
});
const portfolio = await valuation.json();
console.log(`Total value: $${portfolio.total_value_usd}`);
portfolio.positions.forEach(p =>
  console.log(`  ${p.card_id}: $${p.price_usd} x${p.quantity}`)
);
import requests

API_KEY = 'YOUR_API_KEY'
BASE = 'https://pricedepth.com'

# Search for cards
cards = requests.get(f'{BASE}/api/search', params={'q': 'charizard', 'limit': 3}).json()['data']

# Build positions and get portfolio value
positions = [{'card_id': c['card_id'], 'quantity': 1} for c in cards]
portfolio = requests.post(
    f'{BASE}/v1/portfolio/value',
    headers={'X-Api-Key': API_KEY},
    json={'positions': positions}
).json()

print(f"Total value: ${portfolio['total_value_usd']}")
for p in portfolio['positions']:
    print(f"  {p['card_id']}: ${p['price_usd']} x{p['quantity']}")

Price Alert Monitor

Poll a card's price and print a notification when it crosses a threshold.

const API_KEY = 'YOUR_API_KEY';
const CARD_ID = '1999 Pokemon Base Charizard #4|10';
const THRESHOLD = 40000;

async function checkPrice() {
  const res = await fetch(
    `https://pricedepth.com/v1/cards/${encodeURIComponent(CARD_ID)}/price`,
    { headers: { 'X-Api-Key': API_KEY } }
  );
  const data = await res.json();
  console.log(`Current price: $${data.price_usd}`);
  if (data.price_usd <= THRESHOLD) {
    console.log(`*** BUY SIGNAL: Price dropped below $${THRESHOLD}! ***`);
  }
}

// Check every 5 minutes
setInterval(checkPrice, 5 * 60 * 1000);
checkPrice();
import requests, time
from urllib.parse import quote

API_KEY = 'YOUR_API_KEY'
CARD_ID = '1999 Pokemon Base Charizard #4|10'
THRESHOLD = 40000

while True:
    data = requests.get(
        f'https://pricedepth.com/v1/cards/{quote(CARD_ID, safe="")}/price',
        headers={'X-Api-Key': API_KEY}
    ).json()
    print(f"Current price: ${data['price_usd']}")
    if data['price_usd'] <= THRESHOLD:
        print(f"*** BUY SIGNAL: Price dropped below ${THRESHOLD}! ***")
    time.sleep(300)

Market Dashboard (No Auth Required)

Build a simple market overview using public endpoints — no API key needed.

const BASE = 'https://pricedepth.com';

// Fetch market data in parallel (no auth required)
const [summary, movers, indices] = await Promise.all([
  fetch(`${BASE}/api/trends/summary`).then(r => r.json()),
  fetch(`${BASE}/api/trends/movers`).then(r => r.json()),
  fetch(`${BASE}/api/trends/indices`).then(r => r.json()),
]);

console.log(`Market: ${summary.cards_with_prices} cards, $${summary.total_market_value.toLocaleString()}`);
console.log('\nTop Gainers:');
movers.gainers.slice(0, 3).forEach(c =>
  console.log(`  ${c.name} (${c.grade}): +${c.return_7d}%`)
);
import requests

BASE = 'https://pricedepth.com'

# Public endpoints (no auth required)
summary = requests.get(f'{BASE}/api/trends/summary').json()
movers  = requests.get(f'{BASE}/api/trends/movers').json()

print(f"Market: {summary['cards_with_prices']} cards, ${summary['total_market_value']:,.2f} total")
print('\nTop Gainers:')
for c in movers['gainers'][:3]:
    print(f"  {c['name']} ({c['grade']}): +{c['return_7d']}%")

Card Comparison Tool

Compare two cards side-by-side — price, volatility, and risk metrics.

const API_KEY = 'YOUR_API_KEY';
const cardA = '1999 Pokemon Base Charizard #4|10';
const cardB = '1999 Pokemon Base Charizard #4|9';

const res = await fetch(
  `https://pricedepth.com/v1/compare?cards=${encodeURIComponent(cardA)},${encodeURIComponent(cardB)}`,
  { headers: { 'X-Api-Key': API_KEY } }
);
const { cards } = await res.json();

cards.forEach(c => {
  console.log(`${c.name} - ${c.grade}`);
  console.log(`  Price: $${c.current_price}  |  Vol: ${c.analytics.volatility_annual}`);
  console.log(`  Sharpe: ${c.analytics.sharpe_ratio}  |  Max DD: ${c.analytics.max_drawdown_pct}%`);
});
import requests

API_KEY = 'YOUR_API_KEY'
card_a = '1999 Pokemon Base Charizard #4|10'
card_b = '1999 Pokemon Base Charizard #4|9'

data = requests.get(
    'https://pricedepth.com/v1/compare',
    headers={'X-Api-Key': API_KEY},
    params={'cards': f'{card_a},{card_b}'}
).json()

for c in data['cards']:
    print(f"{c['name']} - {c['grade']}")
    print(f"  Price: ${c['current_price']}  |  Vol: {c['analytics']['volatility_annual']}")
    print(f"  Sharpe: {c['analytics']['sharpe_ratio']}  |  Max DD: {c['analytics']['max_drawdown_pct']}%")

Set EV Calculator

Find the best sets to rip by expected value.

const API_KEY = 'YOUR_API_KEY';

const res = await fetch(
  'https://pricedepth.com/v1/sets/ev?sort=total_value&limit=10',
  { headers: { 'X-Api-Key': API_KEY } }
);
const { sets } = await res.json();

console.log('Top 10 Sets by Expected Value:\n');
sets.forEach((s, i) => {
  console.log(`${i + 1}. ${s.set_name}`);
  console.log(`   Total EV: $${s.total_value}  |  Avg: $${s.avg_card_value}  |  Coverage: ${s.coverage_pct}%`);
});
import requests

API_KEY = 'YOUR_API_KEY'

data = requests.get(
    'https://pricedepth.com/v1/sets/ev',
    headers={'X-Api-Key': API_KEY},
    params={'sort': 'total_value', 'limit': 10}
).json()

print('Top 10 Sets by Expected Value:\n')
for i, s in enumerate(data['sets'], 1):
    print(f"{i}. {s['set_name']}")
    print(f"   Total EV: ${s['total_value']}  |  Avg: ${s['avg_card_value']}  |  Coverage: {s['coverage_pct']}%")

Indexes & Oracle

Overview

PriceDepth publishes signed price indexes for the collectibles market. Each index value is computed nightly from live market data and cryptographically signed (ECDSA secp256k1), making each data point tamper-evident and independently verifiable.

Available indexes:

The public key for signature verification is published at:

https://pricedepth.com/.well-known/pricedepth-oracle.pub

Endpoints

GET /v1/indexes — List all indexes

curl https://pricedepth.com/v1/indexes | jq

Response shape:

{
  "indexes": [
    {
      "slug": "pdi-pokemon",
      "name": "PDI PSA-10 Index",
      "current_value": 987.12,
      "change_24h_pct": -0.23,
      "methodology_version": "v1.0.0",
      "as_of_timestamp": "2026-04-11T00:00:00Z"
    }
  ]
}

GET /v1/indexes/:slug — Current value + signature

curl https://pricedepth.com/v1/indexes/pdi-pokemon | jq

Response shape:

{
  "slug": "pdi-pokemon",
  "name": "PDI PSA-10 Index",
  "description": "Pokemon market index.",
  "methodology_version": "v1.0.0",
  "as_of_timestamp": "2026-04-11T00:00:00Z",
  "value": 987.12,
  "history_30d": [
    { "as_of_date": "2026-03-12", "value": 1000.00 },
    { "as_of_date": "2026-04-11", "value": 987.12 }
  ],
  "signature": "MEUCIQDexampleBase64=="
}

GET /v1/indexes/:slug/history — Time-series history

curl "https://pricedepth.com/v1/indexes/pdi-pokemon/history?from=2026-03-01&to=2026-04-11&interval=1d" | jq

Query parameters:

Show point count:

curl "https://pricedepth.com/v1/indexes/pdi-pokemon/history?interval=1d" | jq '.data | length'

GET /v1/indexes/:slug/constituents — Basket

curl https://pricedepth.com/v1/indexes/pdi-pokemon/constituents | jq '.constituents | length'

Returns the current basket with fractional weights (sum = 1.0), sorted by weight descending. Basket size is fixed per index methodology version.

Response Fields

FieldTypeDescription
valuenumberCurrent index level (base 1000 on base_date).
methodology_versionstringSemver of the computation methodology (e.g. v1.0.0). Changes trigger re-backfill.
as_of_timestampISO 8601UTC timestamp of the price snapshot used for computation.
signaturebase64 stringDER-encoded ECDSA secp256k1 signature over canonical JSON (see below).

Signature Verification

The signature field is a base64-encoded DER ECDSA secp256k1 signature. The signed payload is a canonical JSON string of exactly 4 fields in key-sorted order, whitespace-stripped:

{"as_of_timestamp":"2026-04-11T00:00:00Z","methodology_version":"v1.0.0","slug":"pdi-pokemon","value":1042.37}

Field order matters. The 4 fields are always: as_of_timestamp, methodology_version, slug, value — alphabetically sorted, no extra whitespace.

Node.js verification (using @noble/curves)

// npm install @noble/curves
import { secp256k1 } from '@noble/curves/secp256k1';
import { sha256 } from '@noble/hashes/sha256';

async function verifyIndexSignature(slug) {
  // Fetch index data
  const res = await fetch(`https://pricedepth.com/v1/indexes/${slug}`);
  const index = await res.json();

  // Fetch public key (PEM)
  const pubRes = await fetch('https://pricedepth.com/.well-known/pricedepth-oracle.pub');
  const pubPem = await pubRes.text();

  // Extract raw 65-byte uncompressed public key from PEM
  // (strip header/footer, base64-decode, skip 23-byte SubjectPublicKeyInfo prefix)
  const b64 = pubPem.replace(/-----[^-]+-----/g, '').replace(/\s/g, '');
  const der = Buffer.from(b64, 'base64');
  const pubKeyHex = der.slice(23).toString('hex'); // 04 + 32-byte X + 32-byte Y

  // Build canonical payload (4 fields, key-sorted, no whitespace)
  const canonical = JSON.stringify({
    as_of_timestamp: index.as_of_timestamp,
    methodology_version: index.methodology_version,
    slug: index.slug,
    value: index.value,
  });

  // Hash and verify
  const msgHash = sha256(Buffer.from(canonical, 'utf8'));
  const sigDer = Buffer.from(index.signature, 'base64');
  const sig = secp256k1.Signature.fromDER(sigDer);
  const valid = secp256k1.verify(sig, msgHash, pubKeyHex);

  console.log(valid ? '✓ Signature valid' : '✗ Signature INVALID');
  return valid;
}

verifyIndexSignature('pdi-pokemon');

Python verification (using cryptography package)

# pip install cryptography requests
import requests, json, base64, hashlib
from cryptography.hazmat.primitives.asymmetric.ec import (
    ECDSA, EllipticCurvePublicKey
)
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.exceptions import InvalidSignature

def verify_index_signature(slug):
    # Fetch index data
    index = requests.get(f'https://pricedepth.com/v1/indexes/{slug}').json()

    # Fetch public key (PEM)
    pub_pem = requests.get(
        'https://pricedepth.com/.well-known/pricedepth-oracle.pub'
    ).content
    public_key = serialization.load_pem_public_key(pub_pem)

    # Build canonical payload (4 fields, key-sorted, no whitespace)
    canonical = json.dumps({
        'as_of_timestamp': index['as_of_timestamp'],
        'methodology_version': index['methodology_version'],
        'slug': index['slug'],
        'value': index['value'],
    }, separators=(',', ':'))

    # Decode DER signature from base64
    sig_der = base64.b64decode(index['signature'])

    # Verify
    try:
        public_key.verify(sig_der, canonical.encode('utf-8'), ECDSA(hashes.SHA256()))
        print('✓ Signature valid')
        return True
    except InvalidSignature:
        print('✗ Signature INVALID')
        return False

verify_index_signature('pdi-pokemon')

Methodology

Full methodology documentation including inclusion rules, weighting, rebalance cadence, and base value definitions: methodology.html#indexes.

Key points:

API Playground

Make live API requests directly from the docs. Select an endpoint, fill in parameters, and hit Send. Public endpoints work without an API key.

GET Select an endpoint from the left
Response
cURL
Headers
Select an endpoint and click Send to see results

OpenAPI Spec

The full API is described by an OpenAPI 3.0.3 specification. Import into Swagger Editor or download:

cURL
curl -O https://pricedepth.com/openapi.yaml