API reference

Base URL https://fin.ejiapi.com. All endpoints are GET and return JSON.

Quickstart

  1. Request a key. It arrives by email.
  2. Send it in the x-api-key header.
curl -H "x-api-key: YOUR_KEY" \
  "https://fin.ejiapi.com/api/mf/scheme-code/122639"
import requests
r = requests.get("https://fin.ejiapi.com/api/mf/scheme-code/122639",
                 headers={"x-api-key": "YOUR_KEY"}, timeout=30)
print(r.json()["data"]["latestNav"])
const res = await fetch("https://fin.ejiapi.com/api/mf/scheme-code/122639",
  { headers: { "x-api-key": "YOUR_KEY" } });
console.log((await res.json()).data.latestNav);
Keep your key on a server or in Apps Script properties. Do not put it in a web page or app that other people can open.

Authentication

Send your key as the x-api-key header. Two endpoints are open and need no key: GET /api/mf (the full scheme list) and GET /api/mf/health. Every other endpoint needs a valid key. A missing, wrong or revoked key gets 401.

Response format

Successful responses share one envelope:

200 OK
{
  "status": "success",
  "statusCode": 200,
  "message": "Scheme fetched successfully",
  "data": { ... }
}

Dates are ISO YYYY-MM-DD. Navs are numbers. Holding weights, quantities and market values are strings with fixed decimals so no precision is lost.

Errors

Errors use application/problem+json:

404 Not Found
{
  "title": "Scheme not found",
  "status": 404,
  "detail": "Scheme not found",
  "instance": "/api/mf/scheme-code/100001"
}
StatusMeaning
400A parameter is malformed, for example startMonth not in MM-YYYY.
401Missing, invalid or revoked API key.
404Unknown scheme, or no holdings disclosure loaded for that scheme.
429Rate limit or monthly key quota reached. The message says which.

Limits

List all schemes

GET/api/mfno key

The full scheme master with latest and previous NAV. About 14,000 schemes.

Paginated list

GET/api/mf/paginated?page=1&size=20&category=key

page from 1. size 1 to 200 (default 20). category is an optional text match on the scheme category, for example Flexi Cap. The response has content and pagination (pageNumber, pageSize, totalPages, totalElements).

GET/api/mf/search?query=parag%20parikh&limit=25key

query at least 2 characters. limit 1 to 100 (default 25). Returns scheme objects.

Scheme object
{
  "schemeCode": "122639",
  "schemeName": "Parag Parikh Flexi Cap Fund",
  "schemeCategoryLabel": "Equity Scheme - Flexi Cap Fund",
  "schemeStructure": "Open Ended Schemes",
  "planName": "Direct Plan",
  "optionName": "Growth",
  "latestNav": 89.2762,
  "latestNavDate": "2026-10-27",
  "previousNav": 89.3,
  "previousNavDate": "2026-10-26",
  "isinDivPayoutOrGrowth": "INF879O01027",
  "isinDivReinvestment": null,
  "amcId": 27,
  "fundHouse": "PPFAS Mutual Fund"
}

By scheme code

GET/api/mf/scheme-code/{code}key

The scheme object above plus the 52-week fields 52WeekLowNav, 52WeekLowNavDate, 52WeekHighNav, 52WeekHighNavDate, computed from the stored history. They are omitted while a scheme has no stored history.

By ISIN

GET/api/mf/isin/{isin}key

The same object, found by ISIN.

By name

GET/api/mf/scheme-name/{name}key
GET/api/mf/scheme-name/{name}/variantskey

Look a scheme up by its name, or list the plan and option variants (Direct and Regular, Growth and IDCW) that share it. URL-encode the name.

Compare

GET/api/mf/compare?codes=122639,120503key

Up to five comma-separated scheme codes. Each item is the scheme object plus returns with cagr1y, cagr3y and cagr5y (percent, or null when there is not enough history).

AMCs

GET/api/mf/amcskey

Every fund house with its amcId and activeFunds count.

Funds of an AMC

GET/api/mf/amc/{amcId}/fundskey

By fund house name

GET/api/mf/fund-house/{name}key

NAV history

GET/api/mf/nav-history/scheme-code/{code}?start=2026-01-01&end=2026-10-27key
GET/api/mf/nav-history/isin/{isin}?start=&end=key

start and end are optional ISO dates. Oldest first.

Response data
[
  { "date": "2026-10-26", "nav": 89.3 },
  { "date": "2026-10-27", "nav": 89.2762 }
]

Rolling returns

GET/api/mf/scheme-code/{code}/rolling-summarykey
GET/api/mf/isin/{isin}/rolling-summarykey
Response data (shape only, values are illustrative)
{ "cagr1y": 14.2, "cagr3y": 18.9, "cagr5y": 21.4, "cagr10y": null }

Annualised returns in percent from the stored history. A value is null when the scheme does not have that much history yet.

Full NAV history for all schemes is still being loaded. Until it finishes, some schemes return null here and omit the 52-week fields. The status page will not show this; ask us if a scheme matters to you.

Holdings history

GET/api/mf/holdings-history/scheme-code/{code}?startMonth=01-2026&endMonth=09-2026key

startMonth and endMonth are optional and use MM-YYYY. Newest month first. Holdings in each month are sorted by weight.

Response data
{
  "schemeCode": "122639",
  "holdingsHistory": [
    {
      "holdingsMonth": "September",
      "holdingsYear": 2026,
      "holdingsAsOf": "2026-09-30",
      "holdings": [
        {
          "name": "HDFC Bank Limited",
          "displayName": "HDFC Bank Limited",
          "isin": "INE040A01034",
          "sector": "Banks",
          "category": "Equity",
          "weightage": "7.7500",
          "quantity": "158729224.0",
          "marketValue": "1124914.01",
          "nseSymbol": "-",
          "bseSymbol": "-"
        }
      ]
    }
  ]
}

weightage is the percent of net assets. marketValue is in the unit the AMC reports (usually lakhs of rupees). nseSymbol and bseSymbol are "-", since AMC disclosures list ISINs, not exchange symbols. Holdings of all plans of a fund (Direct, Regular, Growth, IDCW) are the same, so any scheme code of the fund works.

Holdings are loaded from AMC disclosures. Today that covers PPFAS and DSP. For a fund with nothing loaded yet you get 404 with "No holdings disclosure for this scheme".

Status

GET/api/mf/statusno key

Everything the status page shows, as JSON: overall state, components, uptime for 24 hours, 7 days, 30 days and per day, response times, data coverage (schemes, NAV history loaded, months of holdings) and incidents. Use it to monitor the API from your side. It is cached for a few seconds, so polling more than once a minute gains nothing.

Response data (abridged)
{
  "overall": "operational",
  "generatedAt": 1793170000,
  "components": [
    { "id": "api", "name": "API", "status": "operational", "detail": "Latest self check answered in 38 ms" },
    { "id": "nav", "name": "NAV refresh", "status": "operational", "detail": "Refreshed from AMFI every 6 hours" }
  ],
  "uptime": { "day": 100, "week": 99.97, "month": 99.97, "days": [ { "date": "2026-10-28", "uptime": 100, "minutes": 642 } ] },
  "latency": { "p50": 38, "p95": 61, "samples": 1438, "hourly": [ { "t": 1793166000, "ms": 40 } ] },
  "data": { "schemes": 14414, "amcs": 56, "latestNavDate": "2026-10-27" },
  "incidents": []
}

status is one of operational, degraded, outage or unknown (no data yet). Times are unix seconds. Values here are illustrative; the live response has more fields.

Freshness and coverage

Google Sheets

In a sheet: Extensions → Apps Script, paste, and save your key under Project Settings → Script properties as EJI_KEY.

Apps Script
function FUNDNAV(code) {
  const key = PropertiesService.getScriptProperties().getProperty("EJI_KEY");
  const res = UrlFetchApp.fetch("https://fin.ejiapi.com/api/mf/scheme-code/" + code,
    { headers: { "x-api-key": key } });
  return JSON.parse(res.getContentText()).data.latestNav;
}
// =FUNDNAV(122639)

Custom functions are cached by Sheets and recalculate when their input changes. To refresh daily, use a time-driven trigger that rewrites the values.