---
title: "ETF top-N holdings (canonical PortfolioSurface)"
method: GET
path: "/data/etf/{ticker}/holdings"
tags: ["Funds Data Plane"]
---

# ETF top-N holdings (canonical PortfolioSurface)

`GET /data/etf/{ticker}/holdings`

## Request

- Base URL: `https://riskmodels.app/api`
- URL: `https://riskmodels.app/api/data/etf/{ticker}/holdings`
- Auth: one of:
  - HTTP bearer
  - none

Top-N current holdings of an ETF, read from its canonical `PortfolioSurface` zarr (Funds_DAG `etf_holdings_zarr` — `source_kind=etf`, `teo_frequency=daily`). Only the in-ERM3 sleeve is materialized, so every holding carries a `bw_sym_id` plus its current `ticker` and `name` (null when the id does not resolve; `POST /api/data/symbols/batch` with `{"symbols": [...]}` does the same lookup). `format=csv` returns the rows as a CSV download. `report_date` (the sponsor's "Fund Holdings as of" date) and `availability_date` (when that file was first observed) are surfaced distinctly — never collapsed — and also as headers `X-Data-As-Of` (= `report_date`) and `X-Data-Availability` (= `availability_date`).

v1 returns the latest snapshot only (no `?as_of=` query). See docs/architecture/CANONICAL_INTELLIGENCE_OBJECTS.md §9.

## Path parameters

- `ticker` string, required

## Query parameters

- `top` integer
- `format` 'json' | 'csv'

## Response `200`

ETF holdings snapshot.

- object
  - `portfolio_id` string
  - `ticker` string
  - `source_kind` 'etf'
  - `teo_frequency` 'daily'
  - `sponsor` string, nullable
  - `report_date` string, date
  - `availability_date` string, date, nullable
  - `aum_reported` number, nullable
  - `aum_erm3` number, nullable
  - `coverage_pct` number, nullable: aum_erm3 / aum_reported — in-ERM3 share of the resolved sleeve.
  - `n_holdings_returned` integer
  - `n_total_holdings` integer
  - `holdings` object[]
    - `bw_sym_id` string
    - `ticker` string, nullable: Current ticker for bw_sym_id; null when unresolved.
    - `name` string, nullable
    - `adj_mv` number
    - `weight` number, nullable

## Other responses

- `400`: Unknown `format` value.
- `404`: ETF not found or no holdings available.

---

[API](https://skmtc.dev/riskmodels/apis/riskmodels-api.md) · [All operations](https://skmtc.dev/riskmodels/apis/riskmodels-api/llms.txt) · [OpenAPI document](https://skmtc.dev/riskmodels/apis/riskmodels-api/revisions/1a034cad408a?raw)
