Getting started

Why does the first request for a fund take so long?

A fund never loaded before is read live from the fund house's documents, which takes 15 seconds to a few minutes. Later calls are instant, even past 24 hours. Timeouts, batches and pre-warming.Published September 12, 2026 · Updated October 25, 2026 · by FundFacts API

Short answer

Because the data is read from the fund house at that moment. A cold ISIN (never loaded, or not in the last 7 days) triggers a read of the product page, factsheet PDF, KID and holdings / NAV files, which takes 15 seconds to about 3 minutes. The server allows 300 seconds; set that timeout and do not send a second request for the same ISIN while the first runs. Every later call returns from the store in well under a second with cached: true; past 24 hours it is flagged stale: true and refreshed in the background.

What happens on a cold load

  1. The issuer adapter resolves the ISIN to the fund house's product page.
  2. The page, the monthly factsheet, the KID and (where published) the holdings and NAV files are fetched and parsed.
  3. Figures are normalised into the data shape, the profile is derived, series are computed.
  4. The payload is stored and returned; it is due for a refresh 24 hours later.

PDF parsing and per-issuer sites set the pace. Two callers asking for the same cold ISIN at once share one load.

Design rules

  • Timeout 300 s on GET /funds/{isin} and POST /funds. Show "loading fund data, first load can take a couple of minutes" in a UI.
  • Never retry in flight. A second request for the same ISIN waits on the same load and, once it completes, is counted too.
  • Batch and let pending work for you. POST /funds with wait: true returns what fits the time budget and marks the rest pending; they finish in the background and the next call finds them warm.
  • Pre-warm in a job, not a request handler. Seed your universe overnight, a few ISINs in parallel at most, and your users only ever hit warm payloads.
  • Cache locally until `expiresAt`. Then even the warm call is saved.

The demo endpoint never loads

GET /demo/funds/{isin} only returns funds already in the store (404 not_cached otherwise), which is why it is instant and keyless.

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.
bash
curl -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]}'

Frequently asked questions

Is a slow call counted more than once?

No: one request per fund found, regardless of whether it took 50 milliseconds from the store or two minutes from the fund house.

Does the 24-hour store expire per fund?

Yes, per ISIN: expiresAt is generatedAt + 24 h. After it the payload is still served at once with stale: true while it refreshes; after 7 days it is read again before answering.

Try it on your own ISINs

One request returns key facts, holdings, risk and performance as JSON. Free plan, no card.