How do I get the SRRI or SRI risk indicator of a fund by ISIN?
The 1–7 synthetic risk indicator printed on the KID for any fund or ETF, from its ISIN as JSON: data.riskRating, plus a low/medium/high band for filtering.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.riskRating in the JSON response (related fields: data.profile.riskBand). The indicator is read from the KID (PRIIPs SRI since 2023 for most UCITS) or, for documents that still print it, the UCITS KIID SRRI; the factsheet's risk scale is used as a cross-check. 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.riskRating | number or null | The 1–7 indicator from the PRIIPs KID (SRI) or UCITS KIID (SRRI). |
data.profile.riskBand | "low" or "medium" or "high" or null | 1–2 low, 3–4 medium, 5–7 high. |
Sample for iShares Core MSCI World UCITS ETF (IE00B4L5Y983):
json"riskRating": 6,"profile": { "riskBand": "high" }
Where the figure comes from
The indicator is read from the KID (PRIIPs SRI since 2023 for most UCITS) or, for documents that still print it, the UCITS KIID SRRI; the factsheet's risk scale is used as a cross-check. The SRRI and SRI glossary entries explain how the two scales differ.
The request
bashcurl -s --max-time 300 https://fundfactsapi.com/api/v1/funds/IE00B4L5Y983 \-H "Authorization: Bearer $FUNDFACTS_API_KEY" | jq '.data.riskRating'
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']['riskRating'])
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.riskRating);
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
- SRI and SRRI are computed differently (the SRI adds a credit-risk component), so the same fund can carry different numbers on old and new documents. The payload carries what the current KID prints.
- Money-market and short-duration funds sit at 1; broad equity ETFs typically at 5 or 6; leveraged and single-country emerging-market funds at 7.
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]}'