How do I bulk-export fund data for a whole universe?
GET /api/v1/export streams every stored fund matching issuer, asset class, currency or since-date filters as NDJSON (optionally gzipped) in one request on the Scale plan. Loading a universe first, and the batch alternative on Pro.Updated 12 September 2026 · by FundFacts APIShort answer
On the Scale plan, GET https://fundfactsapi.com/api/v1/export?issuer=&assetClass=¤cy=&since=&gzip=1 streams every fund in the store that matches the filters as NDJSON, one full payload per line, for one request. The store contains funds that have been loaded, so seed your universe first with batch calls (POST /funds, 200 ISINs per call on Scale). On Pro, the same result is a loop of batch calls of 50 with the payloads written to your own database.
Export on Scale
bashcurl -s "https://fundfactsapi.com/api/v1/export?issuer=ishares&assetClass=Equities&gzip=1" -H "Authorization: Bearer $FUNDFACTS_API_KEY" \| gunzip | head -n 2 | jq '{isin, name, ter: .data.headlineMetrics.ter}'
Filters: issuer, assetClass, currency, since (payloads generated after this date). Each line is the same envelope as GET /funds/{isin}. One request per call regardless of size.
Seeding the universe
The export returns what is in the store. To cover a universe:
- Build the ISIN list (your own, or from the coverage pages and
GET /search). - Load it with
POST /fundsin batches of the plan size withwait: true; re-sendpendingentries after a minute. - Repeat daily for the ISINs whose
expiresAthas passed; on Scale, or Pro with overage, that is one request per ISIN per day.
On Pro
pythonimport os, requests, json, timeH = {"Authorization": f"Bearer {os.environ['FUNDFACTS_API_KEY']}"}isins = [l.strip() for l in open("universe.txt") if l.strip()]with open("funds.ndjson", "a") as out:for i in range(0, len(isins), 50):r = requests.post("https://fundfactsapi.com/api/v1/funds", json={"isins": isins[i:i+50], "wait": True}, headers=H, timeout=300).json()for x in r["results"]:if x["status"] == "ok":out.write(json.dumps(x) + "\n")elif x["status"] == "pending":isins.append(x["isin"]) # try again at the endtime.sleep(1)
Keeping it current
Pair the export with the change feed to update only the funds whose tracked fields moved, rather than re-exporting everything. The quant research use case covers the analysis side.
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]}'