How do I classify a fund by ISIN (asset class, category, region, style)?
A consistent, rule-based classification for any fund or ETF from its ISIN as JSON: data.profile with kind, category, risk band, concentration, region focus, sector tilt, valuation style and credit quality.Updated 12 September 2026 · by FundFacts APIShort answer
Call GET https://fundfactsapi.com/api/v1/funds/{isin} with a bearer API key and read data.profile.kind in the JSON response (related fields: data.profile.category, data.profile.riskBand). The profile is not read from any document: it is derived from the disclosed figures (asset class, exposures, P/E, duration, rating buckets, risk indicator) with rules that are published in the field reference. The Free plan gives 15 lookups a month with no card, and the keyless demo endpoint shows the shape for an already-loaded fund.
Where it is in the response
| Path | Type | Meaning |
|---|---|---|
data.profile.kind | "equity" or "fixedIncome" or "moneyMarket" or "allocation" or "alternative" or "other" | Broad kind. |
data.profile.category | string | Composed category, e.g. "Global Equity", "Euro Corporate Bond". |
data.profile.riskBand | "low" or "medium" or "high" | From the 1–7 indicator. |
data.profile.regionFocus / sectorTilt / valuation / creditQuality / rateSensitivity | string or null | Facets derived from the disclosed exposures with published rules. |
data.profile.rules | string | Version of the rule set, e.g. "fundfacts-profile/1". |
Sample for iShares Core MSCI World UCITS ETF (IE00B4L5Y983):
json"profile": {"kind": "equity", "category": "Global Equity", "riskBand": "high","concentration": "diversified", "regionFocus": "Global", "regionTilt": "United States","sectorTilt": "Broad", "valuation": null, "creditQuality": null, "rateSensitivity": null,"equityShare": null, "rules": "fundfacts-profile/1"}
Where the figure comes from
The profile is not read from any document: it is derived from the disclosed figures (asset class, exposures, P/E, duration, rating buckets, risk indicator) with rules that are published in the field reference. Because the rules are the same for every fund house, the labels are comparable across issuers, which the free-text categories on factsheets are not.
The request
bashcurl -s --max-time 300 https://fundfactsapi.com/api/v1/funds/IE00B4L5Y983 \-H "Authorization: Bearer $FUNDFACTS_API_KEY" | jq '.data.profile'
pythonimport os, requestsr = requests.get("https://fundfactsapi.com/api/v1/funds/IE00B4L5Y983",headers={"Authorization": f"Bearer {os.environ['FUNDFACTS_API_KEY']}"}, timeout=300)fund = r.json()print(fund["name"], fund['data']['profile']['kind'])
javascriptconst res = await fetch("https://fundfactsapi.com/api/v1/funds/IE00B4L5Y983", {headers: { Authorization: `Bearer ${process.env.FUNDFACTS_API_KEY}` },signal: AbortSignal.timeout(300_000),});const fund = await res.json();console.log(fund.name, fund.data.profile.kind);
Sign up at fundfactsapi.com/signup for a key; the Free plan is 15 lookups a month with no card. Without a key, GET https://fundfactsapi.com/api/v1/demo/funds/IE00B4L5Y983 returns the same payload for funds already in the store (30 calls a minute per IP; it never loads a new fund).
Caveats
- It is a classification, not a rating: it says what the fund holds, not whether it is good.
- Facets that need a figure the fund does not publish are null (for example
valuationwithout a P/E).
Several funds at once
POST /funds with { "isins": ["…", "…"], "wait": true } returns the same payload for up to 10 ISINs per call on Starter, 50 on Pro and 200 on Scale. One request is counted per ISIN answered. X-RateLimit-Remaining on every response tells you how many are left this month; a 429 rate_limited response carries Retry-After. Search and /me are free.
A fund nobody has requested in the last 24 hours is loaded on demand from the documents the fund house publishes. That first call takes 15 seconds to about 3 minutes; set your client timeout to 300 seconds and do not fire a second request for the same ISIN while the first is running. Every later call within 24 hours returns from the store in well under a second with cached: true.
Everything else in the payload is listed in the field reference.
Verify it yourself
The demo endpoint returns the live payload for a fund that is already in the store, without a key. Everything on this page can be checked against it.bashcurl -s https://fundfactsapi.com/api/v1/demo/funds/IE00B4L5Y983 | jq '{name, asOf: .data.dataAsOf, ter: .data.headlineMetrics.ter, risk: .data.riskRating, top: .data.topHoldings[:3]}'