# Tradepost pricing API This site publishes two separate datasets: sealed-TCG retail comparisons with 30-day sales and supported MSRP/retail evidence, and the complete public Tradepost market catalog with 90-day completed-sale history and no retail supplementation. The collection engine runs on the Driver host. Cloudflare Pages serves its published results. API requests never initiate collection or change data. Use the origin hosting this file as BASE_URL. This guide is also at /llms.txt. The existing /api/products endpoints below are the retail-comparison dataset. The /api/market/* endpoints are the wider market dataset. Their sales windows and pagination differ: retail exports contain all matches; market lists contain one bounded page. Never describe a 90-day market total as a 30-day retail total. ## Endpoints - GET /api/products — filtered JSON; default view is comparisons. - GET /api/products?format=csv — the same matching rows as CSV. - GET /api/products.json and /api/products.csv — explicit format aliases. - GET /api/status — version, deployed Git commit (on Cloudflare), product count, generated_at, market_snapshot_at, and stale (market data older than 36 hours). - GET /data/manifest.json — complete snapshot metadata, pricing policy, coverage, and relative paths/checksums/counts of the static JSON shards. - GET /data/{version}/{shard.file} — raw product rows, read from manifest.shards. - GET /retail/matches.csv — all products using the snapshot's default policy. - GET /retail/ranked-comparisons.csv — supported comparisons with recent sales. - GET /retail/review-queue.csv — products with unresolved review reasons. - GET /retail/sold-comparisons.csv — all products with recent sales, including unpriced. - GET /retail/quality-summary.json — coverage and known evidence gaps. - GET / — interactive pricing explorer, with shareable filters and downloads. /retail/report.json and /retail/report.csv remain compatible export aliases. GET and HEAD are supported. OPTIONS provides CORS preflight for read-only clients. The default deployment is publicly readable, even when its GitHub repository is private. Deployments protected by Cloudflare Access require the operator's access method; do not attempt to bypass it. No trading or write endpoints exist. ## Query parameters Parameters are case-sensitive. URL-encode values. Unknown parameters, duplicates, invalid values, and conflicts between format and file extension return HTTP 400. | Parameter | Meaning and default | | --- | --- | | view | comparisons (default), all, or review | | q | Case-insensitive substring of product name, set, or Tradepost ID | | game | Exact game value from product rows or the manifest's summary; omit for all | | package | unit, case, display, or set; omit for all | | min_sales | Minimum units sold over 30 days, inclusive; 1 for comparisons, 0 otherwise | | min_spread | Minimum gross spread in USD, inclusive; omit for no minimum; may be negative | | sort | volume_usd_30d (default), units_sold_30d, name, baseline_usd, tradepost_last_usd, tradepost_avg_usd, gross_spread_usd, markup_pct, gross_margin_pct | | direction | desc (default) or asc; missing prices remain last | | tiers | Optional comma-separated baseline tier order, with no duplicates | | retail_age | Optional maximum retail evidence age in days, greater than 0 and at most 3650 | | format | json (default) or csv; explicit extension aliases must agree | | page | UI page, positive integer; accepted for shared links but does NOT truncate exports | | page_size | UI rows per page, 1–1000, default 50; does NOT truncate exports | Every JSON/CSV export includes ALL matching products in the requested order. Use filters to reduce downloads. To iterate the full catalog efficiently, fetch the manifest once, pin its version, and read its listed static shards. If any shard is unavailable during a deployment change, restart with the new manifest; never combine rows from two versions. Baseline tiers: manufacturer-msrp, walmart-direct, target-direct, manufacturer-direct, other-first-party-retail, distributor-msrp, reported-msrp, reported-retail, derived-package. Use the published baseline_preferences unless the user specifically wants a different policy. Changing tiers recalculates the selected baseline, spread, markup, margin, and review eligibility consistently. ## Examples /api/products?min_sales=100&min_spread=10 /api/products.csv?min_sales=100&min_spread=10&sort=gross_spread_usd&direction=desc /api/products?view=all&q=booster&game=pokemon&package=unit /api/products?view=review&min_sales=1 /api/products?view=all&sort=name&direction=asc&format=csv JavaScript: const url = new URL('/api/products', BASE_URL); url.search = new URLSearchParams({min_sales: '100', min_spread: '10'}); const response = await fetch(url); if (!response.ok) throw new Error(`Tradepost API ${response.status}`); const result = await response.json(); console.log(result.count, result.market_snapshot_at, result.rows); JSON envelope: {"count":123,"filters":{},"generated_at":"ISO timestamp", "market_snapshot_at":"ISO timestamp","baseline_preferences":{},"rows":[]} The count is illustrative; use the live result. A valid filter with no matches returns HTTP 200, count 0, and rows []; CSV returns its header only. Responses include X-Tradepost-Version and X-Tradepost-Market-Snapshot. Unexpected missing snapshot data returns HTTP 503; retain the last good result instead of treating an error as an empty catalog. ## Field meanings - tradepost_id: stable source product ID. Distinguish language, edition, and package. - baseline_usd: supported reference cost selected by the pricing policy, not an assertion that the product is currently available for purchase at that price. - tradepost_last_usd / tradepost_avg_usd: last completed sale / 30-day average. - units_sold_30d: number of units sold, NOT number of transactions. - volume_usd_30d: reported 30-day dollar volume. - gross_spread_usd = last sale minus baseline. - markup_pct = spread divided by baseline, multiplied by 100. - gross_margin_pct = spread divided by last sale, multiplied by 100. - baseline_candidates, baseline_source_id, baseline_url, baseline_calculation, baseline_checked_at, package_facts_json: evidence and package arithmetic. - baseline_preference_hash: SHA-256 of the effective pricing policy (sorted, compact JSON), recalculated for custom tiers/retail_age. Whole-number ages normalize to integers, so 30 and 30.0 identify the same policy. Included in JSON rows and the final CSV column. Static shards use the snapshot policy. - baseline_rejections: candidate IDs and reasons they are ineligible under the effective policy; available in JSON rows. - review_reason, baseline_gap_reason, research_next_action: unresolved evidence, updated with policy changes. An empty gap means a baseline was selected. Prices and percentages can be decimal strings. Missing values can be absent or empty; never turn an unknown baseline or spread into zero. Comparisons exclude unresolved baselines and flagged market anomalies. A min_spread filter excludes unknown spreads. Figures are gross, before fees, shipping, and taxes. Tradepost's own retail-price metadata is not automatically manufacturer MSRP. ## Freshness and refreshes The intended cadence is twice daily, plus explicit Driver requests. Check market_snapshot_at for when Tradepost data was collected; generated_at is when the report was calculated. Individual reference-price evidence has its own date. A fresh market snapshot does not imply every retail/MSRP source was fetched again. The existing collector fetches the full catalog each run. To refresh, ask Driver in its configured Slack channel. Driver collects locally, validates the snapshot, updates the private repository's main branch, and checks Pages deployment separately. A successful Git push is not yet a successful Pages deployment. Failed collection/validation leaves the prior published site intact. ## Market universe and product histories The public category list is discovered on each collection. Empty categories remain listed with count 0; they are not collection failures. Use the live metadata for coverage. This dataset includes sealed TCG alongside the other public categories. It contains no selected retail baseline, MSRP enrichment, spread or margin. - GET /market — separate market-only browser, with category/search/sales filters. - GET /product?id={tradepost_id}&category={category_slug} — dedicated product page with an interactive 90-day chart, 30-day view, price line, units/volume bars, dated tooltips and a daily data table. A product with no reported sales has an explicit empty history; no price line is invented. - GET /api/market/status — market version, deployed commit, total catalog count, sold_products, start_date, end_date, market_snapshot_at, stale, period_days=90, and retail_supplemented=false. - GET /api/market/categories — the same metadata plus category IDs, slugs, names, product counts and counts with reported 90-day sales. - GET /api/market/products — one page of matching market products as JSON. - GET /api/market/products.csv or ?format=csv — the SAME page as CSV. - GET /api/market/products/{tradepost_id}?category={slug} — one complete product, including attributes and its history array. Category is optional but speeds lookup. - GET /api/market/products/{tradepost_id}/history.csv?category={slug} — all reported daily sales buckets for that product's source 90-day window, as CSV. - GET /market-data/manifest.json — static bulk manifest. Pin its version and fetch each listed file at /market-data/{version}/{shard.file}. These files contain the entire catalog, including product histories and products without sales. Market list parameters: | Parameter | Meaning and default | | --- | --- | | category | Exact slug from /api/market/categories, or all (default) | | q | Case-insensitive substring of product name, collection, ID or attribute values | | min_sales | Inclusive minimum units sold in 90 days; 0 (default) includes no-sales products | | sort | volume_usd_90d (default), units_sold_90d, last_sale_usd, average_sale_usd_90d, price_change_pct_90d, name | | direction | desc (default) or asc; unknown values remain last | | limit | 1–500; default 50 | | offset | 0-based result offset; default 0; offset + limit must be at most 10000 | | format | json (default) or csv; must agree with a filename extension if provided | | version | Optional expected market version; a mismatch returns HTTP 409 | The UI initially uses min_sales=1 to show traded products; the API defaults to 0. List JSON contains count (ALL matches), returned (rows on this page), filters, next_offset, bulk_manifest, version, market_snapshot_at, period_days and rows. List rows omit history to keep responses small. Fetch the product endpoint for it. X-Total-Count and Link: rel=next are exposed to browser clients for both formats. Pin version on subsequent requests so a new deployment returns 409 instead of silently mixing pages. Narrow filters before exceeding the 10,000-result window; use the static manifest/shards to download or traverse the complete catalog. Examples: /api/market/products?category=sealed-wax&min_sales=1&limit=50 /api/market/products?category=trading-card&q=pikachu&min_sales=0 /api/market/products.csv?category=lego&min_sales=1&sort=units_sold_90d /api/market/products?category=ticket&limit=50&offset=50 Product response: metadata plus product. product.history contains source daily aggregates with date (UTC), average_price_usd, units_sold, volume_usd and trade_count. These are completed-sale daily averages, not individual transaction prices and not listed/asking prices. Dates without reported trades are omitted. Source windows can include two partial boundary dates (up to 91 UTC daily buckets for a rolling 90-day request). Chart gaps must not become zero-price observations. Product summary fields: last_sale_usd, average_sale_usd_90d, units_sold_90d, volume_usd_90d, price_change_pct_90d, vaulted_available_units. Monetary values are decimal strings; missing prices and unavailable percentage changes are null. Product identity distinguishes category, language, printing, package and variety. attributes are source catalog metadata, not reviewed retail evidence. The retail /api/status also exposes market_version, market_count and market_universe_snapshot_at. Retail and wider-market collection times may differ; use each dataset's own timestamp. Driver validates both snapshots before publishing them together. It never silently substitutes a partial universe for a failed import.