{"api_version":"2026-08-28","policy":"X-API-Version (CalVer YYYY-MM-DD) is bumped on any breaking or notable response-shape change; each is logged here newest-first.","changelog":[{"version":"2026-08-28","date":"2026-08-28","breaking":false,"changes":["**`POST /api/v1/auth/keys` now returns `next_calls`** — an ordered, machine-readable onboarding ladder: `GET /api/v1` -> `GET /api/v1/daily` -> `GET /api/v1/quant/market` / `GET /api/v1/quant/gex`, each with its MCP tool name, whether it needs a key, the tier it needs, and why. Until now the mint's only forward pointer was \"confirm your email\", so an agent holding a fresh key had nothing naming a first *data* call and fell back to whatever it already knew — in the observed case, polling candles. **Additive**; every existing field is unmoved.","**`GET /api/v1` (the endpoint index) carries the same `first_calls` block.** It is step 1 of that ladder, so it now answers \"what do I do next\" as well as \"what exists\". **Additive.**","**Tier `403`s now carry the whole upgrade path, not just a pricing URL.** Every `pro_required` / `pro_plus_required` body gained an `upgrade` object — live prices and caps for both paid tiers, the public discount code, and `POST /api/v1/payments/agent-subscribe` (x402) when it is enabled, which is the only upgrade an unattended agent can complete without a browser. **Additive**; `error`, `message`, `required_tier`, `pricing_url` and `hint` are unchanged.","**A `pro` 403 held by an unverified free key also gains `verify_email`.** Confirming that key's address switches Pro on for 24 hours, which clears the gate for free — so the cheapest correct next step is the link already in the user's inbox, not the pricing page. Present ONLY when it would actually help: never on a `pro_plus` gate (the trial grants Pro, not Pro Plus), and never for a key that is already verified or already paid. Branch on the field's presence, not on tier.","**MCP: `list_capabilities` no longer requires an API key.** It returns static metadata and makes no data call, so it is now callable with zero credentials alongside `create_free_api_key`. Every onboarding surface tells a new agent to call it first, and until now that was advice it could not take. Its payload also gained `first_calls`, `rest_api_user_agent` and `tiers.discount`.","**MCP tool errors now include the actionable half of the response body.** A tier 403 was being flattened to its `message` alone, dropping the `verify_email` / `upgrade` / `discount` blocks the API had just attached — so an agent saw \"requires a Pro key\" with no way forward. The error text now carries them, built from the API's own fields rather than a second copy of the copy.","**Documented: Python's built-in `urllib` needs an explicit `User-Agent`.** Its default `Python-urllib/3.x` signature is refused by our CDN's bot protection *before the request reaches the API*, returning an HTML 403 (Cloudflare error 1010) instead of a JSON error — on every path, including `/llms.txt` and `/mcp`. Any other User-Agent works (an empty one included); `requests`, `httpx`, `aiohttp`, `curl` and Node `fetch` are unaffected. No API behaviour changed — this is now stated in `llms.txt`, the MCP instructions, the Agent Skill and the docs instead of only being discoverable by hitting it."]},{"version":"2026-08-27","date":"2026-08-27","breaking":false,"changes":["**`limit` now works on `GET /api/v1/derivatives/binance/funding-rates`.** It was silently ignored for actively-tracked symbols (BTCUSDT, ETHUSDT, …): the background refresh cached a fixed window and the route served it whole, so `limit=5` and `limit=100` both came back with `count: 30`. The response now carries the window you asked for, and `avg_rate` is recomputed over exactly those settlements instead of a different, unstated set. `current_rate` is unchanged (it is the newest settlement either way). **If you were passing `limit` and quietly receiving 30 rows, you will now receive what you requested — check any code that assumed the array length.** Uncached symbols always honoured `limit` and are unaffected.","**No change to `avg_rate` on `/derivatives/binance/summary`, `/derivatives/funding-rates` or `/daily`.** Those call sites passed a `limit` that had never taken effect, so honouring it literally would have silently narrowed their published averages. They are pinned to the 30-settlement window they have always served. Same for the market-health funding sub-score — its window is unchanged, so no published 0-100 score moves.","**`minutes` on `GET /api/v1/liquidity/depth/{coin}` is now a real time window.** It used to slice the last N *samples*, which only equals N minutes at a strict 1-per-minute cadence — collection actually runs on a ~2-minute timer and can skip, so `minutes=3` was observed returning snapshots spanning ~48 minutes. Any rate-of-change computed off that window was wrong by an unknown factor. The window is now measured back from now, so **expect roughly `minutes / 2` records rather than `minutes`** — the rows you get are the rows that genuinely fall inside the interval. Each record's `ts` is authoritative; `count` reflects what landed.","**`404` on that route now means \"coin not tracked\", not \"empty window\".** An in-universe coin whose window contains no samples (a collector stall, or a `minutes` shorter than the sampling gap) returns `200` with `count: 0` and an empty `history`. Previously an empty slice raised `404`, which conflated a transient gap with an unknown symbol. **Additive**, but branch on `count` rather than treating `404` as \"no data right now\"."]},{"version":"2026-08-26","date":"2026-08-26","breaking":true,"changes":["**Every `401` / `403` / `429` on an `/api/*` path is now JSON with the same shape: `{\"detail\": {\"error\": \"<code>\", \"message\": \"<text>\"}}`.** **Breaking for two paths.** (1) `GET /api/v1/quant/gex`, `/api/v1/quant/positioning`, `/api/v1/hyperliquid/*`, `/api/v1/daily/hyperliquid` and `/api/v1/daily/hl-traders` returned an **HTML** error page on a missing/invalid/expired key — those are authed at the proxy layer, which had no JSON handler for `401`. They now return the same JSON envelope as everything else. (2) The Hyperliquid trader routes (`/hyperliquid/wallets/search`, `/hyperliquid/watchlist*`, `/hyperliquid/copy-signals`, `/hyperliquid/traders/*/refresh`) and `POST /api/v1/market-health/refresh` returned `detail` as a plain **string**; it is now the object above. If you read `detail` directly on those routes, read `detail.message` instead.","**NEW fields `required_tier` and `pricing_url`** on every `403` tier refusal, and `hint` where a route offers a free-tier alternative (e.g. BTC-scoped depth). `required_tier` is `\"pro\"` or `\"pro_plus\"` and is the machine-readable form of the message — branch on it rather than parsing prose. **Additive.**","**`GET /api/v1/quant/gex` is Pro, not Pro Plus.** It always was in the app (unchanged since the 2026-07-08 tier revision), but the proxy-layer gate still answered \"Pro Plus tier required or access denied\", contradicting `/quant/market`, which enforces the identical gate. No access change — only the message was wrong. The same correction lands in the docs and `llms.txt`, which listed full-universe gamma/whales/depth under Pro Plus.","**`error: \"btc_only\"` is retired.** The single endpoint that used it (`/api/v1/volatility/regime/{symbol}` for a non-BTC coin on the free tier) now returns `error: \"pro_required\"` with `required_tier: \"pro\"`, matching every other coin-scoping refusal. **Breaking if you matched on that code**; the status stays `403`.","**A `429` now carries `Retry-After` and the full `X-RateLimit-*` header set** (`-limit-day`, `-remaining-day`, `-reset-day`, and the `-minute` trio). They were previously present only on successful responses, so the one reply that should tell you how long to wait was the one that didn't. **Additive.**","**NEW fields `tier` and `scope` on `429` bodies, and the message now names the tier** — e.g. \"Daily rate limit of 50000 requests exceeded on this Pro Plus API key.\" The number was always correct for the caller's tier, but nothing said which tier it belonged to. `scope` is `\"api_key\"`: limits are per key, not per account or organisation. **Additive.**","**`POST /api/v1/auth/keys` now returns this key's actual limits and how to raise them**, so a caller no longer has to discover its cap by being rate-limited. NEW: `daily_limit`, `per_minute_limit` (the EFFECTIVE limits — a fresh key is unverified, so 100/day, not the tier headline of 1,000), `rate_limit_scope`, `email_verified`, `verified_daily_limit`, `next_step` (confirming the address lifts the SAME key to 1,000/day and adds 24 hours of Pro and a discount code — nothing to re-install), and `upgrade` (Pro / Pro Plus monthly and yearly prices with their caps, plus the x402 `agent-subscribe` endpoint when that rail is enabled). `GET /api/v1/auth/keys/me` gains `rate_limit_scope` and `upgrade` to match. **Additive.**","**Every `401` now sends `WWW-Authenticate: ApiKey realm=..., header=\"X-API-Key\"`,** so a client can discover the auth scheme from the response instead of the prose. **Additive.**","**Wallet-authenticated keys (`POST /api/v1/wallet/verify`) move to the full free tier: 1,000/day, up from 100/day.** They were minted unverified, but the address is `{wallet}@wallet` — no inbox, so the email confirmation that lifts the cap could never be completed. A signed wallet is the proof; the website's own wallet sign-in already treated it that way. **No action needed.**"]},{"version":"2026-08-26","date":"2026-08-26","breaking":false,"changes":["**Security fix: an authenticated GET endpoint could occasionally serve a cached response with no API key or an invalid one.** The origin response cache keyed purely on method+path+query with no regard for whether the caller was authenticated, and a cache hit (`X-Cache: HIT`) was served before the API-key check ever ran. Every affected endpoint's docs always required a key — this was never intended behavior — but if an integration was inadvertently relying on it, that path is now closed everywhere.","`/api/v1/*` response caching is now default-deny: only a short, explicit allowlist of genuinely public JSON (currently just the landing-page price ticker) is cacheable without a key. Every authenticated endpoint now runs its API-key check on every request, so `X-RateLimit-Remaining-Day` / `X-RateLimit-Remaining-Minute` are now **always** present on a successful authenticated response (previously silently absent on a cache hit).","**NEW fields `mint_url` and `docs_url`** on every `401` error body (`api_key_required` / `invalid_api_key` / `api_key_expired`) — the REST path to mint a free-tier key (`POST /api/v1/auth/keys`) and the docs URL, alongside the existing `error` code and `message`. **Additive, non-breaking.**"]},{"version":"2026-08-25","date":"2026-08-25","breaking":false,"changes":["**NEW field `ret_90d`** on the meme-metrics block — `GET /api/v1/meme/regime`, `GET /api/v1/meme/regime/{symbol}` and the `meme_regime.by_symbol[*].meme` map embedded in the daily snapshot. 90-day percent price return, alongside the existing `ret_1d` / `ret_7d` / `ret_30d`. **Additive, non-breaking.**","`ret_90d` is `null` when a coin has under 91 days of daily kline history (e.g. a recent listing) — same null convention as the other return windows. It is not part of the regime classifier (which uses only `ret_7d`/`ret_30d`), so this changes no coin's regime label.","**NEW field `sr`** on the technical-structure block — `GET /api/v1/indicators/technical`, `GET /api/v1/indicators/technical/{symbol}` and the `technical_regime.by_symbol[*]` map embedded in the daily snapshot. `sr.support`/`sr.resistance` are up to 3 levels per side (nearest to current price first), each `{price, strength, dist_pct}` — `strength` is how many swing-high/low pivots clustered into that level, `dist_pct` is signed % distance from mark (negative = support, positive = resistance). **Additive, non-breaking.**","Levels come from swing-pivot detection on the same 250-day daily series the rest of the technical block already uses (no new data source), clustered within 1.5% of each other, and dropped if more than 30% from mark. Both lists are `[]` for a coin with too little price oscillation to have a clear swing point — that is a real \"no clean level\" read, not missing data."]},{"version":"2026-08-23","date":"2026-08-23","breaking":false,"changes":["**NEW `GET /api/v1/exchanges`** and **`GET /api/v1/exchanges/{slug}`** — the venue directory behind our exchange pages, now machine-readable and **public (no API key)**. The list returns `exchanges[]`, `all_slugs[]`, `count` and `disclosure`; the detail route returns `{exchange, disclosure}` and **404s** on an unknown slug. Known slugs today: hyperliquid, binance, bybit, okx, asterdex, lighter, robinhood.","Each row carries the venue profile — `slug`, `name`, `kind` (CEX / DEX / Broker), `website`, `tagline`, `about`, `founded`, `based`, `focus[]`, `specs{instruments, coins, max_leverage, kyc, custody, fiat_onramp}` — plus `signup_url`, `signup_incentive`, `referral_code` and `is_referral_link`. The four sign-up fields are **null / false** for venues we hold no partner link with; `?referral_only=true` filters to the ones we do.","**Read `signup_url` as what it is: a CryptoDataAPI referral link.** `signup_incentive` is what the *end user* gets for using it — Hyperliquid pays them a 4% discount on spot and perpetual trading fees, Binance up to 20% off. We may earn a commission; it costs the user nothing extra. Every response carries a `disclosure` string: if you surface the link, surface that with it. It has no bearing on any other output of this API — no score, regime or signal is affected by where you trade.","Same data is now on the agent surfaces: the MCP tool `get_exchange_links` gained a `referral_code` field and its `disclosure` string changed wording (it is prose for humans, not an identifier — do not match on it), `list_capabilities` gained a `where_to_trade` block, and the venue link is documented in llms.txt, llms-full.txt and the Agent Skill. Nothing existing was renamed or removed."]},{"version":"2026-08-22","date":"2026-08-22","breaking":true,"changes":["**Pro Plus is now 120 requests/minute** (was 60). The daily cap is unchanged at 50,000, because the per-minute limit was never the cost control — it is a burst shield, and it was sized wrong. Read against the rate each daily cap already implies (per_day / 1440), Free allowed a 14x burst, Pro 4.3x and Pro Plus only 1.7x: headroom shrank as you paid more, on the tier whose callers fan out hardest. If you fan out across a symbol list, you can now do it roughly twice as wide per minute without backing off. Nothing else changes — you cannot pull more per day than before, and `GET /api/v1/auth/keys/me` reports your effective limits.","FIXED `GET /api/v1/market-intelligence/liquidations/by-exchange`, which had returned **503 on every call since 2026-07-24** — a month of hard downtime that no alarm caught. When the paid CoinGlass API was retired, each of its data types was either re-sourced from free feeds or allowed to go quiet on the grounds that \"every call site tolerates None\". This one did not tolerate it: its handler raises a 503 on empty, so an unsourced slot meant a dead endpoint rather than a thin one. It is now built from our own realized-liquidation feed, which knew each event's venue at ingest and simply was not storing it.","ADDED per-venue fields on that endpoint. Each row is `{exchange, symbol, total, total_usd, long_usd, short_usd}` for BTC over the trailing 4h. `total` keeps the legacy CoinGlass field name and `total_usd` mirrors it under the naming the rest of the liquidation surface uses, so integrations written against either keep working. Rows are sorted largest-first.","FIXED `GET /api/v1/market-intelligence/etf/sol/flows`, dead the same way and for the same month: the free-source cutover wired Farside's BTC and ETH pages and never added the SOL one, which publishes in an identical shape. SOL spot-ETF net flows are live.","FIXED `GET /api/v1/market-intelligence/etf/btc/aum`, also 503 on every call since 2026-07-24 — CoinGlass was the only AUM feed and no free one exists. AUM is derivable though, because it is coins held times price and the daily flow history gives the coins: we now sum `net_flow_usd / btc_close` across all 670-odd days since the January 2024 launch and multiply by spot.","CHANGED the shape of that endpoint, and read the field names carefully. It returns `aum_usd_from_flows` and `btc_held_from_flows` — NOT a bare `aum_usd`. GBTC converted in January 2024 already holding a large stake, and it enters the flow table only as later outflows, so this measures BTC accumulated THROUGH FLOWS since launch and understates the whole complex by roughly that seed. That is not a rounding difference. Also returned: `cumulative_net_flow_usd` and `price_appreciation_usd` (the two are different quantities — the gap is appreciation, negative when the average buyer is underwater), plus `method`, `source`, `excludes` and `caveats`.","BREAKING for one asset: `GET /api/v1/market-intelligence/etf/xrp/flows` now returns **400** naming the supported assets, where it returned 503 before. No free source publishes XRP spot-ETF flows (Farside has BTC, ETH, SOL and HYPE pages and no XRP one). A 503 tells a client to retry, which was never going to succeed; a 400 tells it to stop. No working integration breaks, because no call to it has ever succeeded. Supported assets are now btc, eth, sol.","CAVEAT on that endpoint, the same one `/api/v1/market-intelligence/liquidations` already carries: coverage is the venue subset we stream (OKX + Bybit + Hyperliquid), so totals run UNDER a true all-exchange number. Binance geo-blocks its liquidation stream from our IPs. The Hyperliquid contribution is exact, from the per-fill node stream. Expect a 503 for a few minutes after a deploy while the 4h window refills with venue-tagged events, and partial totals until it is 4h old."]},{"version":"2026-08-21","date":"2026-08-21","breaking":false,"changes":["**The market-moving news tape now recognises US policy catalysts.** On 2026-08-20 a White House crypto event, a presidential push for the CLARITY Act and a doubling of US Treasury debt buybacks moved BTC roughly 10% and liquidated about $3B of shorts — and produced **zero** events on `GET /api/v1/news/market-moving`. Every one of those headlines was ingested and then discarded: the catalyst taxonomy had no rule for legislation, executive action, agency rulemaking or a sovereign buyer, so each scored as \"not a catalyst\" before entity resolution or impact scoring ever ran. Those rules did exist, but only in the Regime #12 policy sidecar, which reads three government document feeds and never sees crypto media. The two taxonomies now share one block, so both surfaces see the same events.","ADDED `category` values on `/api/v1/news/market-moving`, `/api/v1/news/coin/{symbol}` and the archived `/api/v1/backtesting/news-events` tape (additive — existing categories are unchanged): `legislation`, `executive_signal`, `rulemaking`, `restrictive_policy`, `sovereign_bid`, `strategic_reserve`, `pro_crypto_eo`, `macro_liquidity` and `macro_tightening`. All are market-wide, so they resolve to `symbol: \"MARKET\"` when a headline names no coin. If you switch on `category`, add a default branch.","CHANGED classification of sovereign debt operations. `treasury_buy` matched the \"buy\" prefix of \"buybacks\", so \"US Treasury Doubles Debt Buybacks\" was filed as a corporate treasury purchasing crypto. It is now `macro_liquidity`. `treasury_buy` still covers corporate and public-company purchases, and has joined the market-wide set so a bid that names no ticker is no longer dropped.","FIXED a sign error on `GET /api/v1/policy/headlines` and the Regime #12 `policy_headlines` sidecar. The `ban` rule was unbounded on the right, so \"**Bank**ing Regulator Races to Finalize GENIUS Act Stablecoin Rules\" — a constructive story — scored as a maximum-severity regulatory ban at `bias: -1.0`. Any headline containing \"banking\", \"banks\" or \"banner\" was affected, which on the SEC/CFTC/Federal Register feeds is common. `headline_tilt` and `regulatory_pressure` were skewed negative accordingly.","ADDED whitehouse.gov (news, fact sheets and presidential actions) to the policy feed set. The Federal Register query is filtered to the literal term \"digital asset\" and SEC/CFTC press covers enforcement, so none of the existing sources could see a political event. Items from these broad feeds are admitted only when they name digital assets, so non-crypto policy does not enter the sidecar.","TUNED two scoring windows on the news funnel. The corroboration window went from 6h to 24h — outside it an item fell back to a single source no matter how many desks carried it, which permanently pinned slow-syndicating macro stories below the impact threshold. And the 12h novelty damping is now 6h for policy categories: every market-wide story shares the symbol `MARKET`, so one 12h bucket per category collapsed a busy policy day into a single tape entry. Expect a modestly denser tape on policy-heavy days. The impact threshold itself (0.45) is unchanged.","NEW `GET /api/v1/market-intelligence/squeeze-alerts` (Pro; free tier scoped to BTC) — coins whose forced-liquidation flow is one-sided and abnormal right now. Even with the taxonomy fixed, a news-derived signal is 15-45 minutes behind a breaking story. On 2026-08-19 the BTC tape printed $322.8M of short liquidations in one 5-minute bucket at a 334x short/long ratio, 23 minutes before the first related headline qualified. Returns `direction` (`short_squeeze` / `long_flush` / `balanced`, named after the side being LIQUIDATED — a short liquidation is forced buying), `severity` (0..1), `triggered`, `asymmetry`, `side_ratio`, `spike_ratio`, `oi_change_pct` and `oi_state` (`covering` / `fresh_longs` / `capitulating` / `fresh_shorts` / `unclear`, `null` when open interest is not yet measurable). Coverage is the same venue subset as `/market-intelligence/liquidations` — Binance geo-blocks its liquidation stream from our infrastructure — so severity is built from ratios rather than absolute notionals. Check `window_uptime_h`: `spike_ratio` is measured against a trailing-24h baseline and a recently reconnected feed understates it.","No historical backfill is possible for the news changes. The tape starts 2026-08-18 and RSS serves only a recent window, so the 2026-08-20 events described here will not appear retroactively in `/api/v1/backtesting/news-events`.","FIXED (same day) `spike_ratio` being inflated on a recently reconnected liquidation feed, and ADDED two absolute floors to `squeeze-alerts`. The cascade baseline is a mean per window, but it divided the trailing-24h total by a full day's worth of windows regardless of how much of that day had actually been observed — so for the first day after any deploy it understated the mean by (24h / uptime) and overstated `spike_ratio` by the same factor. This affected every consumer of the signal, not just the new endpoint: coin pages, `/quant/positioning` and the liquidation snapshots all read inflated cascade values post-deploy. Separately, because notional carries only 20% of severity weight, a perfectly one-sided window could reach severity 0.80 on any size at all — in production this raised alerts on $760 and $1,094 of liquidations. `triggered` now additionally requires a minimum absolute notional and a minimum baseline age. That age is measured from the SPAN OF RETAINED DATA — new `baseline_span_h` on each row — and not from process uptime: the feed restores up to 24h of events from its snapshot on boot, so seconds after a deploy the process is new while the history is a full day. Gating on uptime would have muted real cascades for an hour after every deploy. `window_uptime_h` is still reported, but `baseline_span_h` is the field to check before trusting a spike.","ADDED `suppressed_by` to each `squeeze-alerts` row (additive): the list of gates that blocked an alert — `no_spike_baseline`, `spike_ratio`, `asymmetry`, `severity`, `min_notional`, `baseline_too_young` — empty when `triggered` is true. The floors gate the alert, not the scoring, so a suppressed row is still returned by `include_quiet=true` with the reason attached rather than leaving you to re-derive it from the numbers."]},{"version":"2026-08-20","date":"2026-08-20","breaking":false,"changes":["**Free-tier rate limits raised, and split on email verification.** The free tier is now **10 requests/minute and 1,000 requests/day** (was 5/min, 50/day). A free key whose email address has not been confirmed runs on a starter allowance of **100 requests/day** at the same 10/minute; confirming the address lifts the SAME key to 1,000/day in place — no re-mint, no new key, nothing to re-install. Existing keys are unaffected: every account that already verified its email (which is every web signup, since verification is required before a key can be created) was migrated onto the full allowance, and even the starter rung is double the old 50/day. Pro (30/min, 10,000/day) and Pro Plus (60/min, 50,000/day) are unchanged. The per-IP aggregate for free keys rose to 20/min · 2,000/day to match.","Confirming a free key's email also grants **24 hours of Pro** (full-universe quant regimes and forward probabilities, dealer gamma, whale activity, liquidation heatmaps and L2 order books — every coin, not just BTC) and emails a single-use discount code. The trial is granted once per address, appears as an ordinary subscription on plan `trial_pro`, and expires on its own; it is not purchasable.","ADDED fields on `GET /api/v1/auth/keys/me` (additive, non-breaking): `per_minute_limit`, `email_verified` (bool), `verified_daily_limit` (the daily cap confirming would unlock, `null` when there is nothing to gain) and `upgrade_message`. `daily_limit` now reports the key's EFFECTIVE cap rather than the tier default, so an unverified free key correctly reads 100.","ADDED fields on the daily-quota `429` body for unverified free keys (additive): `upgrade_available: \"verify_email\"`, `upgrade_message` and `verified_daily_limit`. Absent for every caller whose cap verifying would not change, so there is never a no-op offer to parse.","NEW `POST /api/v1/auth/resend-verify` — re-send the confirmation link for the calling key's own address. Returns `status: \"sent\"`, or `status: \"already_verified\"` when there is nothing to confirm. Throttled to one send per 10 minutes.","NEW MCP tools `check_key_status` and `resend_verification_email`, so an agent that hits the cap can report the exact next step to its user instead of failing. `create_free_api_key` now asks for the user's real email address and returns a `verify_email` note; it no longer suggests minting a key against a different address to work around an existing one.","NEW archived dataset `token_unlocks` on `GET /api/v1/backtesting/snapshots` (Pro Plus). Each snapshot is the whole unlock board exactly as published at that moment — per-coin `float_pct`, `locked_usd`, `dilution_overhang` and `next_unlock` (`date`, `usd`, `tokens`, `pct_of_float`, `categories`) — recorded every 2 hours. This exists because an unlock calendar is the one dataset that CANNOT be reconstructed after the fact: the upstream source revises vesting schedules in place and serves only the current version, so a schedule pulled today says nothing about what the market could see three months ago. Forward-looking queries stay on `/supply/unlocks` and `/supply/float`; this answers 'what did we know, and when'. Coverage starts 2026-08-20 and grows forward — nothing earlier is recoverable."]},{"version":"2026-08-19","date":"2026-08-19","breaking":false,"changes":["NEW `GET /api/v1/supply/float` — circulating float and dilution overhang per coin, ranked by ASCENDING float. `float_pct` is circulating ÷ `supply_basis`, and `supply_basis` states WHICH denominator was used (`max_supply` when the token is genuinely capped, else `total_supply`) — `max_supply` is absent for over half the universe and 'share of max' vs 'share of total' are different claims, so this is published rather than assumed. Also `locked_supply` / `locked_usd`, `dilution_overhang` (locked value as a MULTIPLE of market cap; above 1.0x more value is locked than the market prices), and `next_unlock` with the soonest cliff priced against float. **`unlock_coverage: not_tracked` means no vesting schedule is published for that token in our source — NOT that it has no unlock scheduled.** Do not read a null `next_unlock` as safe. Defaults to a $500M `min_market_cap` floor (below it a 'tight float' is usually a nominal `total_supply`, and those artifacts otherwise lead the ranking); pass 0 for the full set. Free = top 25 rows; Pro / Pro Plus = full board + filters.","NEW `GET /api/v1/supply/unlocks` — the forward token-unlock calendar as a first-class endpoint, each cliff sized in tokens, USD and `pct_of_float`. This is a CLIFF calendar, not an emissions feed: continuous emission (mining inflation, linear vesting, runs of identical daily releases) is deliberately excluded because a drip is not a step. Coverage is bounded by the protocols DefiLlama tracks — absence is not evidence that a token has no unlock. Free = next 7 days; Pro / Pro Plus = full horizon (35d). The same data still drives `/event/calendar?type=unlock`; this is a view, not a fork.","NEW `headlines` on every `GET /api/v1/news/pulse` row — raw coverage: how many stories in the current feed window name that coin at high confidence, whether or not any of them qualified as a catalyst. This is attention, NOT an event: the catalyst funnel discards ~95% of what it reads, so most coins sit at `news_pressure: 0` while `headlines` keeps counting, and a coin high on headlines with no pressure is being talked about without anything happening. Only high-confidence match modes count (`entity_hint` / `cashtag` / `venue_ticker` / `name`) — `ticker_context` is excluded because its 'crypto word within 90 chars' guard barely constrains anything in an all-crypto feed. Rows are now ranked by `news_pressure` first, then `headlines`; a qualified catalyst still outranks any amount of ordinary news flow. `0` until the first pipeline tick after deploy.","NEW `mint` event type on `GET /api/v1/event/calendar` and `/event/regime*` — dated stablecoin mint / burn steps, with new `delta_usd` (signed) and `pct_of_supply` fields. A step must clear BOTH a $50M floor and 0.5% of that issuer's own float, so USDT's ordinary daily noise does not fire while a small issuer's real move still does (measured over 180 days: USDT ~8 events, USDC ~21, DAI ~5). Bias is `long` on a mint (new dry powder) and `short` on a redemption — unlike a macro print, the direction is known. These are OBSERVED, not scheduled, so they carry `days_until <= 0`, matching how depegs already behave. Deliberately NOT part of the Event Risk composite: a quiet week must not re-weight the score.","FIX token-unlock coverage — the calendar was missing essentially every major unlock. The deep-fetch shortlist was ranked by DefiLlama's rolling `emission30d`, which reads $0 for a protocol whose next cliff is outside that window: measured 2026-08-19, `arbitrum-foundation` ranked #370 of 370, `optimism-foundation` #260, `sui-foundation` #271, `aptos` #92, so none were ever fetched — while the top of the ranking was mining inflation (Bitcoin, Dogecoin, Litecoin) that is correctly discarded as continuous. The shortlist is now driven by OUR universe first. IMPACT: `/event/calendar?type=unlock` went from 5 events across 3 protocols to 37 across 27 on the same day, now including SUI, OP, ZRO, W, TON, XPL, ALT, GRASS and EIGEN.","FIX unlock sizes and phantom unlocks. Each schedule is published in two overlapping shapes (`metadata.events` flat, `metadata.unlockEvents` nested) and both were being read, so every unlock was emitted TWICE — and the nested rows carry no category, so they bypassed the continuous-emission filter and arrived with no size. That is what the `(size n/a)` rows were: a pure linear rate change published as a catalyst. Only one shape is read now, and `unlocked_value_usd` / `pct_of_fdv` resolve for the majors (their emissions files carry no `gecko_id`, which the enrichment keys off — it is now backfilled). A run of identical daily releases is also recognised as a schedule rather than 35 separate catalysts.","FIX news entity resolution — headlines were being attributed to coins whose name appeared only as a fragment of an unrelated word. The project-name matcher ran an unanchored substring search, and it strips a trailing ' Protocol', so `NEAR Protocol` matched inside 'nearly', `Mina Protocol` inside 'dominate' and `Ordinals` inside 'according' — each at the 0.90 `name` confidence. Name matching is now anchored on word boundaries. IMPACT: `/news/market-moving`, `/news/pulse` and `/news/coin/{symbol}` will attribute FEWER events, and `news_pressure` / `news_tilt` for affected coins drop toward 0 — those values were wrong, not merely noisy. Response shapes are unchanged. If you snapshot the tape, expect a level shift on this date rather than a gradual drift.","Project names that are ordinary English words or place names (`Optimism`, `Stellar`, `Movement`, `Lighter`, `Plasma`, `Sonic`, `Canton`, `Venice`, `Jupiter`, `Babylon`, `Maple`, `Turbo`, `Seeker`, `Iota`, `Usual`, `Succinct`) now require a crypto context word nearby, the same guard already applied to `Sky`, `Gas` and `Move`. They resolve at `match_mode: ticker_context` (confidence 0.60) instead of `name` (0.90) — so a story that genuinely covers the project still lands, while 'stellar results' and 'optimism in markets' no longer do. Coins whose only name is now guarded appear in `unresolvable` on `/news/sources`.","NEW `GET /api/v1/changelog` — the machine-readable changelog now has a canonical home under `/api/v1`, so it is listed in the OpenAPI spec (`/api/openapi.json`) and in the `/api/v1` endpoint index like every other endpoint, instead of sitting outside the documented surface. Body is unchanged: `api_version`, `policy`, `changelog`. Public, no API key. It always returns JSON regardless of `Accept` — prefer it for new integrations.","`GET /changelog` now serves the human-readable changelog page to browsers and THIS SAME JSON to everything else. If you poll it, nothing changes and no action is needed: no key, identical body, and the JSON is what a caller sending no `Accept` header, `*/*` (the curl / requests / httpx default) or `application/json` receives. Only a caller that ranks `text/html` above JSON gets HTML.","`/changelog` now responds `Vary: Accept` with `Cache-Control: no-store`, so no cache between us can hand you the representation someone else asked for. `/api/v1/changelog` has a single representation and caches normally (`private`)."]},{"version":"2026-08-18","date":"2026-08-18","breaking":false,"changes":["NEW `GET /api/v1/news/pulse` — a per-coin news feature series for the Hyperliquid perp universe: `news_pressure` (0..1, recency-weighted sum of the impact scores of qualified catalysts, saturating) and a signed `news_tilt` (-1 risk-off … +1 risk-on), plus `event_count`, `top_impact` and a cross-sectional `rank`. This is the endpoint built to join against price. **Every active perp gets a row** — a coin with no news is `news_pressure: 0`, NOT a missing row, so a cross-sectional ranking has the zeros it needs and an absent symbol always means a pipeline failure rather than a quiet market. Free returns the top 10 rows by pressure; Pro / Pro Plus return the full universe.","NEW `GET /api/v1/news/market-moving` — the filtered catalyst tape. Each event carries `symbol` (HL perp, or `MARKET` for stories that move everything), `category`, `impact_score` (0..1), signed `bias`, and `corroboration` (how many independent sources carried the same `(symbol, category)` inside the window — the strongest free indicator that a story is real rather than syndicated). Free: BTC / ETH / MARKET, 24h, top 10. Pro: every perp, 7 days. Pro Plus: full retained history plus the score components (`severity`, `confidence`, `match_mode`, `sources`) and `market_response`.","news: this is a FILTERED TAPE, not a news archive. Roughly 300-500 stories a day are ingested and only the ~15-40 that clear the impact threshold are stored or served. Sub-threshold stories are discarded outright — there is **no raw-feed endpoint at any tier**, and tiering varies coin coverage and score detail, never the noise threshold. Do not build an integration that expects to query all news about a coin.","NEW `GET /api/v1/news/coin/{symbol}` — qualified events plus `news_pressure` / `news_tilt` for one perp. Free is limited to BTC and ETH; Pro and above may query any perp; Pro Plus additionally receives `market_response`.","news: Pro Plus responses carry `market_response` — the MEASURED move after the event at `15m` / `1h` / `4h`: `ret_pct`, `oi_change_pct`, `funding_shift`, `volume_multiplier` (vs that coin's own 30-day baseline) and a combined `abnormality` (0..1). Windows fill in as they mature, so a recent event legitimately reports `null` for `4h` — that means 'not yet', not 'no reaction'. A headline that moved nothing scores near-zero abnormality.","news: every event states HOW its coin was identified via `match_mode` (`cashtag` / `name` / `venue_ticker` / `entity_hint` / `venue_native` / `ticker_context`) and `confidence` (0.6-1.0), because the HL universe is full of tickers that are ordinary English words (`TRUMP`, `MOVE`, `NOT`, `S`, `W`, `ME`, `GAS`, `SAND`). Those can only match on a cashtag or their full project name, never a bare ticker. Filter on `match_mode` if your strategy cannot tolerate a false positive.","news: `category` includes `hl_listing` / `hl_delisting`, sourced from our own Hyperliquid universe diff rather than any feed. These are exact and immediate, and are the only coverage a brand-new listing gets before it has a profile or any press.","NEW `GET /api/v1/news/sources` — per-feed health, the hourly funnel counts (`ingested` / `dropped_noise` / `dropped_no_catalyst` / `dropped_no_entity` / `dropped_below_threshold` / `qualified`, counts only — no titles or URLs), and `unresolvable`: active perps whose ticker is an ordinary word and which have no safe project name, so they can only ever match on a cashtag. The coverage gap is published as a field rather than left as a silent blind spot.","news: sourcing is free and keyless throughout — publisher RSS (The Block, CoinDesk, Cointelegraph, Decrypt, The Defiant, CryptoSlate, Bitcoin Magazine), OKX announcements, and ~25 project blogs / Discourse governance forums / GitHub release feeds for the larger perps. **Latency is ~30s-5min behind the source**: this is a context, risk-off and event-study feed, not a listing-sniping race winner. There is no X/Twitter coverage (no free read tier exists), so anything breaking there reaches us via the outlets minutes later.","NEW `GET /api/v1/backtesting/news-events` (Pro Plus) — the archived news tape with MEASURED market-response labels (`ret_15m` / `ret_1h` / `ret_4h` / `vol_mult` / `oi_change_pct` / `funding_shift` / `abnormality`), so `impact_score` can be validated against realised moves rather than taken on trust. Archived daily to Parquet as the `news_events` type. Only qualified events are archived — this is not an 'all news' history.","news: history starts at deploy day and CANNOT be backfilled — RSS serves a recent window only, so no earlier tape will ever exist. Same constraint as `/regimes/history`."]},{"version":"2026-08-17","date":"2026-08-17","breaking":false,"changes":["NEW `GET /api/v1/volume/scanner` — the Crypto Volume Scanner: every Hyperliquid perp with its live rolling-24h notional (`volume_24h`), its 30-day baseline (`avg_volume_30d` / `median_volume_30d`) and the `multiplier` between them (3.0 = trading at three times its own normal daily volume). Relative volume, so a mid-cap punching above its weight outranks a major drifting sideways. Each row also carries `multiplier_median` (same ratio vs the 30d median — far less distorted by a single prior blow-off day; when the two disagree sharply that coin's history is lumpy), an activity `band` (dormant / quiet / normal / elevated / surging / extreme / unknown), `change_24h`, `open_interest_usd`, `funding_rate` and `days_of_history`. Filter with `band` / `min_multiplier`, sort by `multiplier` (default) / `volume_24h` / `symbol` / `change_24h`. Tiers: Free returns the top 20 perps by 24h volume; Pro / Pro Plus return the full universe (~177 active markets).","volume/scanner: the baseline is 30 **settled** UTC days — today's partial day is deliberately excluded, since counting a half-finished day would drag every average down and inflate every multiplier. Perps listed less than 7 days ago have no honest baseline and report `multiplier: null` + `band: \"unknown\"` rather than a spurious figure; they sort last. `market_multiplier` (Σ24h ÷ Σ30d-average) is computed over only the coins that have a baseline, so numerator and denominator cover the same set.","NEW `GET /api/v1/volume/scanner/{symbol}` — one perp's multiplier plus `history`, the 30-day daily notional series the baseline is built from (one point per settled UTC day). HL thousand-unit tickers (`kBONK`, `kPEPE`, `kSHIB`) are accepted as aliases. Pro / Pro Plus.","volume/scanner: each item also carries `volume_change_24h` — the live rolling-24h notional against the **most recent settled day** (a like-for-like ~24h window, where `multiplier` compares against the 30-day norm) — and `spark_7d`, the last 7 settled days of daily notional for sparkline rendering. Both are null when the coin has no baseline. Note `change_24h` is and remains the **price** change; the volume equivalent is the new field.","The relative-volume block is now computed by one shared helper (`build_volume_metrics`) behind /volume/scanner, /hyperliquid/summary and the per-coin pages, so the three surfaces can never disagree about a coin's multiplier. No response-shape change from the refactor itself.","hyperliquid/summary: gains three **additive** fields — `avg_volume_30d`, `volume_multiplier` and `volume_band` — so the relative-volume read rides along wherever a single coin is already being fetched. Null until the 30-day baseline has been built, or when the coin is too newly listed to have one. No existing field changed; the ranked full-universe scan stays at /volume/scanner."]},{"version":"2026-07-10","date":"2026-07-10","breaking":false,"changes":["quant/gex: each coin gains a `distribution_context` block — trailing-30-day percentile ranks of the near-mark cluster density, |distance to flip|, normalized MM skew (`mm_net_delta/mm_gross`), regime score and funding rate, plus `history_days`/`sample_count`/`status` honesty fields. Every `*_pctile` is null while `status` is `warming` (< 2 days of hourly samples — the history is forward-only). `meta.distribution_legend` documents each field. The block is also archived in the `gamma_exposure` snapshot type from 2026-07-10.","quant/gex + quant/positioning: Pro-tier keys are now accepted — an edge-gate lag from the 2026-07-08 tier revision was still requiring Pro Plus at the proxy layer and 403'd Pro keys despite both endpoints being Pro endpoints. No change for Pro Plus. (Historical `gamma_exposure` snapshots via /backtesting/snapshots remain Pro Plus.)"]},{"version":"2026-07-06","date":"2026-07-06","breaking":false,"changes":["quant/gex: `regime.flip_price`/`gamma_flip` is now capped to within ±30% of mark and returns `null` when there is no in-band liquidation crossover — previously it could report a level hundreds/thousands of % from mark (stale far-out clusters). Consumers trading 'price vs flip' should treat `null` as 'no meaningful flip', not zero.","quant/gex: each `regime` gains a `confidence` field (0–1) scaling with the MM account count and gross book behind the read, so thin-sample regimes can be down-weighted.","quant/gex: `regime.inputs.realized_liq` now populates for HL 1000x-multiplier meme perps (kPEPE/kBONK/…) — a symbol-key fix maps them to the OKX/Bybit `1000<BASE>` / bare-ticker feeds.","quant/gex: delisted HL markets (zero OI/funding/volume, e.g. TON) no longer surface as empty shells; the universe is the live perp set.","backtesting snapshots: NEW `gamma_exposure` snapshot type — archives the /quant/gex MM-lens per-coin map (mm_net_delta, gamma_profile, gamma_flip, funding/OI + composite regime) at 5-min cadence, byte-parity with the live endpoint. Pull via `/backtesting/snapshots?data_type=gamma_exposure` (Pro Plus).","backtesting snapshots: the existing `liquidation_map` type already carries the full-universe composite `regime` per coin (5-min, since 2026-06-26) — if you consume `liquidation_levels` you can read the regime layer from its sibling `liquidation_map` today.","backtesting funding: HL funding/OI is now archived for the FULL live universe (bulk snapshot, no per-coin cost), so mid-cap coins no longer silently lose their funding series when 24h volume rank drops them out of the top-N kline set."]},{"version":"2026-06-27","date":"2026-06-27","breaking":true,"changes":["quant/gex: `?symbol=X` now returns the bulk envelope `{scope, note, timestamp, meta, coins:{X:{...}}}` — a single-symbol query is the SAME shape as the full response, just narrowed to one coin. Previously it returned a flat per-symbol object. Read `response['coins'][SYMBOL]`. An unknown symbol yields `coins: {}` with HTTP 200 (not 404)."]}]}