{"bulk_downloads":{"catalog":"https://api.tigzig.com/downloads/mf","all_products":"https://api.tigzig.com/downloads","file_names":"Every file also has an address that ends in its own file name, for example https://api.tigzig.com/mf/v1/download/amfi_nav_master.parquet. The ?format= form keeps working.","query_in_place":"Parquet files support HTTP range requests, so DuckDB, pyarrow, polars or a browser can query them in place and read only the parts a query needs. Browsers can do the same: responses expose Content-Range, Content-Length and ETag to cross-origin JavaScript.","example_sql":"SELECT count(*) FROM read_parquet('https://api.tigzig.com/mf/v1/download/amfi_nav_master.parquet');"},"app":"MF NAV -Open Mutual Fund Data","description":"Every NAV in AMFI's public records: 38,000+ Indian mutual fund schemes, all scheme types (open-ended, closed-ended, interval), April 2006 -present, including matured schemes. Source: AMFI India (Association of Mutual Funds in India).","base_url":"/mf/v1","openapi":"https://api.tigzig.com/mf/v1/openapi.json","docs":"https://api.tigzig.com/mf/v1/docs","data_dictionary":"https://www.tigzig.com/md/mfpro/data-dictionary.md","field_guide":"https://www.tigzig.com/md/mfpro/scheme-universe.md","methodology":"https://www.tigzig.com/md/mfpro/how-the-data-is-built.md","tigzig":"Part of Tigzig: free interactive tools, open-source repos, APIs and MCP servers for analytics and live data across global and Indian markets, macro indicators and filings. Catalog: https://api.tigzig.com/.well-known/api-catalog | Guide: https://www.tigzig.com/llms.txt","stats":{"total_rows":37559880,"total_schemes":38273,"date_range":{"from":"2006-04-01","to":"2026-10-12"}},"mcp":{"url":"https://api.tigzig.com/mf/mcp","transport":"streamable-http","auth":"none","tools":["mf_search","mf_nav","mf_details"],"notes":"Results over about 25,000 tokens are not sent: the tool returns the REST URL for the same data instead. mf_details defaults to view=compact over MCP. Bulk files are REST only (see download / download_dataset below).","docs":"https://www.tigzig.com/apis/mf-nav"},"endpoints":{"catalog":{"path":"/mf/v1/","method":"GET","description":"This catalog -endpoints, schema, stats"},"nav":{"path":"/mf/v1/nav","method":"GET","description":"NAV data by AMFI code or ISIN. Single-scheme via ?scheme=, bulk via ?schemes= (up to 50). Returns full NAV history unless bounded by since/to. Forgiving inputs: isin/isins accepted as synonyms, param names case-insensitive, a comma list in the singular param routes to bulk, repeated params merge, and in bulk invalid entries never fail the batch (reported in not_found) unless no entry is usable: all malformed returns 400 INVALID_IDENTIFIER, all well-formed but unknown returns 404 NOT_FOUND. AMFI assigns scheme codes non-contiguously, so a missing integer is not a missing fund: use /search or the format=latest snapshot for the full list of codes.","params":{"scheme":"AMFI code (numeric, 4-7 digits) or ISIN (12 chars, e.g. INF174K01LT0). Use for single-scheme lookup. `isin=` works as a synonym. All of a scheme's ISINs resolve: payout/growth (ISIN1), IDCW reinvestment (ISIN2), and prior ISINs of renamed schemes - each returns the same full NAV series.","schemes":"Comma-separated list of AMFI codes and/or ISINs, mixed OK. Max 50 per request. Use for bulk. `isins=` works as a synonym; repeated params merge.","latest":"Optional. latest=true returns only the most recent NAV row per scheme (newest within your since/to window, if given). Ideal for 'current NAV' displays - avoids pulling full history for one number.","since":"Optional. NAV from this date onward (YYYY-MM-DD, inclusive).","to":"Optional. NAV up to this date (YYYY-MM-DD, inclusive). Blank = up to latest."},"examples":{"single_amfi":"/mf/v1/nav?scheme=119775","single_isin":"/mf/v1/nav?scheme=INF174K01LT0","single_windowed":"/mf/v1/nav?scheme=119775&since=2024-01-01&to=2024-12-31","bulk_mixed_ids":"/mf/v1/nav?schemes=119775,120468,INF174K01LT0","rest_path_form":"/mf/v1/schemes/119775/nav"},"response_headers":["Last-Modified: the latest NAV date in the response (RFC 7231 HTTP-date).","X-RateLimit-Limit / -Remaining / -Reset: current per-IP budget snapshot."]},"nav_rest":{"path":"/mf/v1/schemes/{code}/nav","method":"GET","description":"REST-canonical single-scheme lookup. {code} accepts AMFI code or ISIN.","example":"/mf/v1/schemes/119775/nav","example_isin":"/mf/v1/schemes/INF174K01LT0/nav"},"search":{"path":"/mf/v1/search","method":"GET","description":"Search AND browse schemes. Text search by name/code, plus metadata filters that work with or without q (pure browse). All text filters are contains-matched and case-insensitive; comma = OR within a filter; different filters AND together; exclude= is the NOT. In-memory, instant (~2ms).","params":{"q":"Scheme-name fragment or numeric scheme code. Min 2 chars. Optional when any filter is present. q does not match ISINs: to look a scheme up by ISIN use isin= here, or /nav?scheme=<ISIN>. Names follow AMFI's latest filing, so a renamed fund is found by its current name only (HDFC Top 100 is now HDFC Large Cap Fund): if an old name returns nothing, browse with amc= and category= (amc=hdfc&category=large cap).","amc":"AMC name contains (comma = OR). e.g. amc=icici,aditya birla","group":"Category group contains. 4 values: Equity Scheme, Debt Scheme, Hybrid Scheme, Other Scheme (SEBI 2026 folded Solution Oriented + Fund of Funds into Other Scheme).","category":"SEBI sub-category contains (category=small matches Small Cap Fund). Also matches raw AMFI category text, so old-style pre-2018 schemes (Income, Growth, ELSS) are findable.","type":"Scheme type contains: open / close / interval.","plan":"Direct / Regular / Other.","option":"Growth / IDCW / Bonus / Other.","txic":"TXIC scheme code contains.","isin":"Exact ISIN (comma = OR). Matches payout/growth (isin) AND reinvestment (isin2) identifiers.","active":"true (default for pure-browse) / false / all. NOTE: the live-only default applies to filter-only calls (no q=), which includes ISIN lookups - pass active=all when looking up a scheme that may have matured.","stale":"true/false - data-orphan schemes with only 1-2 NAV rows.","first_date_from":"Launched on/after YYYY-MM-DD.","first_date_to":"Launched on/before YYYY-MM-DD.","last_date_from":"Last NAV on/after YYYY-MM-DD.","last_date_to":"Last NAV on/before YYYY-MM-DD.","exclude":"NOT filter: drop results whose name or AMC contains any of these comma-separated terms.","limit":"Max results per page (default 30, max 100).","offset":"Pagination offset; filter-mode responses include total_matches."},"example":"/mf/v1/search?q=parag parikh","example_browse":"/mf/v1/search?category=small cap&plan=direct&option=growth","example_launch_window":"/mf/v1/search?group=equity&first_date_from=2015-01-01&first_date_to=2020-12-31","note":"q-only calls return the compact legacy shape (scheme_code, scheme_name, isin, isin2, category_sub, is_active, relevance). Any filter present returns enriched rows (all scheme_meta fields) + total_matches + matched_categories. ALWAYS READ isin2 AS WELL AS isin: IDCW-reinvestment unit classes carry their identifier in isin2 and leave isin empty, so ~1,000 schemes look identifier-less if you read isin alone. Zero-match filter calls return the valid vocabulary lists so you can self-correct. STRICT PARAMETERS: an unknown parameter name fails with 400 UNRECOGNIZED_PARAMETER (with did-you-mean + valid list) - a typo can never silently return unfiltered results. Repeated list-filter params MERGE as OR (amc=a&amc=b = amc=a,b); repeated scalars with differing values fail REPEATED_PARAMETER. Hard limits by design: no parentheses/nesting, no per-field NOT (exclude is global, name+AMC text only), no sort parameter - for anything past the filter language, pull /mf/v1/download?format=latest (the full scheme master incl. latest quarterly AAUM) and query locally."},"download":{"path":"/mf/v1/download","method":"GET","description":"Download full NAV dataset as a pre-generated static file","params":{"format":"File format. Full history: csv.gz, csv.zip, tsv.gz, tsv.zip, parquet, sqlite.gz (alias: sqlite), sqlite.zip (filename spellings db.gz / db.zip accepted). Latest-NAV snapshot (one row per scheme, ~38K rows, small): latest (plain CSV), latest.csv.gz, latest.csv.zip, latest.parquet - the FULL SCHEME MASTER: every scheme_meta field + latest quarterly AAUM (aaum_cr_quarterly_avg, aaum_quarter + its ISO twin aaum_quarter_end) + latest NAV. Includes matured schemes' final frozen NAVs (survivorship-bias free); filter is_active for live schemes. Matches the manifest 'format' labels."},"example":"/mf/v1/download?format=parquet","reliability":"These are large binary files (175 MB - 1.4 GB). Every 200 carries Content-Length + ETag + Last-Modified (since 2026-08-01), so verify received bytes against Content-Length (or size_bytes in /downloads/manifest) and integrity-test the archive (gzip -t / unzip -t; parquet starts with PAR1). The download path honours If-None-Match / If-Modified-Since with 304 Not Modified - poll conditionally instead of re-downloading. One caveat before concluding corruption: right after a regeneration, an edge-cached copy can briefly be one generation BEHIND the manifest - a size mismatch on a file that passes its integrity test is staleness, not truncation (the two differ by one day of NAVs). If the archive fails its integrity test or the connection dropped mid-transfer, retry once - the file is usually edge-cached by then and the retry is fast."},"downloads_manifest":{"path":"/mf/v1/downloads/manifest","method":"GET","description":"Download manifest: per-format sizes, row counts, generated_at. Supports ETag/If-None-Match for cheap re-polling (returns 304 Not Modified when unchanged). The `datasets` key covers scheme_details_latest and data_quality (row counts, sizes, source dates).","example":"/mf/v1/downloads/manifest"},"download_dataset":{"path":"/mf/v1/download/{dataset}","method":"GET","description":"Whole datasets other than NAV. scheme_details_latest: one row per AMFI scheme code, 60 columns - identifiers, AMFI's daily fund AUM (all plans) with riskometers and benchmarks (amfi_daily_*), the scheme summary document: managers, dates, benchmarks, terms (ssd_*), and the latest TER / BER for Regular and Direct (ter_*). Every prefixed column is FUND level and repeats on each plan's row: to total AUM, sum only rows where fund_dedup_flag is true. data_quality: rows that could not be linked cleanly, with the reason. Refresh: scheme_details_latest is rebuilt 4 times a day; the NAV files are regenerated 3 times a day. Coverage: about 11,200 scheme codes, the active schemes plus recently closed ones; the other ~27,000 matured schemes have NAV history only. A newly launched scheme appears once AMFI's daily data or its scheme document carries it, usually within days. Merging with the format=latest snapshot: join on scheme_code; both files carry scheme_name, amc, isin, isin2, category and plan columns, so keep one set. ssd_fund_managers is one text field in the file ('Name (since date); Name'); /schemes/{code}/details returns the same managers as a list of {name, role, since}.","params":{"format":"scheme_details_latest: parquet (default) or csv.gz. data_quality: csv (default) or json."},"query_form":"/mf/v1/download?dataset=scheme_details_latest&format=parquet is the same file.","example":"/mf/v1/download/scheme_details_latest?format=parquet","example_dq":"/mf/v1/download/data_quality?format=csv"},"scheme_details":{"path":"/mf/v1/schemes/{code}/details","method":"GET","description":"One scheme's details as JSON, WRAPPED in `data` (unlike /nav, whose fields sit at the top level): {data: {identifiers..., amfi_daily, ssd, ter}, license...}. Same values as scheme_details_latest. Inside data: identifiers at the top, then amfi_daily, ssd (fund_managers as a list of {name, role, since}) and ter. A group is null when we hold nothing for it. {code} accepts AMFI code or ISIN. 404 NO_DETAILS = the scheme exists but we hold no details for it.","example":"/mf/v1/schemes/118989/details"},"details_bulk":{"path":"/mf/v1/details","method":"GET","description":"Details for up to 50 schemes in one call: {count, data[], not_found[], no_details[]} (the /nav bulk reply names its list `schemes`; here it is `data`). data is a LIST of the same objects /schemes/{code}/details returns; not_found = identifiers that are not schemes; no_details = schemes we hold nothing for. Any group (amfi_daily, ssd, ter) can be null - about a quarter of schemes have ter: null - so check before indexing into it.","params":{"schemes":"Comma-separated AMFI codes and/or ISINs, max 50.","scheme":"One AMFI code or ISIN (same response shape).","view":"Optional. full (default) or compact: identifiers, fund AUM and date, riskometer, benchmark, managers, allotment date, TER and BER (about 900 bytes per scheme against about 5,300 full).","fields":"Optional. Exact fields, e.g. isin,ter.direct. A group name (amfi_daily, ssd, ter) gives the whole group. scheme_code is always included. Unknown names return 400 UNKNOWN_FIELD with the valid list."},"example":"/mf/v1/details?schemes=118989,120503,INF179K01XQ0","example_compact":"/mf/v1/details?schemes=118989,120503&view=compact"}},"schema":{"nav_master":{"columns":["scheme_code","date","nav","scheme_name","isin"],"description":"Daily NAV for all AMFI-registered mutual fund schemes. scheme_code (AMFI numeric) is the unique key for a scheme+plan+option combo. An isin (ISO 6166) normally points to one scheme_code, but ~800 ISINs are shared by an old matured code and a newer one; /nav resolves such an ISIN to the active scheme."},"scheme_meta":{"columns":["scheme_code","scheme_name","isin","isin2","amc","scheme_type","category","category_sub","category_group_clean","scheme_plan","scheme_option","first_date","last_date","is_active","is_stale","txic_code"],"description":"Scheme master, one row per scheme_code. This is the table every /search filter reads. Full field semantics + caveats: see data_dictionary above.","search_filter_columns":{"amc":"amc","group":"category_group_clean (the cleaned 4-value grouping, NOT the raw category_group)","category":"category_sub, also matching the raw category text (old-style schemes - mostly pre-2018, plus later FMP series under the old headers - have a blank category_sub by design)","type":"scheme_type","plan":"scheme_plan","option":"scheme_option","txic":"txic_code","isin":"isin OR isin2 (Div Reinvestment)","active":"is_active (true = NAV published within the last 45 days, recomputed every sync)","stale":"is_stale (true = data-orphan schemes with only 1-2 NAV rows in AMFI's records)","first_date_from / first_date_to":"first_date","last_date_from / last_date_to":"last_date"}},"latest_snapshot":{"file":"/mf/v1/download?format=latest (also .csv.gz / .csv.zip / .parquet)","description":"The full scheme master + each scheme's latest NAV + latest quarterly AAUM. One row per scheme, ALL ~38,000 (matured schemes carry their final frozen NAV - survivorship-bias free; filter is_active for live only). Rebuilt every sync (3x daily), atomic swap - never half-written.","columns":["scheme_code","isin","isin2","scheme_name","amc","scheme_type","category","category_sub","category_group_clean","category_group","scheme_plan","scheme_option","first_date","last_date","is_active","is_stale","txic_code","aaum_cr_quarterly_avg","aaum_quarter","aaum_quarter_end","nav_date","nav"],"column_notes":{"isin2":"Div Reinvestment ISIN - present only where the IDCW plan has a distinct reinvestment unit class (~7,000 schemes incl. matured). Same scheme_code, same NAV series as `isin`; both resolve on /nav.","category_group":"Raw AMFI group header AS FILED - 20+ values, old and new coexisting through the SEBI Feb-2026 re-filing wave ('Income', 'Income/Debt Oriented Schemes', 'Equity Schemes', 'Fund of Funds Scheme (Domestic)', ...). Useful as a MID-LEVEL grouping between the 4-value category_group_clean and category_sub. For clean 4-way analysis use category_group_clean.","aaum_cr_quarterly_avg":"AMFI's quarterly Average AUM in Crores - the SEBI-standardized average of DAILY net assets over the quarter's calendar days (NOT month-end AUM; will differ from factsheet 'current AUM'). Granularity is the SCHEME code = one plan+option variant: a fund's total AUM = the SUM across its family's codes. NULL where AMFI publishes none (~94% of active schemes covered; matured mostly NULL). A scheme launched mid-quarter is averaged over ALL calendar days, so its first AAUM understates its size.","aaum_quarter":"AMFI's quarter label as filed (e.g. 'June-2026'). Latest AVAILABLE quarter PER SCHEME - AMFI publishes each new quarter AMC-by-AMC over weeks, so quarters legitimately differ across rows. WARNING: sorts alphabetically (March > June) - sort on aaum_quarter_end instead.","aaum_quarter_end":"ISO date twin of aaum_quarter (June-2026 -> 2026-06-30). Sort and filter on this, display the label.","category_group_clean":"The cleaned 4-value grouping: Equity Scheme / Debt Scheme / Hybrid Scheme / Other Scheme (SEBI 2026 folded Solution Oriented + Fund of Funds into Other Scheme). Use THIS for stable 4-way analysis; the raw as-filed header sits beside it in `category_group`.","category_sub":"SEBI sub-category. BLANK by design for ~25,000 old-style schemes AMFI never assigned one - mostly pre-2018 filings, plus later FMP/closed-end series AMFI kept filing under the old Income/Growth headers well past 2018. Their raw text lives in `category`.","is_active":"true = published a NAV within the last 45 days; recomputed every sync.","nav":"For matured schemes this is their FINAL NAV, frozen forever - check nav_date before treating it as current. A small set of matured schemes (~2,300) closed with a final FILED NAV of exactly 0.00 - kept as filed (publish-as-filed policy), so treat a 0.00 on an inactive row as a terminal marker, not a price. In the parquet file nav is a DECIMAL(18,4) logical type (4 decimal places; a few fund houses file more, and those are stored rounded to 4): pandas reads it as Python Decimal objects - cast to float before arithmetic (same in the full-history parquet). In duckdb-wasm a plain select of nav shows the unscaled integer (10.0774 as 100774); use CAST(nav AS DOUBLE) there."}}},"downloads":{"generated_at":"2026-10-13T05:40:25Z","files":{"amfi_nav_master.csv.gz":"220.4 MB","amfi_nav_master.csv.zip":"239.2 MB","amfi_nav_master.tsv.gz":"220.0 MB","amfi_nav_master.tsv.zip":"238.9 MB","amfi_nav_master.parquet":"170.4 MB","amfi_nav_master_latest.csv":"9.5 MB","amfi_nav_master_latest.csv.gz":"1.1 MB","amfi_nav_master_latest.csv.zip":"1.1 MB","amfi_nav_master_latest.parquet":"1.6 MB","amfi_nav_master.db.gz":"1.35 GB","amfi_nav_master.db.zip":"1.35 GB"}},"rate_limit":{"nav_search_manifest":"300 requests per minute per IP.","download_range":"3,000 range requests (HTTP 206) per minute per IP, and 25,000 per day. This is the path a remote DuckDB/pyarrow query takes - one unfiltered scan of the full parquet is roughly 300 range requests, so the daily budget is about 83 full scans.","download_whole_file":"60 whole-file requests (GET/HEAD returning 200/304) per minute per IP, and 500 per day.","concurrency":"Separate from the per-minute limits above: up to 32 requests may be open from one IP at the same moment. This counts requests IN FLIGHT, not requests per minute, so a client firing a wide parallel fan-out can be refused while well under 300/min. Up to 2 execute immediately and the rest queue briefly, so a burst is served slightly slower rather than rejected. Beyond that you get 429 with reason=client_concurrency. Batching with /mf/v1/nav?schemes=A,B,C (up to 50 per call) avoids this entirely - it is both faster and cheaper than parallel single-scheme calls.","reason_values":{"rate":"You exceeded the per-minute limit for your IP. Slow down, or take a bulk download.","client_concurrency":"You had too many requests in flight at once. Reduce parallelism or batch with ?schemes=.","server_concurrency":"Our pool was momentarily saturated across all callers. Nothing is wrong with your integration - honour Retry-After and retry."},"headers":"Rate-limit headers are present on every response, but the set differs by surface. MF endpoints other than /download (origin-served) carry X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix epoch seconds). /download* (edge-served) carries X-RateLimit-Limit, -Remaining, -Window plus X-RateLimit-Limit-Day, -Remaining-Day, -Window-Day, and no -Reset; its values are for the kind of request you just made, so a 206 reports the range budget and a 200 reports the whole-file budget. THE HEADERS ARE AUTHORITATIVE - read them rather than hardcoding the numbers above. On 429, Retry-After is set and the JSON body carries a `reason` field naming which limit you hit - branch on that rather than on the status code alone, because a rate 429 and a concurrency 429 need different fixes.","note":"Bulk endpoint /nav?schemes=A,B,... (max 50 per call) is the fastest way to fetch many schemes without burning the budget. For full-dataset access use /download. Pace against BOTH the per-minute and the per-day remaining counts on downloads - a job that only watches the per-minute figure can be refused hours later by the daily ceiling."},"parameter_handling":"/search is strict: an unknown parameter fails with 400 UNRECOGNIZED_PARAMETER, and an impossible date filter (first_date_from after first_date_to, or the last_date_ pair) fails with 400 INVALID_DATE_RANGE. /nav is lenient: an unknown parameter is ignored and named in a `warning` block (with did_you_mean), and since > to returns 200 with no rows, which pollers read as 'nothing new'.","error_shape":{"description":"Every error body carries a top-level `code` (UPPERCASE string, e.g. NO_DETAILS) and `path`: switch on `code`, which is always present and always a string. Most MF errors also carry an `error` object {code, message, docs_url}; the shared 404/405/429 replies carry `error` as a short lowercase label instead, alongside the same `code` (kept that way so existing integrations do not break). A 429 also carries `reason`, `retry_after_seconds` and a Retry-After header.","example":{"detail":"Unrecognized scheme identifier: FOO. Must be AMFI numeric code (4-7 digits) or ISIN (12-char, e.g. INF174K01LT0).","code":"INVALID_IDENTIFIER","path":"/mf/v1/nav","error":{"code":"INVALID_IDENTIFIER","message":"Unrecognized scheme identifier: FOO. Must be AMFI numeric code (4-7 digits) or ISIN (12-char, e.g. INF174K01LT0).","docs_url":"https://api.tigzig.com/mf/v1/docs"}},"known_codes":["INVALID_IDENTIFIER","INVALID_DATE_FORMAT","BULK_LIMIT_EXCEEDED","MISSING_IDENTIFIER","NOT_FOUND","MANIFEST_UNAVAILABLE","TOO_MANY_REQUESTS","INTERNAL_ERROR","INVALID_DATE_RANGE","INVALID_FORMAT","INVALID_FILTER_VALUE","INVALID_LIMIT","INVALID_OFFSET","UNRECOGNIZED_PARAMETER","REPEATED_PARAMETER","TOO_MANY_SCHEMES","VALIDATION_ERROR","SCHEME_NOT_FOUND","NO_DETAILS","DETAILS_UNAVAILABLE","INVALID_VIEW","UNKNOWN_FIELD","DOWNLOAD_UNAVAILABLE","BUSY_RETRY","BUSY_LARGE_REQUEST"]},"integration_hint":"Please set a descriptive User-Agent with a contact email so we can reach you if a change might affect your integration. Example: `User-Agent: Trackeefy/1.0 (contact@example.com)`. Not enforced. If you expect significant volume, drop a note to amar@harolikar.com and we can discuss a higher rate limit.","source":"https://mfpro.tigzig.com","license":"CC0 1.0 - to the extent this service holds any rights in the compilation (the assembly, the schema and the derived fields), they are released into the public domain. No attribution required.","license_url":"https://creativecommons.org/publicdomain/zero/1.0/","data_source":"The underlying NAV data is published by AMFI as public records. This service reformats and republishes it, is not an authoritative source, and is not affiliated with, endorsed by, or sponsored by AMFI. No rights in the NAV data itself are claimed here, and none are granted. Refer to AMFI's own terms and conditions before relying on it.","disclaimer":"Provided as is. No guarantee of accuracy, completeness or availability, and no support commitment. Check against AMFI for anything that matters.","terms":"https://api.tigzig.com/mf/v1/terms"}