Built and run by one person.

MF NAV API - Free Indian Mutual Fund NAV Data (AMFI)

TigZig API & MCP Hub
REST / HTTP APIData APIOpen - no auth

Open, no-auth HTTP API for Indian mutual fund NAV history from AMFI - 37M+ daily NAV records across 38,000+ schemes, all scheme types (open-ended, closed-ended, interval) including matured schemes, history back to April 2006, refreshed daily. Search a scheme by name, browse the universe by category, AMC, plan or launch date, pull the full history for one scheme, or download the ENTIRE dataset in a single call - 7 formats (parquet, plus csv / tsv / sqlite as .gz or .zip), served via Cloudflare R2. Built for AI agents first, humans second: every page here has a Copy-as-Markdown button so you can hand it straight to your agent.

37M+NAV records
38,000+schemes
2006+history
1 callfull download
No authfully open

Quick start

AI agents: this API is open (no auth). Start with the OpenAPI spec for this API: https://api.tigzig.com/mf/v1/openapi.json. The RFC 9727 catalog at api.tigzig.com/.well-known/api-catalog is a site-level directory of all TigZig APIs - go there only if you want a different API, not for more detail on this one.
REST API base URL
https://api.tigzig.com/mf/v1
Live tool no sign-up
Search schemes, compare NAV history and export, all in the browser.

Documentation

For people
api.tigzig.com/mf/v1/redoc

The full reference. Every endpoint, every field, and every enforced limit with the message you get when you cross it. Rendered from the running service, so it is never a copy that can fall behind.

For AI agents
api.tigzig.com/mf/v1/openapi.json

The machine contract for this API. The site-wide directory of every TigZig API is the RFC 9727 catalog at api.tigzig.com/.well-known/api-catalog.

What you can call

6 endpoints. Request bodies, every field and every enforced limit are in the full reference.

GET/mf/v1/API catalog: every endpoint, the data schema, and worked examples
GET/mf/v1/downloadDownload full NAV dataset
GET/mf/v1/downloads/manifestDownload file sizes and metadata
GET/mf/v1/navNAV data by AMFI code or ISIN (single or bulk)
GET/mf/v1/schemes/{code}/navNAV data for a single scheme (REST path form)
GET/mf/v1/searchSearch and browse schemes: name/code search + metadata filters (category, AMC, plan, dates)

Overview

NewJust want the whole database? Download it in one shot - no code, no API.

The complete Indian mutual fund NAV history - every scheme, every day, April 2006 onward - is rebuilt 3x daily and published as a single file in Parquet, CSV, TSV and SQLite. Perfect for a one-off analysis: grab the file and open it in Excel, pandas, or your own database.

No coding needed - download it by hand from the MFPRO app (opens straight to Download Full Database): pick a format, click, done. Prefer to automate it? One API call pulls the entire dataset - see Download the whole database in one call below.

Only need the current picture, not the history? One row per scheme with the master data, latest NAV and average AUM together - 22 columns, about 9.7 MB of plain CSV, in roughly a second: GET /mf/v1/download?format=latest. No unzipping, opens anywhere.

A free, open AMFI mutual fund NAV API for India - no key, no sign-up. AMFI publishes NAVs as a giant daily text dump; this API turns it into clean, queryable data and lets you download the entire NAV history - every scheme, every day - in a single call.

  • 37M+ daily NAV records, refreshed daily from AMFI.
  • 38,000+ schemes across all scheme types, including matured (open-ended, closed-ended, interval).
  • History back to April 2006, including matured closed-ended and interval schemes.
  • AMFI code OR ISIN - use whichever your integration speaks. Auto-detected, no separate endpoint needed.
  • Search or browse - find a fund by name, or list every scheme in a category, AMC, plan or launch window without knowing a single code.
  • Single, bulk, whole-universe snapshot, or full-dataset - one scheme, up to 50 in a single call, every scheme's master data + latest NAV + average AUM in one 20-column CSV, or the entire 37M-row history in one file.
  • No authentication. No key, no sign-up. 300 requests/min per IP.

The same MF NAV data powers the MFPRO analytics app.

Using the API

1. Find a scheme - search by name, or browse by category

Know the fund name? Search it:

GET https://api.tigzig.com/mf/v1/search?q=hdfc flexi cap

Returns matching scheme codes and names (e.g. 118955 = HDFC Flexi Cap Fund - Growth - Direct Plan).

Do not have a name to search for? Browse instead. The same endpoint filters on scheme metadata, so q is optional - pass filters on their own and you get the matching list back:

GET https://api.tigzig.com/mf/v1/search?category=small cap&plan=direct&option=growth
GET https://api.tigzig.com/mf/v1/search?amc=icici,aditya birla&group=equity&exclude=index
GET https://api.tigzig.com/mf/v1/search?group=equity&first_date_from=2015-01-01&first_date_to=2016-12-31

You can filter on AMC, category group, SEBI sub-category, scheme type, plan, option, ISIN, TXIC code, active-or-matured, and launch / last-NAV date windows. The full list with descriptions is in the API Endpoints reference below. What each of those values means - and the caveats that change how you read it - is in the data dictionary (Markdown twin: https://www.tigzig.com/md/mfpro/data-dictionary.md).

The rules are the same for every text filter: contains-matched and case-insensitive (category=small finds Small Cap Fund), a comma means OR within one filter, different filters AND together, and exclude= is the NOT. Repeating a filter does the same thing as a comma - ?amc=icici&amc=hdfc is identical to ?amc=icici,hdfc, the same merge rule schemes= uses on the NAV endpoints - so a form or client that emits repeated params gets the union rather than losing all but the last one. One scope rule worth knowing before you trust a result: exclude= reads the scheme name and the AMC name only, never the category - so exclude=value drops an index fund with "Value" in its name and does not drop the Value Fund category. To remove a category, select the ones you want with category= instead. A browse with no q returns live schemes by default - add active=all to include matured ones. Page through with limit (max 100) and offset; the response carries total_matches.

Parameter names are strict on this endpoint. An unknown parameter is a 400, not a silent ignore - so a typo like ?catgeory=small can never quietly hand you the wrong universe of funds. The same instinct runs through the rest of the validation: an impossible date window, a non-numeric limit, a blank q, or a scalar parameter repeated with two different values all fail loudly and name the problem, instead of returning an empty or arbitrary result you would have to reverse-engineer.

Guessed a filter value wrong? A zero-match browse tells you the valid values for the filters you used - the category groups, the SEBI sub-categories, plans, options, AMC names - so you can fix the call from the response itself. And the shapes stay predictable: a plain q search returns exactly the compact result it always did, while adding any filter returns a richer row carrying the full scheme metadata (AMC, group, category, plan, option, first and last NAV dates, TXIC code).

2. NAV history by AMFI code or ISIN (one or more)

Pass one identifier or several - AMFI scheme code or ISIN, mixed freely - and get the ENTIRE history back, no pagination. scheme= takes a single id or a comma-separated list; isin= / isins= work as synonyms. Both identifier styles are auto-detected (numeric = AMFI code, 12-char starting with IN = ISIN). Add &since=YYYY-MM-DD / &to=YYYY-MM-DD to bound the window:

GET https://api.tigzig.com/mf/v1/nav?scheme=118955&since=2020-01-01
GET https://api.tigzig.com/mf/v1/nav?scheme=INF174K01LT0
GET https://api.tigzig.com/mf/v1/nav?scheme=118955&since=2024-01-01&to=2024-12-31

Same call in REST path form:

GET https://api.tigzig.com/mf/v1/schemes/118955/nav
GET https://api.tigzig.com/mf/v1/schemes/INF174K01LT0/nav

Only need the most recent NAV, not the whole history? Add latest=true to get exactly one row per scheme - the latest published NAV. It works on single, bulk and path forms (and is case-insensitive); add &to=YYYY-MM-DD for the latest NAV as of a date, e.g. a quarter-end:

GET https://api.tigzig.com/mf/v1/nav?scheme=100033&latest=true
GET https://api.tigzig.com/mf/v1/nav?scheme=100033&latest=true&to=2026-06-30

An empty window (no rows in your date range, or the day's NAV not published yet) returns count: 0 with that scheme's first_available_date and latest_available_date, plus a Last-Modified header - so a poller learns the real data range without a second call, and can send If-Modified-Since for a cheap 304.

3. Bulk - up to 50 schemes in ONE call

For portfolios and multi-fund analytics, batch up to 50 identifiers (AMFI codes and ISINs can be mixed):

GET https://api.tigzig.com/mf/v1/nav?schemes=118955,120468,INF174K01LT0

Response shape wraps the per-scheme results under schemes with a top-level not_found list for any identifier that did not resolve. An unknown or malformed entry never fails the batch - the valid schemes still come back.

Single and bulk are the same endpoint, recently unified so you never have to pick which form to use. One identifier returns that scheme's rows directly; several (or schemes=) returns the wrapped shape above. Existing single-identifier and bulk calls are unchanged and keep working exactly as before.

4. The whole scheme universe in one file - one call, ~1 second

If you do not need history, this one file replaces the lot: one row per scheme, 38,000+ rows, 22 columns, about 9.7 MB as plain CSV (1.1 MB compressed). It carries the scheme master, the latest NAV, and each scheme's average AUM together:

GET https://api.tigzig.com/mf/v1/download?format=latest

Raw text/csv - it opens in a browser or Excel, and pd.read_csv works straight off the URL with no unzipping. Also latest.csv.gz, latest.csv.zip and latest.parquet (latest.csv is the same file as bare latest). The 22 columns cover identity (scheme code, both ISINs, name, AMC, TXIC code), classification (type, category, sub-category, group, plan, option), lifecycle (first and last NAV dates, active and stale flags), size (average AUM with its quarter label and ISO quarter-end) and the NAV itself (date and value). The exact column names and their per-column caveats are machine-readable in the API catalog under schema.latest_snapshot - read them there rather than from this page, so a column rename can never leave you working from a stale list.

Two grouping columns, and they answer different questions. category_group_clean is the analysis lens - a small, stable set (Equity / Debt / Hybrid / Other) that every raw name maps into deterministically, so a group-by is comparable across the whole history. category_group is the raw AMFI header as filed, which currently carries 20+ coexisting values because fund houses are still re-filing under SEBI's 2026 recategorisation. Use the clean one for reporting, the raw one when you want the mid-level detail or need to see exactly what AMFI filed. Note the clean set folded Solution Oriented and Fund of Funds into Other Scheme under the 2026 rules, so it is four values now rather than the six you may have seen earlier.

Two ISIN columns. isin is the payout or growth ISIN; isin2 is the reinvestment ISIN where one exists. They are sub-options of the same IDCW plan, not different funds - same scheme, same NAV row. Reinvestment ISINs resolve for all active schemes and most matured ones (about 6,400 mappings), so an ISIN lookup succeeds whichever of the two a client happens to hold.

import pandas as pd
df = pd.read_csv("https://api.tigzig.com/mf/v1/download?format=latest")
live = df[df.is_active]                        # the ~8,600 schemes still publishing
big  = live.nlargest(20, "aaum_cr_quarterly_avg")            # largest by average AUM

Three things to know before you trust a number from this file. Each one produces a wrong answer silently rather than an error.

1. It is each scheme's most recent NAV, not today's NAV for every row. Every scheme is included, matured ones too, so a fund that wound up in 2008 sits there with its final 2008 NAV. About 8,600 rows are live; the other ~29,000 are closed schemes frozen at their last NAV, and roughly 2,300 of those carry a final NAV of exactly 0.00 - AMFI's own closing entry, kept as filed. Read a 0.00 on an inactive row as end of life rather than a price, and exclude those rows before you average anything. Filter is_active, read nav_date. Deliberate - it keeps the file survivorship-bias-free, like the full dataset.

2. One scheme code is one plan-and-option variant, not a fund. To size a fund you sum its family. Aditya Birla Sun Life Value Fund is four codes - 5,628 + 705 + 68 + 11 = about 6,412 Cr. Quote any single row and you understate the fund, in that case by nine tenths. Note also that the oldest code in a family often carries plan Other, because it predates the 2013 Direct/Regular split.

3. Sort quarters on aaum_quarter_end, never on aaum_quarter. The label is text, so alphabetically December-2025 < June-2026 < March-2026, which is not chronological. aaum_quarter_end is the ISO twin (2025-12-31, 2026-03-31, 2026-06-30) and sorts correctly.

On AUM specifically: aaum_cr_quarterly_avg is the average of daily net assets over the quarter, per SEBI's definition - not a month-end or quarter-end balance - so a scheme launched mid-quarter reads low against a full-quarter peer. It is populated for about 8,400 rows (live schemes with a disclosed quarter); matured schemes have it blank. Renamed from aaum_cr on 2026-08-12 (manifest schema_version 2) because the old name read like a point-in-time AUM. Same values, same units, same position - if your code does df['aaum_cr'] it will raise a KeyError, so rename the reference and nothing else changes. The per-column definitions, including this one, are machine-readable in the API catalog under schema.latest_snapshot.column_notes - that is the canonical home, so an agent gets the caveats without reading this page.

5. Download the WHOLE database in one call

Instead of looping over 38,000 schemes, grab everything at once - a single pre-generated file for all 37M+ rows, served via Cloudflare R2 (free egress, edge-cached):

GET https://api.tigzig.com/mf/v1/download?format=parquet

Seven format values (default parquet): parquet (~170 MB), csv.gz / csv.zip / tsv.gz / tsv.zip (~235 MB), sqlite.gz / sqlite.zip (~1.3 GB). Bare sqlite is an alias for sqlite.gz. Load straight into pandas:

import pandas as pd
df = pd.read_parquet("https://api.tigzig.com/mf/v1/download?format=parquet")
print(df.shape)   # every scheme, every day
df["nav"] = df["nav"].astype(float)   # parquet stores nav as DECIMAL - see note below

One parquet quirk worth knowing before it bites. In the parquet downloads (both the full history and the snapshot) nav is a DECIMAL logical type, so pandas hands you Python Decimal objects rather than floats. Aggregations like .mean() still work, which is what makes this easy to miss - but arithmetic against a float, df.nav * 1.05, raises TypeError: unsupported operand type(s). Cast once on load, as above. The CSV and TSV downloads give you plain floats and need no cast, and note it is nav specifically - aaum_cr_quarterly_avg already comes through as a float. The decimal type is deliberate: it preserves AMFI's filed precision exactly rather than rounding it into a float.

Authoritative per-file list (formats, exact sizes, row count, last-refresh time): GET /mf/v1/downloads/manifest. It also reports a validation block confirming the generated files match the source row count. The manifest supports If-None-Match for cheap daily re-polls (returns 304 Not Modified when unchanged) - poll the manifest, and only re-download a file when the manifest says it changed. The download files themselves now honour conditional requests too: every 200 carries Content-Length, ETag and Last-Modified, and sending If-None-Match or If-Modified-Since returns 304 Not Modified with no body. So the cheap daily loop is: fetch once, keep the ETag, re-poll conditionally, and only receive bytes on the days the file actually changed.

Errors

Every 4xx response is a JSON envelope you can act on programmatically:

{ "error": "not_found", "status": 404, "path": "/mf/v1/...", "message": "...",
  "help": { "catalog": "https://api.tigzig.com/mf/v1/", "docs": "https://www.tigzig.com/apis/mf-nav" } }

The error field is a snake_case slug (bad_request, not_found, method_not_allowed, unprocessable_entity, ...). The help block always points at this API's machine catalog + docs page, so a client that hits an error can self-recover. Validation 400/422 keep their richer error.{code, field, docs_url} body - the help block is added alongside. 5xx and 429 have their own shapes (429 carries retry_after_seconds).

A 404 for an unknown scheme also carries an error.hint pointing you straight to /mf/v1/search to resolve a fund name to its code - so an agent can self-correct from the first failed response instead of guessing identifiers. Likewise, calling /nav with a category= or amc= filter (a natural guess) returns a 400 that points you to the browse filters on /search, and tells you to call /nav with the codes you picked.

If the identifier is a corrupted ISIN - it fails the ISIN check-digit test (the 12th character is arithmetic over the first eleven) - the 404 says exactly that and tells you retrying will not help, so you fix it at the source rather than loop. A well-formed ISIN that simply is not in AMFI's data still gets the search-by-name hint. You do not need to run your own validator; the API does the arithmetic and tells you which case you are in.

Compatibility aliases

The canonical names above are all you need - scheme, schemes, since, to, q, and the paths in steps 1-4. For convenience the API also accepts a few aliases (handy if you are porting from another naming convention; you never have to use them, and they are intentionally kept out of the OpenAPI spec and the machine catalog):

  • Param synonyms on the NAV endpoints: scheme_code for scheme; from, start, start_date for since; end, end_date, until for to.
  • On /search: name and query for q (e.g. /mf/v1/search?name=axis focused).
  • Paths that route to GET /mf/v1/nav: /mf/v1/nav-history, /mf/v1/history, /mf/v1/nav/history, /mf/v1/series.
  • Paths that route to the canonical /mf/v1/schemes/{code}/nav: /mf/v1/nav/{code}, /mf/v1/schemes/{code}, /mf/v1/scheme/{code}, /mf/v1/history/{code}, /mf/v1/schemes/{code}/history, /mf/v1/series/{code} (the singular /mf/v1/scheme/{code}/nav works too).

Guides

This page is the reference - what the endpoints are and how to call them. The guides below are the long-form versions, with worked examples and the edges you only meet in real use:

Each is a plain page with a Markdown twin, so you can hand a URL straight to an agent. Come back to this page when you want parameter-level detail. There is also a shorter update post on the forgiving identifier intake, latest=true and the freshness metadata - all three are documented above.

What you can build

  • A returns calculator (1Y / 3Y / 5Y / SIP / rolling returns) over the full history.
  • Backtests, fund-of-funds, and rebalancing strategies.
  • Your own dashboards and notebooks, without scraping AMFI.
  • Research-grade history, no subscription paywall.

Why one-call download matters: every other route makes you paginate - one scheme, one request, rate-limited, often capped at recent history. For any real analysis you need all of it, locally. One call, one file, done.

Documentation

Full documentation for the data behind this API - every field, every metric, and how the data is assembled - lives in one place in the MFPRO app:

MFPRO Documentation →

What you will find there:

  • Data Dictionary - every field in the NAV database with types, meanings and known caveats, table by table.
  • Scheme Universe field guide - the 38,000+ scheme universe: how AMFI categories work, which fields to use and avoid, the old-to-modern category mapping, and the TXIC scheme identifier.
  • How the Data Is Built - sources, the 3x daily sync, the July 2026 historical backfill, validation discipline and honest limitations.
  • Performance & Risk methodology - all 21 metrics with formulas and worked examples.
  • Composition methodology - the portfolio holdings pipeline: AMC disclosures, ISIN mapping, validation checks and the monthly refresh.

One caveat we flag plainly: an AMC merger can split a fund's history across two scheme codes, so an older code may return a short or empty series while the fund continues under a newer code. The How the Data Is Built doc above walks through this with a worked example.

Reading this as an agent? Three of those docs are mirrored on this site as plain pages, each with a Markdown twin, so you can read them without running JavaScript:

  • Data dictionary - every column in the NAV and scheme-metadata tables, with types, meanings and the caveats that change how you read a number. Markdown: https://www.tigzig.com/md/mfpro/data-dictionary.md
  • Scheme universe field guide - what the category, plan and option values mean, the old-to-modern category mapping, and the TXIC identifier. Markdown: https://www.tigzig.com/md/mfpro/scheme-universe.md
  • How the data is built - sources, sync cadence, the July 2026 historical backfill, and the honest limitations. Markdown: https://www.tigzig.com/md/mfpro/how-the-data-is-built.md

Read the data dictionary before drawing conclusions from a filtered browse. It is where the non-obvious rules live - why active means "published a NAV in the last 45 days", why some older schemes carry a blank sub-category on purpose, and why a pre-2010 closed-ended series has roughly weekly gaps rather than missing days.

Rate limits

Published so a well-behaved client can plan around them. These are per-IP limits:

  • Per IP: 300 requests / minute.
  • Downloads, range reads (HTTP 206): 3,000 / minute and 25,000 / day.
  • Downloads, whole-file (200 / 304 / HEAD): 60 / minute and 500 / day.

You get a 429 with Retry-After. The body is product-aware: it names MF's own bulk paths and carries help: { catalog, docs }.

Avoiding 429s: The bulk form /nav?schemes=A,B,... takes up to 50 schemes in one call - far cheaper than one call per scheme. For the whole dataset use /download.

Every successful response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix epoch seconds), read straight from the running limiter, and Retry-After is set on 429. The current numbers are also published as machine-readable JSON at https://api.tigzig.com/mf/v1/, derived from live config. Read those at runtime rather than hard-coding the figures above - limits change, and these channels change with them.

On the download endpoints the headers differ, because a different layer enforces them: you get X-RateLimit-Limit, -Remaining and -Window plus a matching -Day trio (-Limit-Day, -Remaining-Day, -Window-Day) and NO -Reset. The origin endpoints are the other way round: -Reset, no -Day.

Other 4xx responses are a JSON envelope: { error, status, path, message, help: { catalog, docs } } where error is a snake_case slug (not_found, bad_request, unprocessable_entity, ...) and help points at the machine catalog (https://api.tigzig.com/mf/v1/) plus this docs page, so a client that hits an error can self-recover.

Try it

No key, no signup.

Find a fund and its AMFI code by name
Paste into a browser address bar.
https://api.tigzig.com/mf/v1/search?q=parag%20parikh
Response first lines of 7 KB
{
 "query": "parag parikh",
 "count": 28,
 "results": [
  {
   "scheme_code": 122639,
   "scheme_name": "Parag Parikh Flexi Cap Fund - Direct Plan - Growth",
   "isin": "INF879O01027",
   "isin2": null,
   "category_sub": "Flexi Cap Fund",
   "is_active": true,
   "relevance": 16
  },
  {
   "scheme_code": 152109,
   "scheme_name": "Parag Parikh Arbitrage Fund - Direct Plan Growth",
   "isin": "INF879O01225",
   "isin2": null,
   "category_sub": "Arbitrage Fund",
   "is_active": true,
   "relevance": 11
  },
  {
   "scheme_code": 152110,
   "scheme_name": "Parag Parikh Arbitrage Fund - Regular Plan Growth",
   "isin": "INF879O01217",
   "isin2": null,
   "category_sub": "Arbitrage Fund",
   "is_active": true,
   "relevance": 11
  },
  {
   "scheme_code": 148958,
   "scheme_name": "Parag Parikh Conservative Hybrid Fund - Direct Plan - Growth",
   "isin": "INF879O01175",
   "isin2": null,
...
Daily NAV history for one fund, by its AMFI code
Paste into a browser address bar.
https://api.tigzig.com/mf/v1/nav?scheme=119775
Response first lines of 20 KB
{"scheme_code":119775,"scheme_name":"Kotak Midcap Fund - Direct Plan - Growth","isin":"INF174K01LT0","isin2":null,"first_available_date":"2013-01-03","latest_available_date":"2026-08-11","count":3348,"data":[{"date":"2013-01-03","nav":14.052},{"date":"2013-01-04","nav":14.177},{"date":"2013-01-07","nav":14.199},{"date":"2013-01-08","nav":14.223},{"date":"2013-01-09","nav":14.209},{"date":"2013-01-10","nav":14.122},{"date":"2013-01-11","nav":13.978},{"date":"2013-01-14","nav":14.07},{"date":"2013-01-15","nav":14.086},{"date":"2013-01-16","nav":13.972},{"date":"2013-01-17","nav":13.952},{"date":"2013-01-18","nav":13.892},{"date":"2013-01-21","nav":13.86},{"date":"2013-01-22","nav":13.805},{"date":"2013-01-23","nav":13.715},{"date":"2013-01-24","nav":13.524},{"date":"2013-01-25","nav":13.697},{"date":"2013-01-28","nav":13.633},{"date":"2013-01-29","nav":13.58},{"date":"2013-01-30","nav":13.
...