Authentication
Every endpoint (other than key creation and checkout) requires an X-API-Key header. There is no OAuth flow, no session token, and no key rotation endpoint yet — treat your key like a password.
A missing or invalid key returns 401 Unauthorized.
Python SDK
Prefer typed calls over raw HTTP? Install the official Python client from PyPI. It handles the X-API-Key header, JSON parsing into typed objects, pagination, and automatic retry with back-off when you hit a 429 rate limit.
Then set your key (either pass it directly or via the BHARATSTOCK_API_KEY environment variable) and call any endpoint:
The client mirrors this reference: client.stocks, client.deals, client.screener, client.indices, client.market, plus client.search(), client.movers(), client.price_shockers(), and client.status(). Source and full docs on PyPI →
JS/TS SDK
Building in Node.js or TypeScript? Install the official JS/TS client from npm. It handles the X-API-Key header, camelCased typed responses, pagination, and automatic retry with back-off when you hit a 429 rate limit. Works in Node 18+ and modern browsers/edge runtimes (native fetch, zero runtime dependencies).
Then set your key (either pass it directly or, in Node, via the BHARATSTOCK_API_KEY environment variable) and call any endpoint:
The client mirrors this reference and the Python SDK's structure: client.stocks, client.deals, client.screener, client.indices, client.market, plus client.search(), client.movers(), client.priceShockers(), and client.status(). Source and full docs on npm →
Rate limits
Enforced per calendar day (UTC), per API key. Limits depend on your plan: 50/day on Free, 2,000/day on Starter, 10,000/day on Developer, 50,000/day on Pro. Every plan has access to every endpoint — the plan governs your daily request quota and how far back you can read (see Historical data depth).
Returned with HTTP status 429. The counter resets at UTC midnight.
Usage & redistribution
Your subscription grants a limited, internal-use right: you may consume the data inside your own application or workflow and display it (or analysis derived from it) to your own end-users. You may not resell, re-serve, relicense, syndicate, or bulk-redistribute the raw data to third parties as a feed, dataset, file, or API, or use it to build a competing data-distribution product.
This is strictest for exchange-sourced data (EOD prices/OHLCV, index names and values, and bulk/block deals), which is owned by the exchanges (NSE/BSE). Redistributing that data generally requires your own direct redistribution licence from the exchange — we do not grant, and cannot pass through, any such right. If you have a redistribution or white-label use case, contact us before building on it. Full terms are in the Terms of Use.
Historical data depth
Paid plans return the full archive — over a decade of daily prices, financials, corporate actions, shareholding, and more. On the Free plan the time-series endpoints return only the most recent 1 year of history (annual financials get 2 years so you can still compare year-over-year). This applies to prices, technical indicators, index prices, financials, corporate actions, shareholding, bulk/block/insider deals, and FII/DII activity.
The window is silently clamped — a Free key requesting an older from date just receives rows from within the allowed window (no error). Upgrade to any paid plan for the complete history.
MCP server
Use BharatStock as native tools inside AI assistants (Claude Desktop, Cursor, and other MCP hosts) via our official Model Context Protocol server, published on npm as bharatstock-mcp. It wraps the same data endpoints as this API, using your API key — so your plan's limits and history depth apply exactly as they do here.
MCP is a Developer/Pro feature. The server verifies your plan on startup; Free and Starter keys are declined with an upgrade prompt.
Add it to your MCP host's config (no install needed — npx fetches it on demand):
Once connected, your assistant gets ~30 tools covering the full consumer API — quotes, historical prices, financials, fundamentals, technicals, shareholding, corporate actions, bulk/block/insider deals, sector peer comparison, search, market movers, the screener, indices, FII/DII activity, and mutual-fund schemes/NAVs/returns/holdings.
Optional fields: only BHARATSTOCK_API_KEY is required. You may also set BHARATSTOCK_BASE_URL in env to point at a self-hosted/staging API (defaults to the public API). Some hosts (e.g. Kiro) also accept an autoApprove array listing tool names to run without a per-call prompt — a host-specific convenience, not part of the config the key needs.
Prefer a hosted URL (for hosts that connect to a remote MCP endpoint instead of spawning a process)? Point them at https://bharatstockapi.com/v1/mcp with an Authorization: Bearer <your key> header — same Developer/Pro requirement.
Pagination
List endpoints share one envelope shape across the whole API: a data array plus a pagination object. Use the page and page_size query parameters to page through results.
Errors
Validation errors return 422 with a structured detail array. Not-found resources return 404. Everything else follows standard HTTP status codes.
NSE vs BSE data coverage
Every stock has an exchange field: "NSE" for stocks listed on NSE (including ones cross-listed on BSE too), or "BSE" for stocks listed only on BSE. The two data pipelines are now equivalent in coverage — quarterly and annual financials, sector/industry, daily prices and corporate actions are all populated for BSE-exclusive stocks as well. Quarterly financials come from BSE's integrated filing feed and are current to the latest reported quarter, same freshness as NSE. Sector/industry, which BSE's own security master doesn't expose, is backfilled by inference and populated for the large majority of BSE-exclusive stocks (it may be null where no reliable classification exists — best-effort, not guaranteed, same as NSE's own feed). Every stock response includes a data_coverage object stating this, so you can branch on it programmatically instead of inferring it from exchange:
data_coverage is a structural statement of what the pipeline can populate for that exchange, not a live check of the database — e.g. sector_industry: true means "populated where available," not "guaranteed non-null." For NSE it comes from NSE's classification feed (which covers roughly 750 of the more liquid names); for BSE-exclusive stocks it's backfilled by inference and populated for the large majority, but may still be null where no reliable classification exists.
Public data-integrity status — no API key required. Reports whether our daily automated checks are currently passing: freshness (each feed current to its real publication cadence) and correctness (every derived value recomputed from its inputs and required to agree, e.g. P/E = price ÷ TTM EPS, adjusted close = close × factor). This is the same data behind the human-friendly status page.
Values: status is operational, degraded, or unknown (not yet verified). Each check reports a plain-English label, a category (Freshness / Completeness / Correctness), and a status. Unauthenticated and safe to poll.
List all stocks, paginated and optionally filtered by search text or sector.
| Param | Type | Description |
|---|---|---|
| page | int | Page number. Default 1. |
| page_size | int | Rows per page, max 200. Default 50. |
| q optional | string | Search by symbol or company name. |
| sector optional | string | Filter by exact sector name, e.g. "Financial Services". |
| active_only | bool | Exclude delisted stocks. Default true. |
Company info plus the latest available EOD price for a ticker.
| Param | Type | Description |
|---|---|---|
| exchange optional | string | NSE or BSE. Only needed to disambiguate a ticker shared by two different companies across exchanges (see note below). Defaults to the NSE listing. |
Unknown ticker returns 404.
Historical daily prices, optionally bounded by date range. Includes a bonus/split-adjusted close so charts don't show a fake jump on an ex-date.
| Param | Type | Description |
|---|---|---|
| from optional | date | Start date, e.g. 2026-01-01. |
| to optional | date | End date. |
| page, page_size | int | Standard pagination, most recent first. |
Latest price snapshot for multiple tickers in one call — built for watchlists and dashboards. Unknown symbols come back with found: false instead of failing the whole request.
| Param | Type | Description |
|---|---|---|
| symbols | string | Comma-separated tickers, e.g. RELIANCE,TCS,INFY. Max 50. |
Quarterly or annual P&L, balance sheet, and cash flow, normalized from official company financial disclosures — including bank/NBFC statement formats and consolidated-vs-standalone reporting. Annual rows also expose other_equity (Ind-AS reserves + retained earnings, for the Altman Z-score) and capex (purchase of PPE + intangibles, so Free Cash Flow = cash_flow_operating − capex).
| Param | Type | Description |
|---|---|---|
| period_type | string | quarterly or annual. Default quarterly. |
| page, page_size | int | Standard pagination, most recent period first. |
Valuation and profitability ratios, computed on read from the latest price and the latest annual filing (falling back to quarterly if no annual filing exists yet).
SMA, EMA, RSI, and MACD, computed server-side from daily closes. Values are null wherever there isn't enough price history yet to compute them.
| Param | Type | Description |
|---|---|---|
| sma_period | int | Default 20. |
| ema_period | int | Default 20. |
| rsi_period | int | Default 14 (Wilder's smoothing). |
| from, to optional | date | Bound the returned window. |
Dividends, bonus issues, splits, and rights issues for a ticker, most recent ex-date first.
| Param | Type | Description |
|---|---|---|
| action_type optional | string | dividend, bonus, split, rights, buyback, or other. |
Monthly mutual fund holdings — which MF schemes hold this stock, their position size in crores, percentage of AUM, and month-over-month quantity change. Paginated, sorted by market value descending.
Source: compiled from the fund houses' own official monthly portfolio disclosures — pulled directly from 44+ AMCs' sites (first-party) for the houses we cover, with an aggregator filling any remaining houses. First-party AMC data is authoritative where available.
| Param | Type | Description |
|---|---|---|
| page | int | Page number (default 1). |
| page_size | int | Items per page, 1-100 (default 20). |
| month | string | Optional. Filter by month in YYYY-MM format (e.g. 2026-06). Defaults to latest available. |
Compare valuation and profitability ratios across every active stock in a sector — computed in bulk rather than looping the single-ticker ratios endpoint.
| Param | Type | Description |
|---|---|---|
| sector | string | Exact sector name, e.g. "Financial Services". |
| sort | string | market_cap, pe_ratio, pb_ratio, roe, or roce. Default market_cap. |
| limit | int | Max 100. Default 20. |
Bulk deals for a ticker — single-day trades where one client traded more than 0.5% of the company's listed equity. Most recent first.
| Param | Type | Description |
|---|---|---|
| buy_sell | string | Optional. Filter by BUY or SELL only. |
| page | int | Default 1. |
| page_size | int | Max 200. Default 50. |
| exchange | string | Optional. NSE or BSE to disambiguate shared tickers. |
Block deals for a ticker — large trades executed in the exchange's dedicated block-deal window (minimum ticket size ~₹10 Cr). Same parameters and shape as bulk deals.
| Param | Type | Description |
|---|---|---|
| buy_sell | string | Optional. BUY or SELL. |
| page | int | Default 1. |
| page_size | int | Max 200. Default 50. |
| exchange | string | Optional. NSE or BSE. |
Insider / promoter (SEBI PIT) disclosures for a ticker — filed when promoters, directors, or KMPs buy or sell above the regulatory threshold. Strong "smart money" signal.
| Param | Type | Description |
|---|---|---|
| transaction_type | string | Optional. acquisition or disposal. |
| promoters_only | bool | Optional. true to see only promoter/promoter-group disclosures. |
| page | int | Default 1. |
| page_size | int | Max 200. Default 50. |
| exchange | string | Optional. NSE or BSE. |
Recent bulk deals across all stocks, most recent first. Includes symbol and company_name in each row. Cached.
| Param | Type | Description |
|---|---|---|
| buy_sell | string | Optional. BUY or SELL. |
| page | int | Default 1. |
| page_size | int | Max 200. Default 50. |
Recent block deals across all stocks, most recent first. Same response shape as /v1/deals/bulk.
| Param | Type | Description |
|---|---|---|
| buy_sell | string | Optional. BUY or SELL. |
| page | int | Default 1. |
| page_size | int | Max 200. Default 50. |
Recent insider/promoter disclosures across all stocks. Includes symbol, company_name, and all fields from the per-ticker endpoint. Useful for scanning "who's been buying" market-wide.
| Param | Type | Description |
|---|---|---|
| transaction_type | string | Optional. acquisition or disposal. |
| promoters_only | bool | Optional. true for promoter-only. |
| page | int | Default 1. |
| page_size | int | Max 200. Default 50. |
Top gainers, losers, or most-active-by-volume stocks for the most recent trading day with price data. Uses the latest date present in the data, not today's calendar date, so it stays correct on weekends and holidays.
| Param | Type | Description |
|---|---|---|
| category | string | gainers, losers, or active. Default gainers. |
| limit | int | Max 100. Default 20. |
Stocks whose price moved by at least a given percent versus the previous close. Unlike /movers (always a top-N ranking), this is a threshold filter — it can return zero rows on a quiet day, or more than limit on a volatile one.
| Param | Type | Description |
|---|---|---|
| min_change_pct | float | Minimum absolute % move. Default 5.0. |
| direction | string | up, down, or both. Default both. |
| limit | int | Max 200. Default 50. |
Fuzzy search across ticker symbol and company name. Ranks exact/prefix symbol matches above substring/company-name matches, active stocks first.
| Param | Type | Description |
|---|---|---|
| q | string | Search text, e.g. "reliance". |
| limit | int | Max 50. Default 10. |
Filter and screen stocks by 72 pre-computed metrics (refreshed daily) using a generic filter syntax. Combine as many filters as needed. Returns paginated results sorted by any metric.
Pagination & sorting
| Param | Type | Description |
|---|---|---|
| page optional | int | Page number. Default 1. |
| page_size optional | int | Results per page, 1-200. Default 50. |
| sort_by optional | string | Any metric name (e.g. market_cap, pe_ratio, roe, return_1y, free_cash_flow). Default: market_cap. |
| sort_order optional | string | desc or asc. Default: desc. |
Filtering (generic syntax)
| Param | Type | Description |
|---|---|---|
| filter repeatable | string | Format: metric.operator.value. Pass multiple filter params to combine conditions (AND logic). |
| sector optional | string | Sector name (exact match), e.g. "Information Technology". |
| exchange optional | string | NSE or BSE. |
Operators
| Operator | Meaning | Example |
|---|---|---|
gt | Greater than (>) | filter=roe.gt.15 |
lt | Less than (<) | filter=pe_ratio.lt.20 |
gte | Greater than or equal (≥) | filter=promoter_holding.gte.50 |
lte | Less than or equal (≤) | filter=debt_to_equity.lte.1 |
eq | Equals (=) | filter=current_ratio.eq.2 |
Note: Response includes 72 metrics per stock. market_cap in the response is in Crores; filter=market_cap.gt.10000 also expects Crores. Metrics are refreshed daily at 9pm IST. Stocks with NULL for a filtered metric are excluded from that filter.
All 72 filterable & sortable metrics
| Category | Metrics |
|---|---|
| Price | price, high_52w, low_52w, distance_from_52w_high_pct, distance_from_52w_low_pct, avg_volume_30d, avg_delivery_pct_30d, avg_turnover_30d, price_vs_200dma_pct, price_vs_50dma_pct |
| Returns | return_1w, return_1m, return_3m, return_6m, return_1y, return_2y, return_3y, return_5y |
| Volatility | volatility_30d, volatility_365d |
| Valuation | market_cap, pe_ratio, pb_ratio, book_value_per_share, roe, roce, dividend_yield, earnings_yield, peg_ratio, ev_to_ebitda, enterprise_value, price_to_sales, shares_outstanding |
| Per-share | eps, diluted_eps, cash_per_share, revenue_per_share |
| Margins | operating_margin, net_margin, ebitda_margin |
| Absolute financials | ebitda, revenue_ttm, net_profit_ttm |
| Growth | revenue_growth_yoy, profit_growth_yoy, eps_growth_yoy, revenue_growth_qoq, net_profit_margin_qoq_change |
| Balance sheet | debt_to_equity, current_ratio, interest_coverage, total_debt, working_capital, asset_turnover, inventory_turnover, receivables_days, payables_days |
| Cash flow | cash_flow_operating, free_cash_flow, cfo_to_net_profit |
| Tax & depreciation | tax_rate, depreciation_to_revenue |
| Shareholding | promoter_holding, promoter_holding_change_qoq, fii_holding, dii_holding, mutual_funds_holding, public_holding, individuals_holding, fii_holding_change_qoq, dii_holding_change_qoq, mutual_funds_holding_change_qoq, total_shares |
Every metric above supports _gt and _lt filter suffixes. For example: pe_ratio_lt=15, fii_holding_gt=10, debt_to_equity_lt=1, return_5y_gt=100. Combine as many as needed.
Daily aggregate FII/DII cash market activity — buy, sell, and net values in ₹ Crores. Market-wide aggregate (not per-stock). Sorted by date descending.
| Param | Type | Description |
|---|---|---|
| from optional | date | Start date (YYYY-MM-DD). Default: 30 days ago. |
| to optional | date | End date (YYYY-MM-DD). Default: today. |
| limit optional | int | Max rows (1-365). Default: 30. |
| latest optional | bool | If true, return only the single most recent day (ignores from/to/limit). |
Note: Values are in ₹ Crores. Positive fii_net/dii_net = net buying. Published after market close each trading day.
List / search mutual-fund schemes across every AMC (the industry-wide AMFI NAV universe). Each row is one AMFI scheme_code — a (scheme, plan, option) variant with its own NAV. Distinct from /v1/stocks/{ticker}/mf-holdings (which schemes hold a given stock).
Source: the scheme universe and daily NAVs come from AMFI's official industry-wide NAV feed, updated every evening — with NAV history back to 2006 (~20 years).
| Param | Type | Description |
|---|---|---|
| q optional | string | Case-insensitive substring match on scheme name. |
| amc optional | string | Filter by AMC name (substring). |
| category optional | string | Filter by AMFI category (substring), e.g. Flexi Cap. |
| plan optional | string | Direct or Regular (substring). |
| option optional | string | Growth or IDCW (substring). |
| isin optional | string | Exact match on either ISIN (growth or div-reinvest). |
| limit optional | int | Max rows (1-500). Default: 50. |
| offset optional | int | Rows to skip (pagination). Default: 0. |
One scheme's identity plus its latest NAV (with the as-of date). The path value is the AMFI scheme_code from the list endpoint.
Trailing returns computed from the scheme's NAV series (sourced from AMFI's daily feed). Sub-1-year horizons are point-to-point; 1Y and longer are annualized (CAGR). Always derived from the raw NAV — never precomputed — so they can't drift from the underlying series. Horizons without enough history are null.
Note: Percentages. For 1Y and longer the value is annualized (CAGR); for shorter horizons it's the simple point-to-point change.
List all tracked NSE indices, paginated and optionally filtered by category (e.g. broad-market vs. sectoral).
| Param | Type | Description |
|---|---|---|
| category optional | string | e.g. "BROAD MARKET INDICES", "SECTORAL INDICES". |
Historical daily EOD levels for an index, optionally bounded by date range.
Changelog
Notable changes to the official SDKs (Python bharatstock on PyPI, JavaScript/TypeScript bharatstock on npm). The SDKs track the API surface; the REST API itself is additive and backward compatible.
Python SDK
- 0.1.7 (2026-09-15) — Added a
Changelogproject link and this changelog page. Metadata only; no code change. - 0.1.6 (2026-09-15) — Packaging metadata:
CHANGELOG.mdshipped in the sdist. No code change. - 0.1.5 (2026-09-15) — Documentation refresh for the Mutual Funds resource (fully documented, runnable examples). No code change.
- 0.1.4 — Added the
MutualFundsresource: list/search schemes, scheme detail + latest NAV, daily NAV history (~20 years), and trailing returns (1m/3m/6m/1y/3y/5y/since-inception).
JavaScript / TypeScript SDK
- 0.1.8 (2026-09-15) — Added a "Jump to Changelog" link and this changelog page. Metadata only; no code change.
- 0.1.7 (2026-09-15) — Shipped a standalone
CHANGELOG.md. No code change. - 0.1.6 (2026-09-15) — Documentation refresh for the
mutualFundsresource. No code change. - 0.1.5 — Added the
mutualFundsresource:listSchemes,getScheme,nav,returns, mirroring the Python SDK.
Full per-release notes also ship inside each package (README changelog + CHANGELOG.md).