{"openapi":"3.0.3","info":{"title":"SENTINEL — Institutional Bitcoin Intelligence API","version":"1.0.0","description":"Evidence-classified Bitcoin intelligence. Every event carries PROVEN / INFERRED / SPECULATIVE claims, percentile-based anomaly scores, and a chained SHA-256 report hash for independent verification. Historical correlation never implies causation."},"servers":[{"url":"https://mempool.sentinelbtc.com"}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"API key (snt_...) as Bearer token"},"apiKey":{"type":"apiKey","in":"header","name":"X-Api-Key"}},"schemas":{"Event":{"type":"object","properties":{"id":{"type":"string","example":"SNT-2026-000042"},"type":{"type":"string"},"severity":{"type":"string","enum":["CRITICAL","HIGH","WATCH","RESEARCH"]},"summary":{"type":"string"},"headline":{"type":"string"},"blockHeight":{"type":"integer"},"blockTime":{"type":"integer"},"detectedAt":{"type":"integer"},"txids":{"type":"array","items":{"type":"string"}},"amountBtc":{"type":"number"},"rarity":{"type":"number","description":"Overall percentile rarity 0-100"},"significance":{"type":"number"},"significanceLabel":{"type":"string"},"scores":{"type":"object","properties":{"amount":{"type":"number"},"age":{"type":"number"},"dormancy":{"type":"number"},"graph":{"type":"number"},"temporal":{"type":"number"}}},"features":{"type":"object"},"claims":{"type":"array","items":{"type":"object","properties":{"class":{"type":"string","enum":["PROVEN","INFERRED","SPECULATIVE"]},"statement":{"type":"string"},"confidence":{"type":"number","nullable":true},"methodology":{"type":"string","nullable":true},"refs":{"type":"array","items":{"type":"string"}}}}},"story":{"type":"array","items":{"type":"string"}},"reportHash":{"type":"string","description":"SHA-256 over the canonical evidence payload, chained"},"prevReportHash":{"type":"string","nullable":true},"valid":{"type":"boolean","description":"false when invalidated by a chain reorganization"},"urls":{"type":"object"}}},"Error":{"type":"object","properties":{"error":{"type":"string"}}}}},"paths":{"/healthz":{"get":{"tags":["Ops"],"summary":"Liveness probe","responses":{"200":{"description":"OK"}}}},"/readyz":{"get":{"tags":["Ops"],"summary":"Readiness probe (checks database)","responses":{"200":{"description":"Ready"},"503":{"description":"Not ready"}}}},"/api/v1/status":{"get":{"tags":["Public"],"summary":"Service, node and indexer status","responses":{"200":{"description":"Status object"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/events":{"get":{"tags":["Public"],"summary":"List intelligence events (filterable)","parameters":[{"name":"type","in":"query","schema":{"type":"string"},"description":"Comma-separated event types"},{"name":"severity","in":"query","schema":{"type":"string"},"description":"Comma-separated severities"},{"name":"minRarity","in":"query","schema":{"type":"number","minimum":0,"maximum":100}},{"name":"minBtc","in":"query","schema":{"type":"number"}},{"name":"fromTime","in":"query","schema":{"type":"integer"},"description":"Unix seconds"},{"name":"toTime","in":"query","schema":{"type":"integer"}},{"name":"fromHeight","in":"query","schema":{"type":"integer"}},{"name":"toHeight","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer","maximum":200,"default":50}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Event list","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"events":{"type":"array","items":{"$ref":"#/components/schemas/Event"}}}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/events/{id}":{"get":{"tags":["Public"],"summary":"Full evidence package for one event","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^SNT-\\d{4}-\\d{6}$"}}],"responses":{"200":{"description":"Event, similar events, analyst interpretation, citation block"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/events/{id}/verify":{"get":{"tags":["Public"],"summary":"Recompute and verify the chained report hash","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"hashValid true/false with hashes"},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/discoveries":{"get":{"tags":["Public"],"summary":"DISCOVER — the most significant recent findings","responses":{"200":{"description":"Ranked discoveries"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/digest/daily":{"get":{"tags":["Public"],"summary":"SENTINEL DAILY — evidence-backed digest of the last 24h","responses":{"200":{"description":"Digest slots"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/metrics":{"get":{"tags":["Public"],"summary":"Supply-by-age bands, dormant supply, UTXO count","responses":{"200":{"description":"Metrics"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/metrics/hodl-waves":{"get":{"tags":["Public"],"summary":"Supply-by-age distribution across the full indexed history (HODL waves)","parameters":[{"name":"points","in":"query","required":false,"schema":{"type":"integer","minimum":8,"maximum":120,"default":40}}],"responses":{"200":{"description":"Time series of age-band supply samples"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/timemachine/{ref}":{"get":{"tags":["Public"],"summary":"Time Machine — DNA profile plus capped ancestor/descendant genealogy (free tier, depth 4)","parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string"},"description":"txid or txid:vout; bare txid resolves to the dominant-value output"}],"responses":{"200":{"description":"DNA profile with lineage graphs"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/boards/activity":{"get":{"tags":["Public"],"summary":"TX boards feed — recent blocks plus their largest transactions with capped input/output lists","parameters":[{"name":"blocks","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":12,"default":6}},{"name":"top","in":"query","required":false,"schema":{"type":"integer","minimum":5,"maximum":60,"default":30}}],"responses":{"200":{"description":"Blocks and top transactions of the recent window"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/mining/network":{"get":{"tags":["Public"],"summary":"Mining network metrics — difficulty, estimated hashrate, block interval, subsidy, fees, fee share, security budget, hashprice","description":"Every metric carries provenance (PROVEN | INFERRED | ESTIMATED), source, methodology, and computation time. Fiat metrics require an explicitly configured price dataset and are otherwise reported unavailable with the reason.","responses":{"200":{"description":"Provenance-tracked network metrics over the recent block window"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/mining/stress":{"get":{"tags":["Public"],"summary":"SENTINEL miner stress index — weighted composite with per-component evidence and explicit confidence","description":"Composite 0-100 score over documented components. Only components backed by real data contribute; confidence is the share of component weight backed by data. The interpretation is deterministic and labeled INFERRED.","responses":{"200":{"description":"Miner stress composite, components, confidence, interpretation"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/mining/summary":{"get":{"tags":["Public"],"summary":"Mining intelligence summary — network metrics, stress index, and module availability","responses":{"200":{"description":"Full mining intelligence payload with module availability statuses"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/mempool":{"get":{"tags":["Public"],"summary":"Live mempool snapshot — projected next blocks, fee bands, and fee recommendations from SENTINEL's own node","description":"Transaction counts, virtual sizes and fee totals are PROVEN, read straight from the node mempool. The projected-block ordering is ESTIMATED — mempool transactions sorted by fee rate and packed to the 4M weight-unit consensus limit — and labeled as such. Nothing is mirrored from a third-party mempool provider. Returns 503 when no node mempool is available.","responses":{"200":{"description":"Mempool overview, projected blocks, fee bands, and fee recommendations with provenance"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/mempool/recent-blocks":{"get":{"tags":["Public"],"summary":"Recently confirmed blocks with transaction counts and total fees, for the \"just mined\" row beside the projection","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":30,"default":8}}],"responses":{"200":{"description":"Recent confirmed blocks; a block's total fee is null when any input value is not yet indexed, never fabricated"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/mempool/tx/{txid}":{"get":{"tags":["Public"],"summary":"Look up a transaction by id across the mempool (unconfirmed) and the indexed chain (confirmed)","parameters":[{"name":"txid","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"}}],"responses":{"200":{"description":"Transaction location (mempool | confirmed | not_found), fee, fee rate, inputs and outputs; unavailable values carry a reason"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/mempool/search":{"get":{"tags":["Public"],"summary":"Multi-input mempool & chain search — address, txid, block height or block hash","description":"The query is classified deterministically: all-digits => block height, 64-hex => block hash or txid, otherwise => address. Address results are drawn from indexed outputs and note that unconfirmed presence is not scanned by address. No LLM ever generates SQL.","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","maxLength":100}}],"responses":{"200":{"description":"A tx, address, block, or not_found result, each tagged with its kind"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/mempool/network":{"get":{"tags":["Public"],"summary":"Network status — difficulty-epoch progress and halving countdown, INFERRED from the public-API source","description":"Epoch position and block counts are consensus arithmetic on the current tip. The projected retarget magnitude is the source API's estimate and is null on providers that do not publish one — never fabricated.","responses":{"200":{"description":"Difficulty epoch, retarget estimate, and halving countdown with source attribution"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/mempool/recent-txs":{"get":{"tags":["Public"],"summary":"Recently seen mempool transactions from the public-API stream, INFERRED and attributed","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":30,"default":12}}],"responses":{"200":{"description":"Recent unconfirmed transactions with fee, fee rate, and size"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/entities":{"get":{"tags":["Public"],"summary":"Tracked-entity wallet registry: publicly documented attributions with citations","description":"Exchange cold wallets, government seizure wallets, historic hack loot, the OFAC sanctioned-address import (refreshed daily) and a curated subset of the MIT-licensed GraphSense public TagPacks (thousands of addresses: sanctioned services, self-published exchange reserves, hack/ransomware loot — every tag citing a public source). Every attribution cites its public documentation and is INFERRED — SENTINEL performs no clustering and never attributes a private individual's wallet. Entities with no publicly verifiable addresses are listed as untracked with the reason.","responses":{"200":{"description":"Curated entities with citations, sanctioned-import summary, untracked list, and coverage note"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/entities/lookup":{"get":{"tags":["Public"],"summary":"Look up the publicly documented owner of a Bitcoin address, if the registry knows one","parameters":[{"name":"address","in":"query","required":true,"schema":{"type":"string","maxLength":100}}],"responses":{"200":{"description":"The entity match (with citation) or null"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/whales":{"get":{"tags":["Public"],"summary":"Dynamic whale watchlist: large wallets observed on-chain — identity unknown by design","description":"Addresses that received a single output above the whale threshold and are NOT in the tracked-entity registry. Each entry is an on-chain observation (first seen, largest observed output, last activity) — never an identity; SENTINEL states \"identity unknown\" instead of guessing an attribution. Watched wallets are polled round-robin and their movements surface as WHALE_WALLET events. 503 in node mode.","responses":{"200":{"description":"Watched whale wallets with observation metadata and honesty note"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/events/unusual":{"get":{"tags":["Public"],"summary":"Unusual on-chain events across all intelligence verticals — INFERRED from the public-API stream, bucketed for the homepage grid","description":"Every event is INFERRED and names its upstream source. Events are sorted by severity and tagged JUST_NOW / TODAY / THIS_WEEK. Filter with the vertical parameter (comma-separated: WHALE, MEGA_TX, ANOMALY, MINER, ANCIENT, LIGHTNING, EXCHANGE, INSTITUTIONAL) so a category page pulls only its own slice. 503 in node mode, where the detector is not wired.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":60,"default":60}},{"name":"vertical","in":"query","required":false,"schema":{"type":"string","example":"MINER,ANOMALY"}}],"responses":{"200":{"description":"Categorized unusual events with source attribution"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/events/unusual/{id}":{"get":{"tags":["Public"],"summary":"One unusual event by id, while it lives in the 7-day ring","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^ux_[0-9a-z]+$"}}],"responses":{"200":{"description":"The unusual event"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/events/signals":{"get":{"tags":["Public"],"summary":"Always-on network-signals snapshot — fees, mempool, last block, difficulty and issuance, INFERRED and attributed","responses":{"200":{"description":"Current network signals; also rendered at /card/network.png and /share/network"},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/search":{"get":{"tags":["Public"],"summary":"Universal search (txid, block, event id, address, height, or natural language)","description":"Natural-language queries are parsed deterministically into validated filters. No LLM ever generates SQL.","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Typed search result"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/share/{id}.svg":{"get":{"tags":["Public"],"summary":"Self-contained share card (SVG 1200x630) for an event","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"image/svg+xml"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/card/{id}.svg":{"get":{"tags":["Embed"],"summary":"Event card as SVG — usable directly in <img src>","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"image/svg+xml"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/card/{id}.png":{"get":{"tags":["Embed"],"summary":"Event card as PNG (1200x630) — usable directly in <img src>","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"image/png"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/embed/event/{id}":{"get":{"tags":["Embed"],"summary":"Framable HTML card for one event (iframe embed; frame-ancestors *)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"text/html, embeddable in third-party iframes"},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/embed.js":{"get":{"tags":["Embed"],"summary":"Embeddable widget script defining <sentinel-event> and <sentinel-live> custom elements","responses":{"200":{"description":"application/javascript"}}}},"/api/v1/blocks":{"get":{"tags":["Data"],"summary":"List indexed blocks","security":[{"bearer":[]},{"apiKey":[]}],"parameters":[{"name":"from","in":"query","schema":{"type":"integer","default":0}},{"name":"limit","in":"query","schema":{"type":"integer","maximum":500,"default":50}}],"responses":{"200":{"description":"Blocks"},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/blocks/{ref}":{"get":{"tags":["Data"],"summary":"Block by height or hash, with transactions","security":[{"bearer":[]},{"apiKey":[]}],"parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Block + transactions"},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/transactions/{txid}":{"get":{"tags":["Data"],"summary":"Transaction with inputs (held days, coin-days destroyed) and outputs","security":[{"bearer":[]},{"apiKey":[]}],"parameters":[{"name":"txid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Transaction detail"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/utxos/{txid}/{vout}":{"get":{"tags":["Data"],"summary":"Single UTXO with age","security":[{"bearer":[]},{"apiKey":[]}],"parameters":[{"name":"txid","in":"path","required":true,"schema":{"type":"string"}},{"name":"vout","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"UTXO"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/utxos/address/{address}":{"get":{"tags":["Data"],"summary":"UTXOs by address (max 200)","security":[{"bearer":[]},{"apiKey":[]}],"parameters":[{"name":"address","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"UTXO list"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/lineage/{txid}/{vout}":{"get":{"tags":["Data"],"summary":"Lineage graph (ancestors or descendants), depth-capped","security":[{"bearer":[]},{"apiKey":[]}],"parameters":[{"name":"txid","in":"path","required":true,"schema":{"type":"string"}},{"name":"vout","in":"path","required":true,"schema":{"type":"integer"}},{"name":"direction","in":"query","schema":{"type":"string","enum":["ancestors","descendants"],"default":"descendants"}},{"name":"depth","in":"query","schema":{"type":"integer","maximum":32}}],"responses":{"200":{"description":"Graph {nodes, edges, truncated}"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/dna/{txid}/{vout}":{"get":{"tags":["Data"],"summary":"UTXO DNA profile (dominant-value ancestry timeline)","security":[{"bearer":[]},{"apiKey":[]}],"parameters":[{"name":"txid","in":"path","required":true,"schema":{"type":"string"}},{"name":"vout","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"DNA profile"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/trace/{txid}":{"get":{"tags":["Data"],"summary":"TRACE — the story of this bitcoin (dominant-output ancestry)","security":[{"bearer":[]},{"apiKey":[]}],"parameters":[{"name":"txid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trace"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/admin/keys":{"post":{"tags":["Admin"],"summary":"Create API key (raw key returned exactly once)","security":[{"bearer":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"role":{"type":"string","enum":["admin","analyst","readonly"],"default":"readonly"}}}}}},"responses":{"200":{"description":"{id, name, role, key}"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"get":{"tags":["Admin"],"summary":"List API keys (hashes never returned)","security":[{"bearer":[]},{"apiKey":[]}],"responses":{"200":{"description":"Keys"},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/admin/keys/{id}":{"delete":{"tags":["Admin"],"summary":"Revoke API key","security":[{"bearer":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Revoked"},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/alerts":{"post":{"tags":["Alerts"],"summary":"Create alert rule (webhook optional; public endpoints only)","security":[{"bearer":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"minBtc":{"type":"number","nullable":true},"minAgeDays":{"type":"number","nullable":true},"minRarity":{"type":"number","nullable":true},"eventTypes":{"type":"array","items":{"type":"string"},"nullable":true},"webhookUrl":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"Rule"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}},"get":{"tags":["Alerts"],"summary":"List my alert rules","security":[{"bearer":[]},{"apiKey":[]}],"responses":{"200":{"description":"Rules"},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/alerts/{id}":{"delete":{"tags":["Alerts"],"summary":"Delete alert rule","security":[{"bearer":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/alerts/{id}/deliveries":{"get":{"tags":["Alerts"],"summary":"Delivery log for a rule","security":[{"bearer":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deliveries"},"401":{"description":"Missing/invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"403":{"description":"Insufficient role","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}}}}