{"api":"nft","chains":[{"slug":"eth","name":"Ethereum","status":"live"},{"slug":"base","status":"planned"},{"slug":"polygon","status":"planned"}],"freshness_model":{"how_it_works":"There is ONE tier. Cache windows are set per KIND of data from each upstream's measured refresh rate, and every response tells you how old its data is so you can decide for yourself.","windows":{"floor_prices":"120s — the fastest-moving number here.","marketplace_trades":"900s — event-driven upstream (~7 sales/day on a blue chip).","wallet_holdings":"900s — changes only when the wallet transacts.","metadata_traits_rarity":"86400s — the vendor re-ingests daily, so shorter buys nothing.","spam_classification":"86400s — the upstream ships no timestamp and moves on its own schedule."},"never_cached":["/nft/:chain/verify-ownership — ownership is realtime by nature.","/nft/:chain/collection/search — a cheap entry-point lookup.","/nft/:chain/collection/:address/pulse — a momentum snapshot with cursor deltas."],"note":"Every response carries freshness: { tier, max_age_seconds, as_of, age_seconds }. age_seconds is the bound to act on: escalate or re-poll when it exceeds what your use case tolerates.","why_no_live_tier":"We used to sell a pricier /live sibling that bypassed our cache. Measured over ~50 minutes against six upstreams, two calls minutes apart returned byte-identical payloads — it bought a fresher fetch, not fresher data. Removed 2026-08-02; the cache windows above and age_seconds replace it for every caller."},"tools":[{"path":"/nft/:chain/collection/search?q=<name>","returns":"ALWAYS LIVE name → contract lookup: top ~10 matches with address, symbol, supply, OpenSea verification, spam flag, and links into every other endpoint. The entry point when an agent knows a name, not an address."},{"path":"/nft/:chain/collection/:address","returns":"Collection identity card: name, symbol, supply, deployer, OpenSea metadata + floor."},{"path":"/nft/:chain/collection/:address/scam-check","returns":"Deterministic scam checklist: spam flags, safelist status, collection age, metadata storage class, ownership concentration, name/symbol collision vs famous collections. Verdict + evidence, never scores."},{"path":"/nft/:chain/asset/:address/:tokenId","returns":"Asset health: owner(s), token URI + storage durability grade, image URLs/content type, spam inheritance. Optional ?check_image=1 HEAD-checks the image is live."},{"path":"/nft/:chain/verify-ownership?wallet=&contract=&tokenId=","returns":"ALWAYS LIVE holds-or-not check — token-gating for agent auth flows."},{"path":"/nft/:chain/collection/:address/stats","returns":"Supply, owner count, unique-owner ratio, top-10 concentration, per-marketplace floor."},{"path":"/nft/:chain/wallet/:address","returns":"Wallet NFT portfolio (first 100 items, honest truncated flag + totalCount): per-item contract, tokenId, name, collection, spam flag; rollup totalCount + spamCount."},{"path":"/nft/:chain/wallet/:address/collections","returns":"Collection-level portfolio rollup: address, name, symbol, totalBalance, spam flag per collection."},{"path":"/nft/:chain/wallet/:address/scam-exposure","returns":"How much of this wallet's NFT holdings is junk/copymint: verdict CLEAN | SPAM_HOLDINGS_FOUND with per-holding evidence (Alchemy spam flag, famous-collection name/symbol collision)."},{"path":"/nft/:chain/asset/:address/:tokenId/rarity","returns":"Trait rarity for one token (method=alchemy_computeRarity) + the derived rarest trait."},{"path":"/nft/:chain/collection/:address/traits","returns":"Full trait distribution table (trait type → value → count) + totalSupply."},{"path":"/nft/:chain/collection/:address/sales","returns":"Recent sales, normalized (marketplace, tokenId, buyer, seller, price as decimal string + symbol, block, tx) + summary: count, median price, marketplace breakdown. ?limit= up to 100 (default 50)."},{"path":"/nft/:chain/asset/:address/:tokenId/sales","returns":"Price history for ONE token, same normalization; an empty history is a valid state (\"NO_SALES_RECORDED\")."},{"path":"/nft/:chain/asset/:address/:tokenId/provenance","returns":"Provenance-lite: current owners, mint info when the upstream exposes it (often null — honestly noted), and per-token sales history. Full transfer-chain reconstruction is honestly not_checked."},{"path":"/nft/:chain/collection/:address/wash-check","returns":"Deterministic wash-trade heuristics over a ≤24h-cached window of up to 300 recent sales: round-trip cycles, ≥10-trade pair churn, self-purchases. Verdict + per-rule evidence — indicators, not accusations."},{"path":"/nft/:chain/asset/:address/:tokenId/wash-check","returns":"Same wash rules over ONE token's sales; empty sales history → explicit NO_SALES_DATA verdict."},{"path":"/nft/:chain/collection/:address/pulse?cursor=","returns":"ALWAYS LIVE market snapshot: OpenSea floor + retrievedAt, totalSupply, latest sale block, sales in the last page — plus a cursor; resupply it to get deltas (floor change, sales since, blocks elapsed)."}],"method":{"data_sources":["Alchemy NFT API v3 (contract metadata, spam classification, owners, floor prices)"],"cache_policy":"Edge Cache API keyed on the upstream URL (credentials stripped); 24h max-age on cached-tier calls.","house_rules":"Evidence lists, never scores. Skipped checks are listed in not_checked. No ToS-violating scraping."},"wishlist":"Chain not covered, or a check you'd pay for? POST /suggest (free) — e.g. {\"suggestion\": \"nft: add base\"}. Demand routes the roadmap."}