---
title: "How fresh is fund data? As-of dates, publication lags and why a 24-hour cache is enough"
description: "Daily NAV, monthly holdings, yearly KID: what 'as of' means for each factsheet block, how to store it, and why a daily refresh matches how funds publish."
canonical: https://fundfactsapi.com/blog/how-fresh-is-fund-data-as-of-dates
published: 2026-09-21
updated: 2026-10-25
publisher: FundFacts API
---

# How fresh is fund data? As-of dates, publication lags and why a 24-hour cache is enough

> Daily NAV, monthly holdings, yearly KID: what 'as of' means for each factsheet block, how to store it, and why a daily refresh matches how funds publish.

Fund data is not one dataset with one update frequency. A fund's NAV is struck daily, its holdings and exposures are published monthly (daily for some ETF issuers), its factsheet is monthly, its KID is reviewed at least annually, and its fund size moves with every dealing day but is reported at the factsheet's date. "Fresh" therefore means "no older than the fund's own publication cadence", and for factsheet-type data that cadence is measured in days to months. A store that refreshes each fund every 24 hours is at least as current as the documents it is built from, and the important thing is not the refresh rate but carrying the as-of date with every figure.

> **In short** Every figure on a factsheet has an "as of" date, and different blocks can have different dates. NAV: daily, published the next business day. Holdings and exposures: monthly for most funds, daily for some ETFs. Fees and risk indicator: from the KID, updated at least yearly. A 24-hour refresh cycle is fine for all of this; intraday updates only matter for exchange prices, which are not factsheet data. Store `dataAsOf` alongside the payload and show it.

## What "as of" means on a factsheet

The date printed near the top of a factsheet is the reporting date: the day the portfolio snapshot was taken, usually the last business day of the month. But it is a snapshot of several things that are not equally fresh:

| Block | Underlying cadence | Typical lag behind the reporting date |
| --- | --- | --- |
| NAV and performance | Daily NAV, published the next business day | None at month end; the factsheet itself appears days to weeks later |
| Fund size (AUM) | Daily | Reported at the factsheet date |
| Top holdings, sector, country | Monthly for most funds; daily holdings files for many ETF issuers | Some issuers lag holdings one month behind performance |
| Number of holdings | Same as holdings | Same |
| TER / ongoing charges | From the KID, reviewed at least annually and when costs change | Can be up to a year old relative to today's actual costs |
| Risk indicator (SRI) | Recalculated per KID rules, updated when it changes class | Same |
| Calendar-year returns | Annual, fixed once the year closes | None |

So a factsheet dated 31 August can carry August performance, July holdings and a February KID's fee. This is normal and not an error. The practical consequence is that a single "last updated" timestamp on a fund record is not enough; you want the date each figure refers to.

## The two dates you should store

FundFacts API returns two dates for every fund, and they answer different questions:

- `data.dataAsOf` is the date the figures refer to: the as-of date the issuer's documents state (the factsheet's reporting date, a holdings file's date), otherwise the latest NAV observation. This is the date to show next to the numbers ("data as of 31 August 2026").
- `generatedAt` (in the envelope and in `data`) is when the payload was produced from the documents. `expiresAt` is when it is due for a refresh, 24 hours later: a request after that date is still answered at once from the store, flagged `stale: true`, while the refresh runs in the background.

The distinction removes a common confusion. A payload generated this morning can legitimately carry a `dataAsOf` from the end of last month, because the fund has not published anything newer. Conversely, a payload with yesterday's `dataAsOf` was built from a daily NAV file. Both are fresh in the sense that matters: they reflect what the fund has disclosed.

```bash
curl https://fundfactsapi.com/api/v1/funds/IE00B4L5Y983 \
  -H "Authorization: Bearer ffk_live_..."
```

```json
{
  "isin": "IE00B4L5Y983",
  "cached": true,
  "generatedAt": "2026-09-21T06:02:11.408Z",
  "expiresAt": "2026-09-22T06:02:11.408Z",
  "data": {
    "dataAsOf": "2026-09-18",
    "generatedAt": "2026-09-21T06:02:11.408Z",
    "keyFacts": { "aum": "USD 105.4 bn" },
    "headlineMetrics": { "ter": "0.20%" }
  }
}
```

## Why a 24-hour cycle matches how funds publish

Consider what could change between two requests an hour apart. The NAV, if the issuer publishes it daily, changes once per business day, after the close. Holdings files from issuers who publish daily are updated once a day. Factsheets change once a month. KIDs change a few times a year at most. Nothing in a factsheet payload changes intraday, so refreshing more often than daily produces identical payloads and costs the issuer's servers and yours.

A 24-hour store also gives the behaviour products need: the first request for an ISIN loads the fund's documents (a cold load takes roughly one to three minutes for a fund never loaded before, or not in the last 7 days), and every later request returns in well under a second with `cached: true`. After 24 hours the stored payload is still served at once, flagged `stale: true`, and the refresh runs in the background, usually within a minute; nothing older than 7 days is served without a new read. Concurrent requests for the same cold fund trigger one load. Funds in the pre-warmed universe are refreshed on a schedule, so the popular ETFs are always warm. The [freshness and sourcing docs](https://fundfactsapi.com/docs/freshness) describe the mechanics.

For the same reason, caching on your side until `expiresAt` is safe. The [ISIN lookup post](https://fundfactsapi.com/blog/fund-data-api-from-isin) shows a client that does this, and the pattern cuts usage to one request per fund per day regardless of how many users ask.

## When you do need something faster

Two kinds of data are genuinely intraday, and neither is factsheet data:

1. **Exchange prices of ETF shares.** Market price, bid and ask, and the premium or discount to NAV move all day and belong to a market-data feed. The [NAV vs market price post](https://fundfactsapi.com/blog/etf-nav-vs-market-price-premium-discount) explains why published performance uses NAV instead.
2. **Order and settlement data** for your own transactions, which comes from your broker or custodian.

If your product shows a factsheet with a live price next to it, keep the two visibly separate: "price 15:42" and "data as of 31 August". Mixing a live price into a NAV-based series makes the last point incomparable with the rest.

## Detecting when something actually changed

Daily refreshes produce many identical payloads. What most products want to know is when a tracked figure moved: the TER changed, the risk indicator moved a class, the manager changed, the fund size crossed a threshold, or the top-five holdings changed. Diffing payloads yourself works; the `GET /api/v1/changes` feed (Scale and Enterprise) does it server-side and returns the tracked fields that moved between refreshes, plus a `fund.refreshed` event whenever `dataAsOf` advances. Webhooks on the same plans push those events. The [compliance monitoring use case](https://fundfactsapi.com/use-cases/compliance-monitoring) is built on this.

```bash
curl "https://fundfactsapi.com/api/v1/changes?since=2026-09-01T00:00:00Z&isins=IE00B4L5Y983,IE00B3RBWM25" \
  -H "Authorization: Bearer ffk_live_..."
```

## Displaying freshness honestly

- **Show `dataAsOf` next to every block** that carries figures, and in the same format everywhere. Users rarely object to a month-old holdings date; they object to not being told.
- **Do not show `generatedAt` as "updated"** without explanation. It says when the payload was rebuilt, not when the fund published.
- **Expect block-level skew.** If you have both a NAV-derived `dataAsOf` and a factsheet-derived holdings snapshot, the holdings can be older; say so in a footnote.
- **Keep history.** Store each day's `dataAsOf` and the tracked fields, so you can answer "when did the fee change" later. The [change feed](https://fundfactsapi.com/docs/endpoints) gives you this for free on Scale.
- **Treat empty as unknown, not zero.** A blank `dataAsOf` or an empty metric string means the document does not state it.

For AI assistants the same rule applies in prose: every figure the model quotes should carry its date. The [LLM grounding post](https://fundfactsapi.com/blog/fund-data-for-ai-agents-and-llms) turns that into a system-prompt rule, and the MCP tool descriptions ask the model to do it by default.

The short version: fund data is slow-moving by construction, a daily store is faster than the documents it reads, and the as-of date is the field that makes the whole thing trustworthy. Try it on a fund you follow with a [free key](https://fundfactsapi.com/signup) and compare `dataAsOf` with the date on the issuer's factsheet.

## FAQ

### How often is ETF holdings data updated?

It depends on the issuer. Many large ETF issuers publish a full holdings file every business day; most traditional funds publish holdings monthly, sometimes with a one-month lag, and some only disclose their top ten. The `dataAsOf` field reports the date the returned figures refer to.

### Is fund data available in real time?

Factsheet data is not real-time by nature: NAV is struck once a day and holdings, fees and risk indicators change monthly or yearly. Only the exchange price of an ETF's shares moves intraday, and that is market data rather than fund data.

### What is the difference between dataAsOf and generatedAt?

`dataAsOf` is the date the fund's figures refer to (the documents' stated as-of date, otherwise the latest NAV observation). `generatedAt` is when the payload was built from the documents. A payload can be generated today with figures as of last month if the fund has published nothing newer.

### Is caching fund data for 24 hours acceptable?

Yes. Nothing in a factsheet changes intraday, so a daily refresh is at least as current as the documents. FundFacts refreshes each fund every 24 hours, returns `expiresAt` so clients can cache until then (a payload past it is served at once with `stale: true` while the refresh runs in the background), and offers a change feed for detecting when tracked fields actually moved.

## About FundFacts API

FundFacts turns any fund or ETF ISIN into one dated factsheet (fees and KID costs, the 1–7 risk indicator, holdings, sector and country exposure, returns) read from the fund house's own documents: as a client-ready PDF under your firm's name for advisers and wealth managers, as JSON through its API for developers, or inside ChatGPT and Claude through its MCP server.

FundFacts works inside ChatGPT and Claude as a connector (a remote MCP server): ask about any fund or ETF by ISIN, ticker or name and the assistant answers from FundFacts' dated figures, fees, risk, holdings, exposure and returns, with fund cards, side-by-side comparisons, holdings overlap and portfolio look-through.

- Free API key, no card: https://fundfactsapi.com/signup
- Documentation: https://fundfactsapi.com/docs (OpenAPI: https://fundfactsapi.com/openapi.json)
- MCP server: https://fundfactsapi.com/api/mcp (set-up for every client: https://fundfactsapi.com/mcp-server)
- Pricing: https://fundfactsapi.com/pricing
- Site index for AI assistants: https://fundfactsapi.com/llms.txt
- Informational data, not investment advice.
