Fund Portfolio Exposure API
Roll any ETF or mutual fund portfolio into weighted buckets — by sector, industry, country, asset class or security type — computed server-side from position-level SEC filings, for the latest reporting period or for a run of up to 56 of them in one call. Weights are re-derived from market value rather than summed from the filed percentages, so every period closes at exactly 100.0000% and a stacked area chart's bands do not wander. The API is free to use.
Use this endpoint to:
https://data.businessquant.com/funds/exposure?ticker={ticker}&breakdown={breakdown}&periods={periods}&api_key={api_key}
Related endpoints: The position list behind these buckets is on the Fund Holdings API. For per-holding weights across every period rather than per-bucket, use the Holdings Over Time API. The Reporting Periods API lists which periods a fund has, and the Fund Overview API carries the fees and objective.
1. Request Parameters
One identifier is required; breakdown and periods are optional and default to a single latest-period sector split. There is no paging — a breakdown is at most a few dozen rows per period.
| Parameter | Description |
|---|---|
| api_key |
Required
Your unique API key for authentication.
|
| ticker |
Conditional Identifier
The fund or ETF ticker. A ticker identifies a share class, not a fund — VOO and VFIAX are two classes of the same portfolio, so the fees you get back are the ones that class charges. Either ticker or seriesid is required.
Example:
ticker=VOO |
| seriesid |
Conditional Identifier
The SEC Series ID of the fund. Resolves to the fund's lowest-cost share class. Use this when you want the fund rather than a particular class, or for funds that have no ticker of their own.
Example:
seriesid=S000002839 |
| breakdown |
Optional
Which dimension to group by. Default sector. Accepted values:sector industry country asset_class security_type
Example:
breakdown=country |
| periods |
Optional
How many reporting periods to return, newest first. Default 1 — the latest breakdown only. Range 1–56. Every row carries its own reportperiod, so the shape of the response does not change when you raise this.
Example:
periods=12 |
What each breakdown actually groups on. sector and industry classify the issuer, one level apart. country is the issuer's country, not the listing venue. asset_class is the instrument type — Equity, Fixed Income, Derivative, Fund & Cash Equivalents, Other. security_type is the issuer category — Corporate, US Treasury, Municipal, US Government Agency and so on — which is the split that matters for a bond fund and is nearly meaningless for an equity one.
curl -X GET "https://data.businessquant.com/funds/exposure?ticker=VOO&breakdown=sector&api_key=YOUR_API_KEY"
{
"metadata": {
"ticker": "VOO",
"seriesid": "S000002839",
"classid": "C000092055",
"cik": 1004655,
"fund_name": "Vanguard 500 Index Fund",
"class_name": "ETF Shares",
"gross_expense_ratio_pct": 0.03,
"net_expense_ratio_pct": 0.03,
"net_assets_usd": 1421263311402.89,
"net_assets_asof": "2026-03-31",
"breakdown": "sector",
"breakdown_field": "sector",
"periods": [
"2026-03-31"
],
"period_count": 1,
"period_latest": "2026-03-31",
"period_earliest": "2026-03-31",
"bucket_count": 12
},
"data": [
{
"reportperiod": "2026-03-31",
"bucket": "Technology",
"market_value": 586298948762.74,
"holdings_count": 92,
"weight_pct": 41.1947
},
{
"reportperiod": "2026-03-31",
"bucket": "Financial Services",
"market_value": 148533422244.17,
"holdings_count": 66,
"weight_pct": 10.4363
},
{
"reportperiod": "2026-03-31",
"bucket": "Healthcare",
"market_value": 130915529753.13,
"holdings_count": 58,
"weight_pct": 9.1984
},
{
"reportperiod": "2026-03-31",
"bucket": "Consumer Discretionary",
"market_value": 125892579101.92,
"holdings_count": 35,
"weight_pct": 8.8455
},
{
"reportperiod": "2026-03-31",
"bucket": "Industrials",
"market_value": 117591385928.23,
"holdings_count": 79,
"weight_pct": 8.2622
},
{
"reportperiod": "2026-03-31",
"bucket": "Other",
"market_value": 91158353029.97,
"holdings_count": 50,
"weight_pct": 6.405
},
{
"reportperiod": "2026-03-31",
"bucket": "Consumer Staples",
"market_value": 71498198397.5,
"holdings_count": 34,
"weight_pct": 5.0236
},
{
"reportperiod": "2026-03-31",
"bucket": "Energy",
"market_value": 53983760715.01,
"holdings_count": 19,
"weight_pct": 3.793
},
{
"reportperiod": "2026-03-31",
"bucket": "Basic Materials",
"market_value": 30835515052.02,
"holdings_count": 26,
"weight_pct": 2.1666
},
{
"reportperiod": "2026-03-31",
"bucket": "Communication Services",
"market_value": 24659489631.41,
"holdings_count": 15,
"weight_pct": 1.7326
},
{
"reportperiod": "2026-03-31",
"bucket": "Utilities",
"market_value": 22974073633.97,
"holdings_count": 21,
"weight_pct": 1.6142
},
{
"reportperiod": "2026-03-31",
"bucket": "Real Estate",
"market_value": 18897471303.12,
"holdings_count": 24,
"weight_pct": 1.3278
}
]
}
2. Response Fields
Standard metadata / data envelope. Rows are ordered by market value within each period, largest bucket first, and periods run newest to oldest.
metadata
| Field | Type | Description |
|---|---|---|
| ticker, seriesid, classid, cik | string | Fund and share-class identity. |
| fund_name, class_name | string | Registered fund name and resolved share class. |
| net_assets_usd, net_assets_asof | float, date | Fund net assets and the date reported. |
| breakdown | string | The breakdown that was applied, echoed back. |
| breakdown_field | string | The underlying column it grouped on — country maps to country_name, security_type to issuer_category. |
| periods | array | Every reportperiod present in data, newest first. |
| period_count, period_latest, period_earliest | integer, date, date | Size and bounds of the returned window. |
| bucket_count | integer | Number of distinct buckets across all returned periods. |
data — one row per (period, bucket)
| Field | Type | Description |
|---|---|---|
| reportperiod | date | The period this bucket belongs to. Present on every row even when periods=1, so the response shape never changes. |
| bucket | string | The bucket label — a sector, industry, country, asset class or issuer category. null when the underlying positions carry no classification. |
| market_value | float | Total absolute market value of the positions in this bucket, in USD. |
| holdings_count | integer | Number of positions in the bucket. |
| weight_pct | float | Bucket weight in percent, re-derived from market value. Within any single period these sum to exactly 100.0000. |
Why weight is re-derived rather than summed from filed weights. A filed portfolio sums to roughly 99–103%, so summing filed weights per bucket produces columns that do not close at 100 — visible as wandering band edges on a stacked area chart and as a pie that does not quite fill. Here each bucket's weight is its share of that period's total absolute market value, partitioned by period, so every period closes at exactly 100.0000%. The as-filed weights are still available per position on the Fund Holdings API.
3. Response Viewer — Single Period
A real response for ticker=VOO&breakdown=sector. The bars are drawn in this page from weight_pct; they are not part of the payload.
API Response — Sector Exposure
Vanguard 500 Index Fund · breakdown=sector
| # | Bucket | Positions | Market Value | Weight | |
|---|---|---|---|---|---|
| 1 | Technology | 92 | $586.30B | 41.1947% | |
| 2 | Financial Services | 66 | $148.53B | 10.4363% | |
| 3 | Healthcare | 58 | $130.92B | 9.1984% | |
| 4 | Consumer Discretionary | 35 | $125.89B | 8.8455% | |
| 5 | Industrials | 79 | $117.59B | 8.2622% | |
| 6 | Other | 50 | $91.16B | 6.4050% | |
| 7 | Consumer Staples | 34 | $71.50B | 5.0236% | |
| 8 | Energy | 19 | $53.98B | 3.7930% | |
| 9 | Basic Materials | 26 | $30.84B | 2.1666% | |
| 10 | Communication Services | 15 | $24.66B | 1.7326% | |
| 11 | Utilities | 21 | $22.97B | 1.6142% | |
| 12 | Real Estate | 24 | $18.90B | 1.3278% |
4. Response Viewer — Multiple Periods
The same endpoint with periods=3 against an actively managed fund, where allocation actually moves. The payload is one flat row per (period, bucket); the grid below is that payload pivoted in this page, which is the two lines of client code the flat shape is designed to make easy.
API Response — Sector Exposure Over Time
ARK Innovation ETF · breakdown=sector&periods=3
| Bucket | 2025-10-31 | 2026-01-30 | 2026-04-30 | Change |
|---|---|---|---|---|
| Technology | 45.80% | 45.05% | 43.30% | -2.49 pp |
| Healthcare | 23.88% | 27.69% | 26.69% | +2.81 pp |
| Consumer Discretionary | 15.62% | 13.91% | 12.45% | -3.17 pp |
| Financial Services | 8.19% | 7.23% | 8.68% | +0.49 pp |
| Industrials | 5.32% | 6.03% | 6.10% | +0.78 pp |
| Other | 0.75% | 0.09% | 2.77% | +2.02 pp |
| Communication Services | 0.43% | — | — | — |
5. More Request Examples
Five breakdowns, one period argument. Every combination is valid.
https://data.businessquant.com/funds/exposure?ticker=VOO&breakdown=sector&api_key=YOUR_API_KEY
https://data.businessquant.com/funds/exposure?ticker=VXUS&breakdown=country&api_key=YOUR_API_KEY
https://data.businessquant.com/funds/exposure?ticker=AGG&breakdown=security_type&api_key=YOUR_API_KEY
https://data.businessquant.com/funds/exposure?ticker=AOR&breakdown=asset_class&api_key=YOUR_API_KEY
https://data.businessquant.com/funds/exposure?ticker=ARKK&breakdown=sector&periods=12&api_key=YOUR_API_KEY
https://data.businessquant.com/funds/exposure?ticker=QQQ&breakdown=industry&api_key=YOUR_API_KEY
6. Use Cases
The aggregation happens server-side, so these are all one request each.
Allocation Donut And Bar Charts
bucket and weight_pct bind straight to a chart with no client-side aggregation, and because the weights close at exactly 100 the segments fill the circle.
Style Drift Monitoring
Raise periods and watch whether a fund's sector mix still matches what its prospectus claims. An actively managed fund that has quietly become a technology fund shows up here long before it shows up in a fact sheet.
Geographic Risk Screening
breakdown=country against a portfolio of funds answers total exposure to any single country, including exposure held indirectly through funds that do not describe themselves as regional.
Bond Fund Composition
security_type splits Treasuries from agency paper from corporates from municipals — the split that actually characterises a fixed income fund, and the one an equity-oriented breakdown misses.
Fund Comparison On One Axis
Call the endpoint for two tickers with the same breakdown and the bucket labels line up, so the difference in weights is directly comparable without a mapping layer.
Stacked Area Allocation Charts
One call with periods=56 returns the entire history already bucketed and normalised per period, which is exactly the shape a stacked area series needs.
Frequently Asked Questions
The questions developers ask most often about this endpoint.
Why do these weights differ slightly from the fund's own fact sheet?
Because they are re-derived from position market values rather than taken from the filed percentages. A filed portfolio sums to roughly 99–103%, and a fact sheet usually normalises differently — often excluding cash, sometimes excluding derivatives. Here every bucket is its share of the period's total absolute market value, so the column closes at exactly 100.0000%.
What is the difference between asset_class and security_type?
asset_class describes the instrument — Equity, Fixed Income, Derivative, Fund & Cash Equivalents, Other. security_type describes the issuer — Corporate, US Treasury, Municipal, US Government Agency, US Government Sponsored Entity, Non-US State, Registered Fund, Private Fund, Unknown. For an equity fund the second is nearly all Corporate; for a bond fund it is the whole story.
Can I get more than one breakdown in a single call?
No — one breakdown per request. The responses are small (a few dozen rows), so issuing two or three calls in parallel is cheap. If you need a genuine cross-tab, such as sector within country, pull the position list from the Fund Holdings API and group it yourself; every classification column used here is present on each position row.
What does a null bucket mean?
The positions in that group carry no classification for the dimension you asked for — common for cash, for certain derivatives, and for issuers the classification source does not cover. The bucket is still returned with its market value and weight rather than being dropped, so the column still closes at 100.
How many periods can I request at once?
Up to 56, which is every period in the store. Any individual fund only has the periods it filed, so ask for more than it has and you simply get everything it has — metadata.period_count tells you what you actually received.
Is the Fund Portfolio Exposure API free to use?
Yes, the API is free to use. Sign up for an API key and start pulling sector, country and asset class breakdowns immediately — no credit card required.