{"openapi":"3.1.0","info":{"title":"gpufax API","version":"1.0.0","description":"Free JSON API for the used-GPU market: per-configuration asking-price statistics with a labeled sold slice, quality-gated live listing search with deep links, single-listing trust checks, verified card-health reports, and standing listing alerts.\n\nEvery response is `{ data, meta }` (or `{ error, meta }`): meta carries `as_of`, `source`, `docs`, and — on price-carrying endpoints — `attribution`. Prices ship as two labeled slices, never blended: the asking band from live listings (`price_basis: \"asking\"`, field names say `_ask`) and — where present — a `sold` block with verified-sale stats and a sale estimate labeled by `sold.basis` (\"direct\" = percentiles over verified sales, \"calibrated\" = the ask band scaled by a measured, disclosed clearance ratio). Preserve the labels when citing.\n\nIdentity is graduated, never a wall: anonymous per-IP limits → an instant free key (`POST /api/v1/keys`, returned in-response, no email) at roughly 10× limits. Honest `429`s carry `Retry-After` and `X-RateLimit-*` headers.\n\nThe same five task tools are served over MCP (streamable HTTP, authless) at https://gpufax.com/mcp — registry name com.gpufax/gpufax.\n\nAttribution: cite results as \"gpufax\" linking the `html_url`/`gpufax_url` in the payload. Listings must keep their deep link to the source marketplace. Bulk export and catalog replication are not offered at any tier.","contact":{"url":"https://gpufax.com/developers","email":"support@gpufax.com"},"termsOfService":"https://gpufax.com/terms"},"servers":[{"url":"https://gpufax.com"}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"Optional free API key (gfx_…)."},"apiKeyHeader":{"type":"apiKey","in":"header","name":"X-Api-Key"},"apiKeyQuery":{"type":"apiKey","in":"query","name":"api_key"}},"schemas":{"Listing":{"type":"object","description":"One live listing, display-grade: what a gpufax catalog card shows, plus the deep link to the source marketplace where the purchase actually happens.","properties":{"id":{"type":"string","description":"Stable gpufax listing id (works with check-listing)."},"title":{"type":"string","description":"'EVGA RTX 3080'"},"spec":{"type":["string","null"],"description":"'24GB · mining use disclosed'; null when the title says it all."},"asking_price_usd":{"type":["integer","null"]},"price_basis":{"type":"string","const":"asking"},"channel":{"type":"string","description":"eBay, Craigslist, OfferUp, Facebook Marketplace, Reddit, gpufax"},"url":{"type":"string","description":"Deep link to the source listing — send the buyer here."},"gpufax_url":{"type":"string","description":"The gpufax listing page (staleness notes, report badge)."},"config_key_l0":{"type":["string","null"],"description":"Family rollup, e.g. nvidia-rtx-30."},"config_key_l1":{"type":["string","null"],"description":"Exact SKU, e.g. nvidia-rtx-3090."},"vendor":{"type":["string","null"],"enum":["nvidia","amd","intel",null]},"chip":{"type":["string","null"]},"vram_gb":{"type":["integer","null"]},"aib_brand":{"type":["string","null"],"description":"Board partner (ASUS, EVGA, MSI, …) — a facet, never part of the config key."},"cooler_type":{"type":["string","null"]},"mining_flag":{"type":"boolean","description":"Disclosed mining-use facet: the listing's own mining/ex-mining language, surfaced as a badge and a filter. Tainted listings are disclosed, never silently dropped."},"condition":{"type":["string","null"]},"location":{"type":["string","null"]},"first_seen":{"type":"string","format":"date-time"},"last_confirmed":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["active","sold","delisted","removed","expired"]},"trust_tier":{"type":"string","enum":["premium","free","listed"],"description":"premium/free = a verified gpufax report is attached; listed = no report."},"report_url":{"type":["string","null"]},"featured":{"type":"boolean"}}},"Band":{"type":["object","null"],"description":"Asking-price band. level says how exact: l1 = this exact SKU, l0 = the whole family line. Null = no live comps — read it as not enough data, never as zero.","properties":{"level":{"type":"string","enum":["l1","l0"]},"config_key":{"type":"string"},"median_ask":{"type":"integer"},"p25_ask":{"type":"integer"},"p75_ask":{"type":"integer"},"n":{"type":"integer","description":"Live comps behind the numbers — cite it."},"n_sold":{"type":"integer","description":"Verified BIN sales behind median_sold (quality-gated, 90-day window). 0 unless the sold band resolves at least as deep as this band — the full picture is the sold object beside the band."},"median_sold":{"type":["integer","null"],"description":"Median verified sold price at this band's level, present when n_sold >= 5. See the sold object for basis, window and the sale estimate."}}},"Sold":{"type":"object","description":"The sold slice (doc: /developers). Verified-sale stats plus one sale estimate, labeled by basis and never blended into the asking band.","properties":{"window_days":{"type":"integer","description":"Sold-side window the stats cover."},"direct":{"type":["object","null"],"description":"Deepest quality-gated sold band for the config: >= 5 verified BIN sales in the window. Null when sales are too thin.","properties":{"level":{"type":"string","enum":["l1","l0"]},"median":{"type":"integer"},"p25":{"type":"integer"},"p75":{"type":"integer"},"n":{"type":"integer","description":"Verified sales behind the numbers — cite it."}}},"basis":{"type":["string","null"],"enum":["direct","calibrated",null],"description":"What produced estimated_sale: 'direct' = the sold percentiles themselves; 'calibrated' = the asking band scaled by ratio_to_ask; null = no honest basis, no estimate."},"ratio_to_ask":{"type":["number","null"],"description":"Clearance ratio applied when basis is 'calibrated': median sold / median live ask, measured per config bucket and aggregated, clamped to [0.6, 1.0]. Null on direct."},"estimated_sale":{"type":["object","null"],"description":"The sale estimate (mid/low/high, whole USD). Null when basis is null.","properties":{"mid":{"type":"integer"},"low":{"type":"integer"},"high":{"type":"integer"}}}}},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}},"meta":{"type":"object"}}}}},"security":[{},{"bearer":[]},{"apiKeyHeader":[]},{"apiKeyQuery":[]}],"paths":{"/api/v1/price-stats":{"get":{"operationId":"get_gpu_price_stats","summary":"Asking + sold price statistics for a GPU configuration","description":"What a used GPU configuration is listed for right now and what it actually sells for. The band is the live asking side: median/p25/p75 with sample size, per-channel medians, launch MSRP retention. The sold block carries verified-sale percentiles when the config has enough recent sales (sold.basis \"direct\"; n and window_days ride along), else the asking band scaled by a measured clearance ratio (sold.basis \"calibrated\", ratio_to_ask disclosed). Use asking to set a list price, the sold estimate to set expectations or an offer. The slices are never blended — preserve the basis label when you cite. Rate limits: 30/min and 1000/day per anonymous IP; 300/min and 10000/day with a free key.","parameters":[{"name":"config","in":"query","required":true,"description":"gpufax config key: vendor-chip, with a VRAM variant where real variants diverge, or a family rollup. Examples: nvidia-rtx-3090, nvidia-rtx-3060-12gb, nvidia-a100-80gb-pcie, nvidia-rtx-30 (family). Off-catalog keys are rejected — discover keys via /api/v1/listings or /shop.","schema":{"type":"string"}}],"responses":{"200":{"description":"Band + sold slice + channels + MSRP context (band may be null = not enough data; sold.basis null = no honest sale estimate)."},"400":{"description":"Malformed or off-catalog config key."},"429":{"description":"Rate limited — honor Retry-After."}}}},"/api/v1/listings":{"get":{"operationId":"search_gpu_listings","summary":"Search live used-GPU listings across marketplaces","description":"Quality-gated live listings aggregated from eBay, Craigslist, OfferUp, Facebook and Reddit — scam clusters, junk titles, classified-ad bait, auctions and stale/sold rows are already filtered out. Mining-tainted cards stay in with a disclosed mining_flag facet (filter it either way). Every row deep-links to the source listing; the buyer completes the purchase there. Page depth is capped (offset ≤ 480) — this is a buying tool, not a bulk feed. Rate limits: 20/min and 500/day per anonymous IP; 200/min and 5000/day with a free key.","parameters":[{"name":"config","in":"query","schema":{"type":"string"},"description":"gpufax config key: vendor-chip, with a VRAM variant where real variants diverge, or a family rollup. Examples: nvidia-rtx-3090, nvidia-rtx-3060-12gb, nvidia-a100-80gb-pcie, nvidia-rtx-30 (family). Off-catalog keys are rejected — discover keys via /api/v1/listings or /shop. An exact SKU key filters that SKU; a family key filters the whole line."},{"name":"vendor","in":"query","schema":{"type":"string","enum":["nvidia","amd","intel"]}},{"name":"vram_gb","in":"query","schema":{"type":"integer"}},{"name":"aib_brand","in":"query","schema":{"type":"string"},"description":"Board partner, case-insensitive exact: ASUS, EVGA, MSI, …"},{"name":"mining_flag","in":"query","schema":{"type":"boolean"},"description":"true = only listings with disclosed mining use; false = only listings without the disclosure. Omit for all (tainted rows always carry the flag on the row)."},{"name":"max_price_usd","in":"query","schema":{"type":"integer"}},{"name":"min_tier","in":"query","schema":{"type":"string","enum":["listed","free","premium"]},"description":"free/premium = only listings with a verified gpufax report attached."},{"name":"sort","in":"query","schema":{"type":"string","enum":["fresh","price_asc","price_desc"]}},{"name":"limit","in":"query","schema":{"type":"integer","maximum":50}},{"name":"offset","in":"query","schema":{"type":"integer","maximum":480}}],"responses":{"200":{"description":"Listings + page info."},"400":{"description":"Bad filter or page depth over the cap."},"429":{"description":"Rate limited."}}}},"/api/v1/check-listing":{"get":{"operationId":"check_gpu_listing","summary":"Check one listing before trusting it","description":"\"Should I trust this listing?\" — pass the listing URL (or a gpufax listing id) and get: whether gpufax knows it, whether it still passes every quality gate, its scam/junk/classified/auction flags, when a scan last verified it live, its ask against the configuration's typical asking band, the disclosed mining-use facet, and whether a verified gpufax report is attached. Facts, not verdicts — relay the numbers. Rate limits: 20/min and 500/day per anonymous IP; 200/min and 5000/day with a free key.","parameters":[{"name":"url","in":"query","schema":{"type":"string"},"description":"The listing's URL on the source marketplace."},{"name":"id","in":"query","schema":{"type":"string"},"description":"A gpufax listing id (from search results)."}],"responses":{"200":{"description":"Check result; known:false when gpufax hasn't indexed the listing."},"400":{"description":"Neither url nor id supplied."},"429":{"description":"Rate limited."}}}},"/api/v1/reports/{reportId}":{"get":{"operationId":"get_gpu_report","summary":"Fetch a verified gpufax card-health report","description":"The machine twin of a gpufax report page: hardware-read identity (GPU UUID, PCB serial where the SKU records one), VBIOS/InfoROM/driver versions, persisted wear counters as NVIDIA's tools report them, and the signing chain. Null wear fields mean the SKU doesn't record that counter — not zero. status \"superseded\" means the same card was re-verified more recently under a newer report — treat the payload as historical state, not current. Rate limits: 30/min and 1000/day per anonymous IP; 300/min and 10000/day with a free key.","parameters":[{"name":"reportId","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-hjkmnp-tv-z]{8}$"}}],"responses":{"200":{"description":"The report."},"404":{"description":"No such report."},"429":{"description":"Rate limited."}}}},"/api/v1/alerts":{"post":{"operationId":"create_gpu_alert","summary":"Create a standing listing alert (email, human-confirmed)","description":"Watch the market for a configuration: a daily email when new matching listings appear. CONSENT CONTRACT: create an alert only for a user who explicitly asked for this alert on this email address. The first alert for a new email is created as pending_confirm and activates only when the email's owner clicks the confirmation link — nothing sends before that, and unconfirmed alerts don't exist for any other purpose. Every alert email carries manage + unsubscribe links. Per-email creation is capped at 5/day. Rate limits: 5/min and 20/day per anonymous IP; 10/min and 40/day with a free key.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","config"],"properties":{"email":{"type":"string","format":"email"},"config":{"type":"string","description":"gpufax config key: vendor-chip, with a VRAM variant where real variants diverge, or a family rollup. Examples: nvidia-rtx-3090, nvidia-rtx-3060-12gb, nvidia-a100-80gb-pcie, nvidia-rtx-30 (family). Off-catalog keys are rejected — discover keys via /api/v1/listings or /shop."},"vram_gb":{"type":"integer","description":"VRAM tightener for family-key alerts."},"max_price_usd":{"type":"integer"},"min_tier":{"type":"string","enum":["listed","free","premium"]},"under_typical":{"type":"boolean","description":"Only listings under the config's typical asking range (p25 gate)."}}}}}},"responses":{"201":{"description":"Created — status is active or pending_confirm."},"400":{"description":"Invalid email or config."},"429":{"description":"Rate limited (per-caller or per-email)."}}}},"/api/v1/keys":{"post":{"operationId":"create_api_key","summary":"Mint an instant free API key","description":"Anonymous → identified in one request: the key comes back in the response (shown once, stored hashed), no email, no account. Free keys raise read limits roughly 10×. Rate limits: 2/min and 5/day per anonymous IP; 2/min and 5/day with a free key.","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":120}}}}}},"responses":{"201":{"description":"The key — store it now."},"429":{"description":"Key-minting rate limited."}}}},"/api/v1/configs/{config}":{"get":{"operationId":"get_gpu_config","summary":"A config page, as data","description":"The machine twin of /shop/<config> (also served at /shop/<config>.json): asking band + sold slice, inventory facets, the freshest live listings with deep links, buyer demand signal, and other configurations with live inventory. Rate limits: 20/min and 500/day per anonymous IP; 200/min and 5000/day with a free key.","parameters":[{"name":"config","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The config's market state."},"400":{"description":"Malformed config key."},"404":{"description":"No such GPU configuration in the gpufax catalog."},"429":{"description":"Rate limited."}}}},"/api/v1/briefs/{month}":{"get":{"operationId":"get_market_brief_csv","summary":"A monthly market brief's data, as CSV","description":"The data behind gpufax.com/market/<YYYY-MM> (also served at /market/<YYYY-MM>.csv): per-configuration snapshot statistics — live inventory, asking-price percentiles, flow counts, days on market, dollars per GB of VRAM, channel mix. Aggregates only, pinned to the month's first snapshot date, never restated. Rate limits: 30/min and 500/day per anonymous IP; 300/min and 5000/day with a free key.","parameters":[{"name":"month","in":"path","required":true,"schema":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"}}],"responses":{"200":{"description":"CSV (text/csv)."},"404":{"description":"No snapshot data for that month."},"429":{"description":"Rate limited."}}}}}}