Spot ETF overview (issuer disclosures)
Holdings, net assets and net flow of spot crypto ETFs for one asset, summed over the funds CoinBoss can collect from issuer disclosures, with the full fund list and the reason for every fund that is missing.
/api/sd/etf/overviewRequest
Query parameters
| Name | Type | Required | Default | Allowed values | Description |
|---|---|---|---|---|---|
| asset | string | Required | — | BTC, ETH, SOL, HYPE | Underlying asset, case-insensitive. `coin` is accepted as an alias. Example: BTC |
Example request
curl -s "https://www.coinboss.com/api/sd/etf/overview?asset=BTC"Response fields
The field table is generated from real responses, so it lists exactly what the endpoint returns. Paths use a[] for array items and {*} for objects keyed by a dynamic name such as a coin or an exchange.
| Field | Type | Unit | Description |
|---|---|---|---|
| success | boolean | — | true when the request succeeded. On failure the body is `{ success: false, code, error, request_id }`. |
| schema | string | — | Schema id of this response. It changes only when an existing field changes meaning or type. |
| now | number | ms | Server time when the response was built. |
| asset | string | — | Underlying asset. |
| as_of | string | — | Newest issuer as-of date among covered funds. |
| as_of_min | string | — | Oldest issuer as-of date among covered funds. |
| expected_as_of | string | — | Most recent US trading day whose publication deadline has passed. |
| totals_scope | string | — | Always `covered_funds_only`: totals are not whole-market totals. |
| funds_total | number | — | Funds registered for the asset. |
| funds_covered | number | — | Funds with fresh issuer data. |
| holdings_coin_total | number | coin | Coin holdings summed over covered funds. |
| holdings_funds | number | — | Funds included in `holdings_coin_total`. |
| aum_usd_total | number | USD | Net assets summed over covered funds. |
| aum_funds | number | — | Funds included in `aum_usd_total`. |
| net_flow_usd | number | USD | Net creation / redemption summed over the funds whose flow date equals `net_flow_as_of`. CoinBoss method. |
| net_flow_as_of | string | — | Date the net flow is booked on. |
| net_flow_funds_covered | number | — | Funds included in `net_flow_usd`. |
| net_flow_funds | array | — | Tickers included in `net_flow_usd`. |
| net_flow_funds[] | string | — | Tickers included in `net_flow_usd`. |
| net_flow_missing | array | — | Covered funds not included in `net_flow_usd`, each with the reason. |
| net_flow_missing[] | object | — | Covered funds not included in `net_flow_usd`, each with the reason. |
| net_flow_missing[].ticker | string | — | Fund ticker. |
| net_flow_missing[].reason | string | — | Machine-readable reason code. |
| net_flow_missing[].flow_as_of | string|null | — | Date the flow is booked on. |
| funds | array | — | One row per registered fund, including funds that cannot be collected. |
| funds[] | object | — | One row per registered fund, including funds that cannot be collected. |
| funds[].ticker | string | — | Fund ticker. |
| funds[].issuer | string | — | Fund issuer id. |
| funds[].name | string | — | Fund name. |
| funds[].status | string | — | OK, STALE, ERROR or UNAVAILABLE. |
| funds[].as_of_date | string|null | — | Issuer as-of date of the row. |
| funds[].holdings_coin | number|null | coin | Coins held, as disclosed by the issuer. |
| funds[].holdings_usd | number|null | USD | Market value of the holdings, as disclosed by the issuer. |
| funds[].ref_price | number|null | USD | Reference price per coin used by the issuer. |
| funds[].aum_usd | number|null | USD | Net assets of the fund. |
| funds[].aum_src | string|null | — | How net assets were obtained: `reported`, `nav_x_shares` or `holdings_mv_sum`. |
| funds[].shares_out | number|null | shares | Shares outstanding. |
| funds[].shares_src | string|null | — | How shares outstanding were obtained: `reported` or derived from net assets and NAV. |
| funds[].nav | number|null | USD | Net asset value per share. |
| funds[].market_price | number|null | USD | Closing market price per share. |
| funds[].premium_pct | number|null | % | Premium (+) or discount (−) of market price to NAV, as published by the issuer. |
| funds[].fee_pct | number|null | % | Sponsor fee per year; `null` when not published. |
| funds[].flow_usd | number|null | USD | Net creation / redemption of the fund on its flow date. CoinBoss method. |
| funds[].flow_shares | number|null | shares | Change in shares outstanding. |
| funds[].flow_coin | null | coin | Change in coin holdings; includes fee accrual paid in coin, informational only. |
| funds[].flow_method | string|null | — | Formula used: `shares_x_nav` or `aum_nav_ratio_t1`. |
| funds[].flow_as_of | string|null | — | Date the flow is booked on. |
| funds[].flow_obs_date | string|null | — | As-of date of the newer of the two rows used. |
| funds[].flow_prev_date | string|null | — | As-of date of the older of the two rows used. |
| funds[].flow_note | string|null | — | Why the flow is missing or special (for example `no_previous_row`, `multi_day_gap`). |
| funds[].is_stale | boolean|null | — | True when the data is older than its fresh window. |
| funds[].source_url | string|null | — | Issuer endpoint the row was collected from (lineage only). |
| funds[].observed_at | number|null | ms | Timestamp given by the source for the data. |
| funds[].received_at | number|null | ms | Time the CoinBoss collector received the data. |
| funds[].unavailable_reason | string|null | — | Reason code when the fund cannot be collected. |
| funds[].unavailable_detail | string|null | — | Explanation when the fund cannot be collected. |
| coverage | object | — | What is and is not included in the numbers. Compare this before comparing totals with another source. |
| coverage.included_exchanges | array | — | Sources whose fresh data is included. |
| coverage.included_exchanges[] | string | — | Sources whose fresh data is included. |
| coverage.unavailable | array | — | Sources that could not be included, each with a reason. They are never counted as 0. |
| coverage.unavailable[] | object | — | Sources that could not be included, each with a reason. They are never counted as 0. |
| coverage.unavailable[].exchange | string | — | Exchange id (lower case). |
| coverage.unavailable[].issuer | string | — | Fund issuer id. |
| coverage.unavailable[].reason | string | — | Machine-readable reason code. |
| coverage.unavailable[].detail | string | — | Human-readable explanation of the reason. |
| coverage.stale_excluded | array | — | Rows left out because their last update is outside the fresh window. empty in the samples used to generate this table |
| method | object | — | Plain-text statement of the formulas used for this response, one entry per field. |
| method.holdings_coin_total | string | — | Formula note for `holdings_coin_total`, plain text. |
| method.aum_usd_total | string | — | Formula note for `aum_usd_total`, plain text. |
| method.net_flow_usd | string | — | Formula note for `net_flow_usd`, plain text. |
| method.net_flow_missing | string | — | Formula note for `net_flow_missing`, plain text. |
| method.flow_coin | string | — | Formula note for `flow_coin`, plain text. |
| method.premium_pct | string | — | Formula note for `premium_pct`, plain text. |
| method.is_stale | string | — | Formula note for `is_stale`, plain text. |
| method.units | string | — | Formula note for `units`, plain text. |
| meta | object | — | Lineage and freshness of this response. |
| meta.schema | string | — | Schema id of this response. It changes only when an existing field changes meaning or type. |
| meta.source | array | — | Upstream public endpoints the data was collected from. |
| meta.source[] | object | — | Upstream public endpoints the data was collected from. |
| meta.source[].exchange | string | — | Exchange id (lower case). |
| meta.source[].endpoint | string | — | Public endpoint of the source the collector reads (shown for lineage; clients never call it). |
| meta.observed_at | number | ms | Timestamp given by the source for the data. |
| meta.received_at | number | ms | Time the CoinBoss collector received the data. |
| meta.fetched_at | number | ms | Time this response was assembled. |
| meta.window | string | — | Time window the numbers cover. |
| meta.quality | string | — | FRESH, PARTIAL, STALE, BROKEN or UNAVAILABLE, judged from data timestamps and coverage. |
| meta.is_stale | boolean | — | True when the data is older than its fresh window. |
| meta.cache_ttl_s | number | s | Cache lifetime of this response. |
| meta.fallback | string | — | What the endpoint returns when the collector or a source fails. |
Generated 2026-11-11 23:00 UTC from 4 real responses.
Example response
/api/sd/etf/overview?asset=BTC · Real response captured 2026-11-13 03:58:18 UTC. Long arrays and maps are shortened for display: funds had 12 items; meta.source had 5 items; coverage.unavailable had 7 items.
- "success"true
- "schema""coinboss.sd.etf/1"
- "now"1794542298326
- "asset""BTC"
- "as_of""2026-11-12"
- "as_of_min""2026-11-11"
- "expected_as_of""2026-11-11"
- "totals_scope""covered_funds_only"
- "funds_total"12
- "funds_covered"5
- "holdings_coin_total"89855.4854312
- "holdings_funds"5
- "aum_usd_total"6204214916.33
- "aum_funds"4
- "net_flow_usd"0
- "net_flow_as_of""2026-11-11"
- "net_flow_funds_covered"3
- "net_flow_funds"
- "ARKB"
- "BTCO"
- "HODL"
- "net_flow_missing"
- "funds"
- "coverage"
- "included_exchanges"
- "unavailable"
- "stale_excluded"
- "method"
- "holdings_coin_total""sum of issuer-reported coin holdings over covered (non-stale) funds only; NOT a whole-market total, see funds_covered/funds_total"
- "aum_usd_total""sum of fund net assets (USD) over covered funds; aum_src per fund: reported | nav_x_shares (NAV x shares outstanding) | holdings_mv_sum (sum of issuer holdings …"
- "net_flow_usd""own method, per fund between two consecutive issuer as-of rows: shares_x_nav = (shares_out[t] - shares_out[t-1]) x NAV[t], dated t; aum_nav_ratio_t1 (issuer pub…"
- "net_flow_missing""covered funds not included in net_flow_usd and why: no_previous_row (needs two consecutive issuer rows), t1_booking_available_next_trading_day (Franklin: flow o…"
- "flow_coin""holdings_coin[t] - holdings_coin[t-1]; includes daily sponsor-fee accrual paid in coin, informational only"
- "premium_pct""issuer-reported premium/discount to NAV in percent; null when the issuer does not publish it"
- "is_stale""fund as_of_date older than the trading day before expected_as_of (expected_as_of = latest NYSE trading day whose T+1 16:00 UTC publication deadline has passed)"
- "units""holdings in coins; aum/flow in USD; nav/market_price in USD per share; fee_pct/premium_pct in percent"
- "meta"
- "schema""coinboss.sd.etf/1"
- "source"
- "observed_at"1794441600000
- "received_at"1794537318126
- "fetched_at"1794542298326
- "window""latest"
- "quality""PARTIAL"
- "is_stale"false
- "cache_ttl_s"300
- "fallback""collector failure keeps the last issuer row with its real as_of_date; a fund whose as_of_date is more than 1 trading day behind the expected as-of is flagged is…"
Verified samples
Besides the example above, the probe calls this endpoint with these parameters and checks the schema each time.
| Parameters | HTTP | Latency | Result |
|---|---|---|---|
| asset=ETH | 200 | 4 ms | Pass PARTIAL |
| asset=SOL | 200 | 4 ms | Pass PARTIAL |
| asset=HYPE | 200 | 2 ms | Pass PARTIAL |
| — | 400 | 1 ms | Pass returns the expected error |
Checked 2026-11-13 03:58:18 UTC
Details
- Authentication
- None. Public endpoint.
- Rate limit
- 1200 requests per minute per IP
- Server cache
- 5m
- Edge micro-cache
- 10s
- Update frequency
- Three collector rounds per day (02:35, 10:35, 16:35 UTC). Issuers publish once per US trading day, usually the evening of the trade date.
- Window
- Latest issuer as-of date per fund (`as_of`, `as_of_min`); `expected_as_of` is the most recent US trading day whose publication deadline has passed.
- Data sources
- Daily disclosures published by the fund issuers themselves (holdings, net assets, shares outstanding, NAV), collected and stored by CoinBoss (sd_etf_fund_daily). Net flow is computed by CoinBoss from those disclosures.
- Exchange coverage
- Only funds whose issuer publishes machine-readable daily data are covered. `funds_total` and `funds_covered` state how many; every fund that is not covered is listed under `coverage.unavailable` with the reason. Totals are sums over covered funds only (`totals_scope = "covered_funds_only"`), not the whole market.
- Units
- Amounts in USD; holdings in units of the underlying coin; NAV and market price in USD per share; `premium_pct` and `fee_pct` in percent.
- Method
- Funds that disclose shares outstanding: flow = (shares[t] − shares[t−1]) × NAV[t]. Funds that disclose only net assets and NAV: flow = AUM[t] × NAV[t−1] ÷ NAV[t] − AUM[t−1], booked on t−1. A fund enters `net_flow_usd` only when its flow date equals `net_flow_as_of`; the others are listed in `net_flow_missing`.
- Timestamps
- Unix epoch milliseconds (UTC) unless the field description says otherwise
- Response format
- json
- Stability
- Stable
- Available since
- 2026-11-11
Live status
The endpoint reports data quality PARTIAL — Partial coverage: several large issuers do not offer a public machine-readable disclosure that can be collected from a server. Their funds are listed as unavailable, and totals cover the remaining funds only. Compare `funds_covered` / `funds_total` before comparing totals with other sources.
Availability, last 30 days
100% of 407 checks passed
Errors
Failed calls share one shape on every endpoint. The full list is on the errors page. Errors and rate limits →
| Code | HTTP | Meaning | What to do |
|---|---|---|---|
| INVALID_PARAM | 400 | A required parameter is missing or a value is not accepted. `param` names the parameter when it is known. | Do not retry unchanged; fix the request. |
| UNAUTHORIZED | 401 | The `CB-API-KEY` header was sent but the key is unknown or revoked. Public data needs no key — drop the header or use a valid key. | Do not retry unchanged. |
| FORBIDDEN | 403 | The route is not part of the public API (internal or account-only). | Do not retry. |
| NOT_FOUND | 404 | Unknown route, or the requested coin / exchange / fund does not exist. | Do not retry; check the path and identifiers against the catalog. |
| RATE_LIMITED | 429 | More requests than the per-minute limit. `Retry-After` gives the seconds to wait. | Wait for `Retry-After`, then retry with backoff. |
| INTERNAL | 500 | Unexpected server error. The message is generic by design; quote `request_id` when reporting it. | Retry once after a few seconds; report it with the request id if it persists. |
| UPSTREAM_FAILED | 503 | The data source behind this endpoint did not answer in time. No stale or substitute numbers are returned in its place. | Retry with backoff; check the status page. |
| UNAVAILABLE | 501 / 503 | The dataset is temporarily not ready (cache warming) or the endpoint has no lawful public source yet. | Retry later; the catalog marks endpoints that are unavailable by design. |
| REQUEST_FAILED | 200 | Some older endpoints answer HTTP 200 with `success: false`. Always check `success`, not only the HTTP status. | Depends on the message; treat as a failed request. |
Try it
/api/sd/etf/overviewPartialstring — Underlying asset, case-insensitive. `coin` is accepted as an alias.
https://www.coinboss.com/api/sd/etf/overview?asset=BTCMore in this category
- Spot ETF funds /api/sd/etf/funds
- Spot ETF history /api/sd/etf/history
- Spot ETF overview (issuer disclosures) /api/sd/etf/overview
- Per-fund daily spot-ETF net flows /api/etf/detail
- Daily spot-ETF net-flow history /api/etf/flows
- Single ETF detail /api/etf/fund/:ticker
- ETF fund list /api/etf/funds
- ETF coin holdings per fund /api/etf/holdings
- ETF / trust products of one issuer /api/etf/issuer
- ETF overview /api/etf/overview
- Grayscale trust premium / discount /api/grayscale/premium
- Futures-based ETF volumes /api/indicators/futures-etf-volumes