Fund data for robo-advisors and model portfolios
A robo-advisor maps a questionnaire answer to a model portfolio of funds, then keeps that portfolio on target over time. This page covers the fund data a robo-advisor needs at each stage, from universe construction to the regulated display of each fund, and how to source it from a single endpoint.The problem
Digital advice products live or die on operational discipline. The fund universe must be documented, every model must be reproducible, rebalancing must run on consistent inputs, and the fund information shown to a client must match what the fund house currently publishes. Doing this across dozens of share classes from several issuers means either a manual data team or an automated feed.
The regulatory side adds constraints. In Europe a retail client must be able to see the KID risk indicator, costs and objective for each fund before investing, and the MiFID II suitability assessment relies on those same attributes.
What you need from the data
Three layers of data support a robo-advisor:
- Universe. Asset class, region, structure, distribution policy, currency, fees and size for every eligible share class, so the investment committee can define inclusion rules.
- Models. For each model portfolio, the target weights plus the per-fund attributes needed to explain the model: risk rating, benchmark, headline volatility, weighted cost.
- Client display. Investment objective, risk rating on the 1–7 scale, ongoing charges, top holdings and an as-of date, presented in a way that mirrors the KID.
Rebalancing itself uses positions and prices from your custodian; fund data supplies the static and semi-static attributes that decide which fund to buy when a sleeve drifts.
How it works with FundFacts API
One request per ISIN returns all three layers. Keep a funds table refreshed daily and build models and client pages on top of it.
typescripttype Sleeve = { isin: string; target: number };export async function describeModel(sleeves: Sleeve[]) {const rows = await Promise.all(sleeves.map(async ({ isin, target }) => {const res = await fetch(`https://fundfactsapi.com/api/v1/funds/${isin}`, {headers: { Authorization: `Bearer ${process.env.FUNDFACTS_API_KEY}` },});if (!res.ok) throw new Error(`${res.status} loading ${isin}`);const { name, data, expiresAt } = await res.json();return {isin,name,target,riskRating: data.riskRating as number | undefined,ter: data.headlineMetrics?.ter as number | undefined,objective: data.investmentObjective as string | undefined,dataAsOf: data.dataAsOf as string | undefined,expiresAt,};}),);const complete = rows.every((r) => typeof r.ter === "number");const weightedTer = rows.reduce((s, r) => s + (r.ter ?? 0) * r.target, 0);return { rows, weightedTer, complete };}
The weighted TER is a common disclosure on a model page; because headlineMetrics.ter is in percent, the result is also in percent. The complete flag matters: if any fund is missing a TER, show the model as incomplete rather than under-reporting cost.
For the client-facing fund page, render investmentObjective, riskRating, headlineMetrics.ter, topHoldings and dataAsOf directly. The SRRI explainer covers how to present the risk scale correctly.
Design notes
Rebalancing inputs. Store the fund attributes you relied on when a rebalance was decided (risk rating, TER, benchmark) alongside the trade log. Regulators ask "why this fund on that date", and a snapshot answers it.
Caching. The API refreshes every 24 hours; expiresAt tells you when. A nightly job that re-loads expired ISINs keeps a universe of a few hundred share classes current within a Pro or Scale quota, depending on size. Client page requests should never hit the API directly.
Quota and errors. Watch X-RateLimit-Remaining in the nightly job and stop cleanly on 429. A 404 fund_not_found for a fund already in a model should raise an alert: it may have been merged or closed. Treat 502 upstream_error as retry-tomorrow and keep yesterday's record.
Share-class hygiene. Models should reference a specific share class ISIN, not a fund name. Accumulating and distributing classes of the same fund have different ISINs and different tax treatment; see accumulating vs distributing.
Disclaimers. Fund attributes are facts read from the documents the fund house publishes. Show dataAsOf next to them, state that past performance is not a guide to future returns, and keep the suitability logic, which is advice, separate from the data layer.