---
title: "ETF holdings API: holdings, sector and country weights by ISIN as JSON"
description: "Top holdings with weights, the holdings count and sector, country and asset weights for any UCITS ETF or fund by ISIN, dated, as JSON. Free plan, no card."
canonical: https://fundfactsapi.com/etf-holdings-api
published: 2026-10-06
updated: 2026-10-06
publisher: FundFacts API
---

# ETF holdings API: holdings, sector and country weights by ISIN as JSON

> Top holdings with weights, the holdings count and sector, country and asset weights for any UCITS ETF or fund by ISIN, dated, as JSON. Free plan, no card.

FundFacts API returns the holdings of an ETF or fund from its ISIN as JSON: the largest positions with their weights, the number of holdings, and the sector, country, region and asset-class weights, with the as-of date of the fund house's documents. One GET request with an API key; the Free plan gives 15 lookups a month without a card.

> FundFacts API turns any fund or ETF ISIN into one dated, structured factsheet (fees and KID costs, the 1–7 risk indicator, holdings, sector and country exposure, returns) read from the fund house's own documents: as JSON for your code, inside ChatGPT and Claude through its MCP server, or as a client-ready PDF factsheet.

## What the holdings block contains

Every fund payload carries the same keys; one that does not apply to the fund is an empty array or `null`, never missing.

| Field | Shape | What it holds |
| --- | --- | --- |
| `data.topHoldings` | `[{ name, weight }]` | Largest positions in the fund house's order, weight in percent. |
| `data.holdingsBasis` | `"portfolio"`, `"substituteBasket"` or `null` | The fund's own positions, or a synthetic ETF's swap collateral. |
| `data.keyFacts.holdings` | number | Number of positions in the portfolio. |
| `data.sector` | `[{ label, weight }]` | Sector weights (GICS-style for equity funds). |
| `data.geography`, `data.region` | `[{ label, weight }]` | Country and regional weights. |
| `data.assetAllocation` | `[{ label, weight }]` | Equity, bond and cash split. |
| `data.creditQuality`, `data.maturity` | `[{ label, weight }]` | Rating and maturity buckets for bond funds. |
| `data.profile.concentration` | string | From the weight of the ten largest positions. |
| `data.dataAsOf` | date | As-of date of the figures. |

The same payload carries fees, the risk indicator and returns: see the [ETF data API](https://fundfactsapi.com/etf-data-api) page.

## A request and a trimmed response

```bash
curl -s https://fundfactsapi.com/api/v1/funds/IE00B4L5Y983 \
  -H "Authorization: Bearer $FUNDFACTS_API_KEY"
```

```json
{
  "isin": "IE00B4L5Y983",
  "name": "iShares Core MSCI World UCITS ETF",
  "cached": true,
  "generatedAt": "2026-09-02T20:32:58.872Z",
  "expiresAt": "2026-09-03T20:32:58.872Z",
  "data": {
    "keyFacts": {
      "holdings": 1253
    },
    "topHoldings": [
      { "name": "NVIDIA", "weight": 5.48 },
      { "name": "APPLE", "weight": 5.24 },
      { "name": "MICROSOFT", "weight": 3.88 }
    ],
    "sector": [
      { "label": "Information Technology", "weight": 29.8 },
      { "label": "Financials", "weight": 16.46 },
      { "label": "Industrials", "weight": 11.03 }
    ],
    "geography": [
      { "label": "United States", "weight": 72.07 },
      { "label": "Japan", "weight": 5.85 },
      { "label": "United Kingdom", "weight": 3.49 }
    ],
    "assetAllocation": [
      { "label": "Equity", "weight": 99.75 },
      { "label": "Cash Collateral and Margins", "weight": 0.02 }
    ],
    "profile": {
      "concentration": "diversified"
    },
    "dataAsOf": "2026-09-01"
  }
}
```

This is the real payload for iShares Core MSCI World UCITS ETF, trimmed to three rows per array. Its `topHoldings` lists the ten largest of 1,253 positions, which together weigh 26.7% of the fund. To check the shape without a key, the demo endpoint returns the same envelope for any fund already loaded (30 requests a minute per IP, not for production):

```bash
curl -s https://fundfactsapi.com/api/v1/demo/funds/IE00B4L5Y983
```

## Top ten or longer list: what each fund house publishes

`topHoldings` is what the fund house discloses. It is never estimated.

- **Most funds: the top ten.** The list comes from the factsheet's top-ten table, or from the ten heaviest lines of the fund house's holdings file where it publishes one (iShares does).
- **Longer lists from a few fund houses.** Where the fund house's data lists more positions, up to 50 are kept (Amundi, Franklin Templeton, J.P. Morgan and UBS among them).
- **Names without weights.** Some fund houses publish names only. Every `weight` is then `null`; a list is never mixed.
- **Synthetic ETFs.** A swap-based ETF holds a substitute basket that backs the swap. `holdingsBasis` is then `substituteBasket`, and `sector` and `geography` describe the index instead.

The sector, country and asset weights describe the whole portfolio, from the fund house's own tables or its holdings file, so they are not limited to the listed positions. Where a holdings file exists, `keyFacts.holdings` counts its lines. The [coverage pages](https://fundfactsapi.com/coverage) state, per fund house, which sections the payload fills.

## Overlap and look-through

Two endpoints do the holdings arithmetic for you:

- `GET /overlap?isins=A,B` returns, for each pair of funds, the overlap percentage (the sum of the smaller weight of every shared holding, matched by issuer name), the shared positions and how much of each portfolio was disclosed. When a fund publishes only its top ten, the figure is a lower bound; it is `null`, not 0, when a fund gives names without weights.
- `POST /portfolio` takes weighted positions and returns the combined sector, country, region, asset and currency weights, the combined top holdings, the blended TER and the weighted risk indicator, each with a coverage figure.

Both are included in Pro, Scale and Enterprise and count one request per fund. The free [ETF overlap checker](https://fundfactsapi.com/tools/etf-overlap) and [portfolio look-through](https://fundfactsapi.com/tools/portfolio-look-through) run without a key on funds already loaded.

## What it does not do

- No complete constituent file: `topHoldings` stops at the fund house's list, and each row is a name and a weight, without the holding's ISIN or ticker.
- No intraday holdings, and no regulatory filings such as 13F or N-PORT. Holdings come from the fund house's own documents.
- No prices or quotes. Use a market-data API alongside for those.
- Stocks, bonds and indices are not funds. They return `404 fund_not_found`, which is not counted, up to as many misses a month as the plan's allowance.

## Price

Free is $0: 15 lookups a month, no card, personal use, one ISIN per call. Starter is $9.99 a month for 500 requests and batches of 10, Pro $49 for 9,000 and batches of 50, Scale $249 for 60,000 and batches of 200 (VAT included). Holdings overlap, portfolio look-through and commercial use of the data come with Pro, Scale and Enterprise. One request is counted per fund found; `/search` and the demo endpoint are free. See [pricing](https://fundfactsapi.com/pricing).

## Get started in three steps

1. **See the payload without a key.** `curl -s https://fundfactsapi.com/api/v1/demo/funds/IE00B4L5Y983` returns the full payload of any fund already loaded, holdings and exposure included.
2. **Create a free key.** [Sign up](https://fundfactsapi.com/signup) with an e-mail address or Google. The Free plan gives 15 lookups a month without a card, and the key is in the dashboard.
3. **Request your ETF by ISIN.** Call `GET /api/v1/funds/{isin}` with `Authorization: Bearer <key>`. A fund nobody requested in the last 24 hours takes 15 seconds to 3 minutes to load the first time, so set a 300-second timeout. The [quickstart](https://fundfactsapi.com/docs/quickstart) has the SDK version.

## FAQ

### Is there a free ETF holdings API?

Yes. The FundFacts API Free plan gives 15 lookups a month without a card, with the full payload (holdings, sector and country weights included) for personal, non-commercial use. The demo endpoint `/api/v1/demo/funds/{isin}` needs no key for funds already loaded.

### Does it cover European UCITS ETFs?

Yes. UCITS ETFs are at the core of the coverage, including [iShares](https://fundfactsapi.com/coverage/ishares), [Xtrackers](https://fundfactsapi.com/coverage/xtrackers), [SPDR](https://fundfactsapi.com/coverage/spdr), [Amundi](https://fundfactsapi.com/coverage/amundi), [Vanguard](https://fundfactsapi.com/coverage/vanguard) and [Invesco](https://fundfactsapi.com/coverage/invesco). Each share class is looked up by its own ISIN, and the [coverage pages](https://fundfactsapi.com/coverage) say which sections each fund house fills.

### Can I get the full holdings list?

Not as one complete file. `topHoldings` lists the largest positions the fund house publishes: ten for most funds, up to 50 where its data lists more. The sector, country and asset weights describe the whole portfolio, and `keyFacts.holdings` gives the number of positions.

### How often are holdings updated?

Each ISIN is re-read from the fund house's documents when its payload is older than 24 hours. The holdings are as recent as those documents: `data.dataAsOf` dates them, typically the last month end for a factsheet's top-ten table.

### Does it return ETF prices?

No. There are no quotes, intraday prices or iNAV. The payload carries calendar and annualised returns and monthly return series built from the fund house's published NAV history; use a market-data API alongside for prices.

### Can I look up an ETF by ticker?

Yes, through `GET /search?q=`: it matches an exchange ticker such as VWCE or EUNL, a name or an ISIN prefix among funds already loaded, returns the ISIN and is not counted. The holdings call itself takes the ISIN.

### Can I compare the holdings of two ETFs?

`GET /overlap?isins=A,B` returns the overlap percentage and the shared positions, on Pro, Scale and Enterprise. The free [ETF overlap checker](https://fundfactsapi.com/tools/etf-overlap) does the same in the browser for funds already loaded.

## Related

- [Field reference](https://fundfactsapi.com/docs/fields)
- [Endpoints](https://fundfactsapi.com/docs/endpoints)
- [Quickstart](https://fundfactsapi.com/docs/quickstart)
- [Coverage by fund house](https://fundfactsapi.com/coverage)
- [ETF overlap checker](https://fundfactsapi.com/tools/etf-overlap)
- [Holdings, sector and country exposure (guide)](https://fundfactsapi.com/blog/etf-holdings-api)
- [Get ETF holdings by ISIN](https://fundfactsapi.com/answers/get-etf-holdings)
- [Sector exposure by ISIN](https://fundfactsapi.com/answers/get-sector-exposure-of-a-fund)
- [Country exposure by ISIN](https://fundfactsapi.com/answers/get-country-exposure-of-a-fund)
- [ETF overlap, step by step](https://fundfactsapi.com/answers/how-to-calculate-overlap-between-two-etfs)
- [ETF data API](https://fundfactsapi.com/etf-data-api)
- [Pricing](https://fundfactsapi.com/pricing)

## About FundFacts API

FundFacts API turns any fund or ETF ISIN into one dated, structured factsheet (fees and KID costs, the 1–7 risk indicator, holdings, sector and country exposure, returns) read from the fund house's own documents: as JSON for your code, inside ChatGPT and Claude through its MCP server, or as a client-ready PDF factsheet.

FundFacts works inside ChatGPT and Claude as a connector (a remote MCP server): ask about any fund or ETF by ISIN, ticker or name and the assistant answers from FundFacts' dated figures, fees, risk, holdings, exposure and returns, with fund cards, side-by-side comparisons, holdings overlap and portfolio look-through.

- Free API key, no card: https://fundfactsapi.com/signup
- Documentation: https://fundfactsapi.com/docs (OpenAPI: https://fundfactsapi.com/openapi.json)
- MCP server: https://fundfactsapi.com/api/mcp (set-up for every client: https://fundfactsapi.com/mcp-server)
- Pricing: https://fundfactsapi.com/pricing
- Site index for AI assistants: https://fundfactsapi.com/llms.txt
- Informational data, not investment advice.
