{"openapi":"3.0.0","paths":{"/v1/flows/summary":{"get":{"description":"Returns the latest net ETF flow (USD millions) for each of the 16 tracked assets — BTC, ETH, SOL, XRP, HYP, DOGE, LINK, AVAX, HBAR, LTC, BNB, DOT, SUI, NEAR, TRX and ZEC. \"Latest\" is the most recent day with a non-zero flow for that asset, so `date` can differ between assets: a small fund with no creations for a few days shows its last active day. For a time series of one asset use `/v1/flows/{asset}`.","operationId":"summary","parameters":[],"responses":{"200":{"description":"Latest non-zero net flow per asset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowsSummaryDto"}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"},"example":{"statusCode":401,"error":"Unauthorized","message":"API key required. Register at cryptoetf.today and pass it as \"Authorization: Bearer <key>\"."}}}},"429":{"description":"More than 120 requests in the current minute for this key. The `Retry-After` header says how many seconds to wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"},"example":{"statusCode":429,"error":"Too Many Requests","message":"Rate limit exceeded (120/min). Retry in 17s."}}}}},"security":[{"ApiKey":[]}],"summary":"Latest net flow for every asset","tags":["Flows"]}},"/v1/flows/{asset}":{"get":{"description":"Returns the daily net ETF flow series of one asset for the last 30 days, ordered oldest → newest. For btc, eth, sol, xrp and hyp every calendar day is listed, with weekends and a day not yet published as `0`; the other assets list trading days only. Flows are T+1: a trading day appears the next morning (UTC).","operationId":"byAsset","parameters":[{"name":"asset","required":true,"in":"path","description":"Lowercase symbol of the asset. Full names work too (bitcoin, ethereum, solana, dogecoin, chainlink, avalanche, hedera, litecoin, polkadot, tron, zcash), and Hyperliquid accepts hyp or hype. Anything else returns 400.","schema":{"enum":["btc","eth","sol","xrp","hyp","doge","link","avax","hbar","ltc","bnb","dot","sui","near","trx","zec"],"type":"string"}}],"responses":{"200":{"description":"Daily net flows of the asset, last 30 days.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssetFlowsDto"}}}},"400":{"description":"Unsupported asset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"},"example":{"statusCode":400,"error":"Bad Request","message":"Unsupported asset \"abc\". Supported: btc, eth, sol, xrp, hyp, doge, link, avax, hbar, ltc, bnb, dot, sui, near, trx, zec."}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"},"example":{"statusCode":401,"error":"Unauthorized","message":"API key required. Register at cryptoetf.today and pass it as \"Authorization: Bearer <key>\"."}}}},"429":{"description":"More than 120 requests in the current minute for this key. The `Retry-After` header says how many seconds to wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"},"example":{"statusCode":429,"error":"Too Many Requests","message":"Rate limit exceeded (120/min). Retry in 17s."}}}}},"security":[{"ApiKey":[]}],"summary":"Daily net flows of one asset","tags":["Flows"]}},"/v1/index/cefi":{"get":{"description":"Returns the composite Crypto ETF Flow Index (CEFI): a 0–100 index of money moving through US spot crypto ETFs on all 16 tracked assets — the current value, its components and recent history. Net flows are added up in dollars and three components are scored against the past year: flow (today's net flow, smoothed, 40%), trend (net flow over 20 trading days, 30%) and breadth (share of funds with inflows, 30%). 50 = zero net flow. This is the only CEFI index: there are no per-asset variants. History covers the last 30 days, trading days only. Methodology: https://cryptoetf.today/en/crypto-etf-sentiment-index","operationId":"composite","parameters":[],"responses":{"200":{"description":"Current CEFI value, its components and 30 days of history.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CefiIndexDto"}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"},"example":{"statusCode":401,"error":"Unauthorized","message":"API key required. Register at cryptoetf.today and pass it as \"Authorization: Bearer <key>\"."}}}},"429":{"description":"More than 120 requests in the current minute for this key. The `Retry-After` header says how many seconds to wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"},"example":{"statusCode":429,"error":"Too Many Requests","message":"Rate limit exceeded (120/min). Retry in 17s."}}}}},"security":[{"ApiKey":[]}],"summary":"CEFI — Crypto ETF Flow Index","tags":["Index"]}},"/v1/tickers":{"get":{"description":"Returns the 16 tracked assets — symbol, internal id and name. Either the `asset` value or the lowercase `symbol` works as the `{asset}` path parameter. Hyperliquid is listed as `HYP`.","operationId":"list","parameters":[],"responses":{"200":{"description":"The 16 tracked assets.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TickerDto"}}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"},"example":{"statusCode":401,"error":"Unauthorized","message":"API key required. Register at cryptoetf.today and pass it as \"Authorization: Bearer <key>\"."}}}},"429":{"description":"More than 120 requests in the current minute for this key. The `Retry-After` header says how many seconds to wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"},"example":{"statusCode":429,"error":"Too Many Requests","message":"Rate limit exceeded (120/min). Retry in 17s."}}}}},"security":[{"ApiKey":[]}],"summary":"List tracked assets","tags":["Tickers"]}},"/v1/prices":{"get":{"description":"Returns the last price and the rolling 24-hour change of each tracked coin (the coin, not the ETF share), quoted in USDT. The answer is cached for 60 seconds and can be up to five minutes old — `updatedAt` tells when it was fetched. A coin the exchange did not return is left out.","operationId":"list","parameters":[],"responses":{"200":{"description":"Last price and 24-hour change per coin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricesDto"}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"},"example":{"statusCode":401,"error":"Unauthorized","message":"API key required. Register at cryptoetf.today and pass it as \"Authorization: Bearer <key>\"."}}}},"429":{"description":"More than 120 requests in the current minute for this key. The `Retry-After` header says how many seconds to wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"},"example":{"statusCode":429,"error":"Too Many Requests","message":"Rate limit exceeded (120/min). Retry in 17s."}}}}},"security":[{"ApiKey":[]}],"summary":"Spot prices of the coins","tags":["Prices"]}},"/v1/analytics/weekly":{"get":{"description":"Returns flow totals for each of the 16 assets over a window of seven calendar days ending today (UTC, `from`…`to`): total net flow, average per listed day, and the number of inflow and outflow days. The window holds about five trading days, and today is usually not published yet (flows are T+1).","operationId":"weekly","parameters":[],"responses":{"200":{"description":"Seven-day totals per asset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WeeklyAnalyticsDto"}}}},"401":{"description":"Missing, unknown or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"},"example":{"statusCode":401,"error":"Unauthorized","message":"API key required. Register at cryptoetf.today and pass it as \"Authorization: Bearer <key>\"."}}}},"429":{"description":"More than 120 requests in the current minute for this key. The `Retry-After` header says how many seconds to wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"},"example":{"statusCode":429,"error":"Too Many Requests","message":"Rate limit exceeded (120/min). Retry in 17s."}}}}},"security":[{"ApiKey":[]}],"summary":"Seven-day flow totals","tags":["Analytics"]}}},"info":{"title":"CryptoETF API","description":"Free REST API for US spot crypto ETF data: daily net flows for 16 assets, the CEFI — Crypto ETF Flow Index, spot prices of the coins and weekly totals. These are the numbers behind [cryptoetf.today](https://cryptoetf.today). Overview, FAQ and the MCP setup: [cryptoetf.today/api](https://cryptoetf.today/en/api).\n\n## Quick start\n\n```bash\ncurl -H \"Authorization: Bearer $CRYPTOETF_KEY\" \\\n  https://api.cryptoetf.today/api/v1/flows/btc\n```\n\n```js\nconst KEY = process.env.CRYPTOETF_KEY;\nconst res = await fetch(\n  \"https://api.cryptoetf.today/api/v1/flows/btc\",\n  { headers: { Authorization: `Bearer ${KEY}` } },\n);\nconst { days } = await res.json(); // oldest → newest\n```\n\n```python\nimport os, requests\n\nKEY = os.environ[\"CRYPTOETF_KEY\"]\nres = requests.get(\n    \"https://api.cryptoetf.today/api/v1/flows/btc\",\n    headers={\"Authorization\": f\"Bearer {KEY}\"},\n)\nres.raise_for_status()\nprint(res.json()[\"days\"][-1])  # newest day\n```\n\n## Authentication\n\nEvery `/v1` request needs a free API key — no card, no plan. Sign in at cryptoetf.today and open your [profile](https://cryptoetf.today/en/profile): the key (`cetf_live_…`) is created there. Send it as `Authorization: Bearer <key>` or as `X-API-Key: <key>`. A missing, unknown or revoked key returns `401`.\n\n## Rate limits\n\n**120 requests per minute per key**, counted in fixed 60-second windows. Responses carry `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` (Unix time in seconds when the window resets). Over the limit the API returns `429` with a `Retry-After` header in seconds.\n\n## Data window and freshness\n\n- **30 days.** Every key reads the last 30 days of history; `windowDays` in the response says so. Older data is not served through the API or MCP — the long-range charts are on [cryptoetf.today](https://cryptoetf.today).\n\n- **T+1.** A trading day becomes available the next morning (UTC), before the US open. The newest day can be revised once later that day. SUI funds arrive a day later.\n\n- **Prices** come from exchange tickers and are cached for 60 seconds; a response can be up to five minutes old — check `updatedAt` in `/v1/prices`.\n\nPer-fund tables and charts: [Flows dashboard](https://cryptoetf.today/en/dashboard) · [Funds](https://cryptoetf.today/en/funds) · [CEFI methodology](https://cryptoetf.today/en/crypto-etf-sentiment-index).\n\n## CEFI — Crypto ETF Flow Index\n\nEvery trading day CEFI adds up the net flows of all spot ETFs on the 16 tracked assets, in dollars. Three parts are scored against the past year: today's flow, smoothed (40%), the net flow of the last 20 trading days (30%) and breadth, the share of funds with inflows (30%). Zero flow scores 50; a typical inflow day scores about 69 and a typical outflow day about 31. There is one composite index — no per-asset variants.\n\n## MCP server for AI agents\n\nThe same data over the Model Context Protocol (Streamable HTTP) at `https://mcp.cryptoetf.today/api/mcp`. **No key and no sign-up**; the limit is 60 requests per minute per IP, and over it the server answers with JSON-RPC error `-32029`. Same 30-day window as the REST API. Tools: `get_flows_summary`, `get_asset_flows`, `get_cefi_index`, `get_prices`, `get_weekly_analytics` (all read-only).\n\n**Claude Code**\n\n```bash\nclaude mcp add --transport http cryptoetf https://mcp.cryptoetf.today/api/mcp\n```\n\n**Claude Desktop** (`claude_desktop_config.json`)\n\n```json\n{\n  \"mcpServers\": {\n    \"cryptoetf\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.cryptoetf.today/api/mcp\"\n    }\n  }\n}\n```\n\n**Cursor** (`~/.cursor/mcp.json` or `.cursor/mcp.json`)\n\n```json\n{\n  \"mcpServers\": {\n    \"cryptoetf\": {\n      \"url\": \"https://mcp.cryptoetf.today/api/mcp\"\n    }\n  }\n}\n```\n\n**Any stdio client** — the bridge package fetches the data from the same server:\n\n```json\n{\n  \"mcpServers\": {\n    \"cryptoetf\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"-y\",\n        \"@zerosix-studio/cryptoetf-mcp\"\n      ]\n    }\n  }\n}\n```\n\nPackage: [@zerosix-studio/cryptoetf-mcp](https://www.npmjs.com/package/@zerosix-studio/cryptoetf-mcp) · source: [zerosix-studio/cryptoetf-mcp](https://github.com/zerosix-studio/cryptoetf-mcp) · [MCP Registry](https://registry.modelcontextprotocol.io): `io.github.sly13/cryptoetf`.\n\n## Conventions\n\n- Dates are UTC, `YYYY-MM-DD`; timestamps are ISO 8601.\n\n- Flows are net, in millions of USD, rounded to 0.1: positive = inflow, negative = outflow.\n\n- `btc` `eth` `sol` `xrp` `hyp` return every calendar day: weekends and a day not yet published come as `0`. The other eleven assets return trading days only.\n\n- The `{asset}` path takes a lowercase symbol (`btc`, `doge`) or a full name (`bitcoin`, `dogecoin`). Hyperliquid is `HYP` in responses; the path takes `hyp` or `hype`.\n\n- The `asset` field in responses is the internal id: `bitcoin`, `ethereum`, `solana`, `xrp`, `hyp`, then the symbol in lowercase for the rest (`doge`, `link`, …).\n\n## Errors\n\nErrors are JSON: `{ \"statusCode\": 401, \"error\": \"Unauthorized\", \"message\": \"…\" }`.\n\n| Status | When |\n| --- | --- |\n| `400` | Unsupported `{asset}`; the message lists the accepted values. |\n| `401` | Missing, unknown or revoked API key. |\n| `429` | Over 120 requests a minute for this key; wait `Retry-After` seconds. |\n\n## Changelog\n\n- **2026-10-03** — CEFI v2: flows summed in dollars across 16 assets; new `components` field (`flow`, `trend`, `breadth`).\n- **2026-10-01** — NEAR, TRX and ZEC added: 16 assets.\n- **2026-08-29** — MCP server limited to 60 requests per minute per IP.\n- **2026-08-22** — DOGE, LINK, AVAX, HBAR, LTC, BNB, DOT and SUI added; CEFI became a single composite.\n- **2026-06-17** — `/v1` launched.\n\n## Terms\n\nUse of the API is covered by the [Terms of Service](https://cryptoetf.today/en/terms). The data is for information and research and is not investment advice. Questions and bug reports: [support](https://cryptoetf.today/en/support).","version":"1.0","contact":{}},"tags":[{"name":"Flows","description":"Daily net flows of US spot crypto ETFs per asset, USD millions."},{"name":"Index","description":"CEFI — Crypto ETF Flow Index: one 0–100 composite over all 16 assets."},{"name":"Tickers","description":"Directory of the 16 tracked assets."},{"name":"Prices","description":"Spot prices of the underlying coins from exchange tickers."},{"name":"Analytics","description":"Seven-day flow totals per asset."}],"servers":[{"url":"https://api.cryptoetf.today/api","description":"API Server"}],"components":{"securitySchemes":{"ApiKey":{"scheme":"bearer","bearerFormat":"API key","type":"http"}},"schemas":{"FlowsSummaryItemDto":{"type":"object","properties":{"symbol":{"type":"string","example":"BTC","description":"Asset ticker symbol."},"asset":{"type":"string","example":"bitcoin","description":"Internal asset id."},"date":{"type":"object","example":"2026-06-16","nullable":true,"description":"Latest day with a non-zero net flow for this asset (UTC). Can differ between assets; null if there is no data."},"netFlowUsdM":{"type":"number","example":245.7,"description":"Net flow on that day in millions of USD, rounded to 0.1 (positive = inflow)."}},"required":["symbol","asset","date","netFlowUsdM"]},"FlowsSummaryDto":{"type":"object","properties":{"assets":{"description":"One entry per tracked asset.","type":"array","items":{"$ref":"#/components/schemas/FlowsSummaryItemDto"}},"updatedAt":{"type":"string","example":"2026-06-16T07:50:00.000Z","description":"Response generation time (UTC, ISO 8601)."}},"required":["assets","updatedAt"]},"ApiErrorDto":{"type":"object","properties":{"statusCode":{"type":"number","example":401,"description":"HTTP status code."},"error":{"type":"string","example":"Unauthorized","description":"HTTP status text."},"message":{"type":"string","example":"Invalid or revoked API key.","description":"What went wrong, in plain English."}},"required":["statusCode","error","message"]},"FlowPointDto":{"type":"object","properties":{"date":{"type":"string","example":"2026-06-16","description":"Day in UTC (YYYY-MM-DD). btc, eth, sol, xrp and hyp list every calendar day; the other assets list trading days only."},"netFlowUsdM":{"type":"number","example":245.7,"description":"Net ETF flow for the day in millions of USD, rounded to 0.1. Positive = net inflow, negative = net outflow. For btc, eth, sol, xrp and hyp a weekend or a day not yet published is 0."}},"required":["date","netFlowUsdM"]},"AssetFlowsDto":{"type":"object","properties":{"symbol":{"type":"string","example":"BTC","description":"Asset ticker symbol."},"asset":{"type":"string","example":"bitcoin","description":"Internal asset id: bitcoin, ethereum, solana, xrp, hyp, then the lowercase symbol (doge, link, …)."},"windowDays":{"type":"number","example":30,"description":"Days of history this key can read: 30 for every key."},"days":{"description":"Daily net flows, ordered oldest → newest.","type":"array","items":{"$ref":"#/components/schemas/FlowPointDto"}},"updatedAt":{"type":"string","example":"2026-06-16T07:50:00.000Z","description":"Response generation time (UTC, ISO 8601)."}},"required":["symbol","asset","windowDays","days","updatedAt"]},"CefiComponentsDto":{"type":"object","properties":{"flow":{"type":"number","example":59,"description":"Flow: today's net flow, smoothed (40% of the index)."},"trend":{"type":"number","example":74,"description":"Trend: net flow over 20 trading days (30% of the index)."},"breadth":{"type":"number","example":62,"description":"Breadth: share of funds with inflows (30% of the index)."}},"required":["flow","trend","breadth"]},"IndexPointDto":{"type":"object","properties":{"date":{"type":"string","example":"2026-06-16","description":"Date (UTC, YYYY-MM-DD)."},"value":{"type":"number","example":64,"description":"CEFI value for that trading day: an integer 0–100, 50 = zero net flow."}},"required":["date","value"]},"CefiIndexDto":{"type":"object","properties":{"index":{"type":"string","example":"CEFI-Composite","description":"Index id. Always CEFI-Composite: there is one index for all 16 assets."},"current":{"type":"number","example":64,"description":"Latest value: an integer 0–100. 50 = zero net flow; a typical inflow day is about 69, a typical outflow day about 31."},"components":{"nullable":true,"description":"Components of the current value; null while the history is too short to score all three.","allOf":[{"$ref":"#/components/schemas/CefiComponentsDto"}]},"date":{"type":"string","example":"2026-06-16","description":"Trading day of the current value (UTC, YYYY-MM-DD)."},"windowDays":{"type":"number","example":30,"description":"Days of history this key can read: 30 for every key."},"history":{"description":"Index history for trading days, ordered oldest → newest.","type":"array","items":{"$ref":"#/components/schemas/IndexPointDto"}}},"required":["index","current","components","date","windowDays","history"]},"TickerDto":{"type":"object","properties":{"symbol":{"type":"string","example":"BTC","description":"Ticker symbol."},"asset":{"type":"string","example":"bitcoin","description":"Internal asset id; works as the {asset} path parameter."},"name":{"type":"string","example":"Bitcoin","description":"Human-readable asset name."}},"required":["symbol","asset","name"]},"PriceDto":{"type":"object","properties":{"symbol":{"type":"string","example":"BTC","description":"Ticker symbol."},"priceUsd":{"type":"number","example":67432.1,"description":"Last price of the coin against USDT on the exchange (≈ USD)."},"change24hPct":{"type":"number","example":1.83,"description":"Rolling 24-hour price change on the exchange, percent, rounded to 0.01."}},"required":["symbol","priceUsd","change24hPct"]},"PricesDto":{"type":"object","properties":{"prices":{"description":"One entry per tracked asset. An asset the exchange did not return is left out.","type":"array","items":{"$ref":"#/components/schemas/PriceDto"}},"updatedAt":{"type":"string","example":"2026-06-16T07:50:00.000Z","description":"When the prices were fetched from the exchange (UTC, ISO 8601). Cached for 60 s; can be up to 5 minutes old."}},"required":["prices","updatedAt"]},"WeeklyAssetDto":{"type":"object","properties":{"symbol":{"type":"string","example":"BTC","description":"Ticker symbol."},"asset":{"type":"string","example":"bitcoin","description":"Internal asset id."},"netFlowUsdM":{"type":"number","example":1203.4,"description":"Total net flow over the window, millions of USD, rounded to 0.1."},"avgDailyUsdM":{"type":"number","example":171.9,"description":"Total divided by the number of days listed in the window: 7 for btc, eth, sol, xrp and hyp (weekends count as 0), trading days only for the other assets. Millions of USD."},"positiveDays":{"type":"number","example":3,"description":"Number of days with net inflow (> 0) in the window."},"negativeDays":{"type":"number","example":2,"description":"Number of days with net outflow (< 0) in the window."}},"required":["symbol","asset","netFlowUsdM","avgDailyUsdM","positiveDays","negativeDays"]},"WeeklyAnalyticsDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-06-10","description":"Window start (UTC, inclusive): six days before `to`."},"to":{"type":"string","example":"2026-06-16","description":"Window end (UTC, inclusive): today, so the latest day may not be published yet."},"assets":{"description":"One entry per tracked asset.","type":"array","items":{"$ref":"#/components/schemas/WeeklyAssetDto"}}},"required":["from","to","assets"]}}}}