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
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'])
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.
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:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Requests allowed per minute |
| X-RateLimit-Remaining | Requests remaining in current window |
| X-RateLimit-Reset | Unix timestamp when window resets |
| X-Monthly-Quota | Total monthly calls allowed |
| X-Monthly-Used | Calls used this billing period |
| Retry-After | Seconds 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"
}
| Status | Code | Meaning |
|---|---|---|
| 401 | INVALID_API_KEY | Missing or invalid API key |
| 403 | TIER_REQUIRED | Endpoint requires a higher tier |
| 404 | CARD_NOT_FOUND | Card ID does not exist |
| 429 | RATE_LIMIT_EXCEEDED | Per-minute rate limit hit |
| 429 | MONTHLY_QUOTA_EXCEEDED | Monthly quota exhausted |
Cards
Search and list cards in the catalog. Paginated.
| Param | Type | Description |
|---|---|---|
| q | string | Search query (max 200 chars). Supports synonym expansion and fuzzy matching. |
| page | int | Page number (default: 1) |
| limit | int | Results per page (default: 50, max: 100) |
| grade | string | Filter by grade (e.g. PSA 10) |
| category | string | Filter by category |
| product_type | string | Filter by product type (e.g. pokemon-tcg) |
| language | string | Filter by language (e.g. EN, JP) |
| set_name | string | Filter by set name |
| sport | string | Filter by sport |
| year | string | Filter by year |
| grading_company | string | Filter by grading company |
{
"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 full details for a single card.
{
"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
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.
| Param | Type | Description |
|---|---|---|
| date | string | Optional. Historical price as of this date. |
{
"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
}
Daily price time series for a card.
| Param | Type | Description |
|---|---|---|
| days | int | Number of days (default: 90, max: 365) |
{
"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 }
]
}
Grade-specific pricing with PSA population data. Shows prices across all grades (PSA 1-10) for a card.
{
"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
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.
{
"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}.
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
Compare 2-10 cards side-by-side with pricing, analytics, and liquidity data.
| Param | Type | Description |
|---|---|---|
| cards | string | Required. Comma-separated card_ids (2-10). |
{
"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
Unified comp data: recent sales, median prices, liquidity score, and PSA population — everything needed to value a card.
| Param | Type | Description |
|---|---|---|
| days | int | Lookback window (default: 30, max: 90) |
| grade | string | Optional. Filter sales by grade. |
{
"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
PSA population report for a card — total graded, grade distribution, and report dates.
| Param | Type | Description |
|---|---|---|
| limit | int | Max results (default: 50, max: 200) |
| grader | string | Optional. Filter by grading company. |
{
"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
Batch valuation for up to 500 card positions.
{
"positions": [
{ "card_id": "1999 Pokemon Base Charizard #4|10", "quantity": 2 },
{ "card_id": "1999 Pokemon Jungle Pikachu #60|9", "quantity": 1 }
]
}
{
"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
}
Portfolio P&L summary with cost basis. Returns per-position gains/losses and aggregate summary.
{
"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 }
]
}
{
"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
Look up the latest price for up to 500 cards in a single request.
{
"card_ids": [
"1999 Pokemon Base Charizard #4|10",
"1999 Pokemon Jungle Pikachu #60|9"
]
}
{
"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": []
}
Paginated bulk export of all latest card prices. Available on the Enterprise plan.
| Param | Type | Description |
|---|---|---|
| page | int | Page number (default: 1) |
| limit | int | Results per page (default: 100, max: 1000) |
Price Alerts
Create a price alert. Triggers email when condition is met.
| Field | Type | Description |
|---|---|---|
| card_id | string | Required. Card to monitor. |
| alert_type | string | above, below, or percent_change |
| threshold_value | number | Price threshold (USD) or percentage. |
| string | Optional. Notification email. | |
| webhook_url | string | Optional. Webhook to POST on trigger. |
{
"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"
}
}
List all alerts for your API key.
{
"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 a price alert.
Arbitrage
Cross-platform arbitrage opportunities. Compares prices across multiple marketplace sources, net of platform-specific fees.
| Param | Type | Description |
|---|---|---|
| min_spread | number | Minimum profit spread % (default: 5) |
| limit | int | Max results (default: 20, max: 50) |
| category | string | Filter by category (optional) |
{
"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
Real-time price + WebSocket channel info for streaming updates.
{
"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.
Search (Public)
Search 64,000+ cards by name, set, or number. Public endpoint (30 req/min per IP).
| Param | Type | Description |
|---|---|---|
| q | string | Search query (max 100 chars) |
| page | int | Page number (default: 1) |
| limit | int | Results per page (default: 20, max: 50) |
| grade | string | Filter by grade |
| sort | string | relevance (default), price_asc, price_desc, name_asc, change_7d_asc, change_7d_desc |
| price_min | number | Minimum price filter (USD) |
| price_max | number | Maximum price filter (USD) |
| vertical | string | Category filter (e.g. pokemon-tcg, sports-baseball) |
| product_type | string | Product type filter |
| group | string | Set to true to group results by card name |
{
"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"
}
Market Trends (Public)
Latest market index snapshot for all categories. Data sourced from unified index_history table (category aggregates use cat-* slugs).
{
"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"
}
Top gainers and losers by 7-day price change.
{
"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"
}
Market-wide stats: total cards, market value, average price. Data sourced from unified index_history (cat-all aggregate).
{
"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
| Grade | Meaning |
|---|---|
| 0 | Raw / Ungraded |
| 1–8 | PSA 1 through PSA 8 |
| 9 | PSA 9 (Mint) |
| 10 | PSA 10 (Gem Mint) |
Example card_ids
| card_id | Description |
|---|---|
| 1999 Pokemon Base Charizard #4|10 | Charizard, Base Set, PSA 10 |
| 1999 Pokemon Base Charizard #4|9 | Charizard, Base Set, PSA 9 |
| 1998 Pokemon Illustrator Pikachu Promo|10 | Pikachu Illustrator Promo, PSA 10 |
| 2000 Pokemon Neo Genesis Lugia #9|0 | Lugia, Neo Genesis, Raw/Ungraded |
Discovering card_ids
Use the public search endpoint to find card_ids for any card. No authentication required:
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:
# 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
| Plan | Monthly Quota | Rate Limit | Features |
|---|---|---|---|
Free free | 100 | 10 req/min | Card search, multi-source FMV, confidence scoring, 30-day history, predictions. |
Collector collector | 1,000 | 20 req/min | Portfolio tracking, price alerts, full history, forecasts, momentum, collections, stateful portfolio CRUD. |
Dealer dealer | 10,000 | 60 req/min | Batch matching, screener, arbitrage, multi-marketplace availability, embeddable widgets. |
API api | 50,000 | 120 req/min | ML price predictions, risk signals, bulk lookup, white-label pricing. |
Enterprise enterprise | Unlimited | 300 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.
<!-- 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
| Attribute | Description |
|---|---|
| card-id | Required. Card ID or slug. |
| theme | Optional. light (default) or dark. |
| compact | Optional. 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:
- pdi-100 — Broad market index (top 100 cards by market cap).
- pdi-psa10 — PSA 10 gem mint index.
- cat-pokemon-tcg — Pokemon TCG category index.
- cat-sports-baseball — Baseball category index.
- cat-sports-basketball — Basketball category index.
- cat-sports-football — Football category index.
- cat-all — Market-wide aggregate.
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:
from— Start date YYYY-MM-DD (default: 30 days ago)to— End date YYYY-MM-DD (default: today)interval—1d(default),1w, or1m
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
| Field | Type | Description |
|---|---|---|
value | number | Current index level (base 1000 on base_date). |
methodology_version | string | Semver of the computation methodology (e.g. v1.0.0). Changes trigger re-backfill. |
as_of_timestamp | ISO 8601 | UTC timestamp of the price snapshot used for computation. |
signature | base64 string | DER-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:
- Methodology version bumps with any rule change and trigger a full re-backfill.
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.
OpenAPI Spec
The full API is described by an OpenAPI 3.0.3 specification. Import into Swagger Editor or download:
curl -O https://pricedepth.com/openapi.yaml