How do I get notified when a fund's TER, risk indicator or holdings change?
The Scale plan's change feed (GET /api/v1/changes?since=) lists every tracked field that moved between refreshes, and signed webhooks push the same events. Which fields are tracked, the event shape and the signature check.Updated 12 September 2026 · by FundFacts APIShort answer
On the Scale plan, GET https://fundfactsapi.com/api/v1/changes?since=<ISO date>&isins=A,B returns every tracked field that changed between refreshes (TER, risk indicator, AUM, manager, distribution policy, holdings count, benchmark, objective and the top-five holdings) as fund.changed events, plus fund.refreshed when the as-of date moves. Webhooks registered through POST /webhooks push the same events to your URL, signed with an HMAC in the X-FundFacts-Signature header, with retries. The feed itself is free to read.
Tracked fields
A refresh compares the new payload with the one it replaces. A difference in any of these produces one fund.changed row per field, with the old and the new value:
headlineMetrics.terriskRatingkeyFacts.aum,keyFacts.manager,keyFacts.distribution,keyFacts.holdingsbenchmarkName,investmentObjective- the top-five names in
topHoldings
A change of data.dataAsOf alone (a new factsheet with the same tracked values) produces fund.refreshed.
Polling the feed
bashcurl -s "https://fundfactsapi.com/api/v1/changes?since=2026-09-01T00:00:00Z&isins=IE00B4L5Y983,IE00B3RBWM25" -H "Authorization: Bearer $FUNDFACTS_API_KEY"
json{"since": "2026-09-01T00:00:00.000Z", "count": 2, "hasMore": false, "nextSince": "2026-09-11T06:02:11.000Z","changes": [{ "id": 8812, "isin": "IE00B4L5Y983", "name": "iShares Core MSCI World UCITS ETF", "event": "fund.changed", "field": "headlineMetrics.ter", "old": "0.20%", "new": "0.18%", "dataAsOf": "2026-09-01", "changedAt": "2026-09-11T06:02:11.000Z" },{ "id": 8813, "isin": "IE00B4L5Y983", "name": "iShares Core MSCI World UCITS ETF", "event": "fund.refreshed", "field": "dataAsOf", "old": "2026-08-01", "new": "2026-09-01", "dataAsOf": "2026-09-01", "changedAt": "2026-09-11T06:02:11.000Z" }]}
Filter with event=fund.changed or fund.refreshed and page with limit (up to 1,000); store nextSince and pass it on the next call while hasMore is true. Reading the feed is free; the funds must be in the store, so keep them warm with a daily batch call.
Webhooks
bashcurl -s -X POST https://fundfactsapi.com/api/v1/webhooks -H "Authorization: Bearer $FUNDFACTS_API_KEY" -H "Content-Type: application/json" \-d '{"url":"https://example.com/hooks/fundfacts","events":["fund.changed"]}'
Every delivery is signed: X-FundFacts-Signature: t=<unix>,v1=<HMAC-SHA256(secret, "<t>.<body>")>. Verify the HMAC with the secret returned at creation, reject stale timestamps, and answer 2xx quickly; failed deliveries are retried with back-off up to six times, and an endpoint that keeps failing is disabled. Manage endpoints from the dashboard or GET/POST /webhooks, DELETE /webhooks/{id}.
Without Scale
On Pro, store each payload with expiresAt, re-fetch after expiry and diff the fields you care about yourself; the tracked-field list above is a good template. The compliance monitoring use case describes the full workflow.
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]}'