This is the full developer documentation for Tapetide API
# Indian market data for code and agents
> Quotes, financial statements, price history, shareholding, options analytics, indices and market flows for about 8,200 NSE and BSE stocks. Call it over REST, or connect an AI assistant over MCP with the same token.
## What you get
[Section titled “What you get”](#what-you-get)
* **One contract.** Every success is `{ data, meta }`, every error is `{ error: { code, message } }`. Collections add `links.next` and an opaque cursor.
* **Complete documents.** Nothing is trimmed to fit. Routes that page say so in `meta`.
* **Honest values.** A missing figure is `null`, never `0`. Dates are IST trading dates.
* **Point-in-time fields.** Financial periods carry the date they became public, so a backtest can avoid look-ahead.
* **Agent ready.** An MCP server, `llms.txt`, and a Markdown twin of every page on this site.
[Quickstart](/quickstart/)Create a token and call a real endpoint with curl, Python or JavaScript.
[Authentication](/authentication/)Personal tokens, access tokens and the shared MCP quota.
[Pagination](/pagination/)Cursor paging on collections and end_date paging on price history.
[Use Tapetide from an agent](/guides/agents/)MCP setup for Claude, ChatGPT, Cursor and more, or REST from your own agent.
Machine-readable contract: [`openapi.json`](https://api.tapetide.com/v1/openapi.json) (OpenAPI 3.1).
Data is for information only and is not investment advice. Tapetide is not a SEBI-registered investment adviser or research analyst.
# Quickstart
> Create a token and make your first Tapetide API request with curl, Python or JavaScript.
1. **Create a token.** Sign in at [tapetide.com/settings](https://tapetide.com/settings) and create a personal token. It starts with `tpt_rt_`. Keep it out of source control.
```bash
export TAPETIDE_TOKEN=tpt_rt_...
```
2. **Check your quota.** `/v1/me/usage` is free, so it is a safe first call.
```bash
curl -s -H "Authorization: Bearer $TAPETIDE_TOKEN" https://api.tapetide.com/v1/me/usage
```
3. **Fetch a quote.** This costs one request unit.
* curl
```bash
curl -s -H "Authorization: Bearer $TAPETIDE_TOKEN" \
https://api.tapetide.com/v1/stocks/TCS/quote
```
* Python
```python
import os
import requests
resp = requests.get(
"https://api.tapetide.com/v1/stocks/TCS/quote",
headers={"Authorization": f"Bearer {os.environ['TAPETIDE_TOKEN']}"},
timeout=30,
)
resp.raise_for_status()
quote = resp.json()["data"]
print(quote["symbol"], quote["price"], quote["change_pct"])
```
* JavaScript
```js
const res = await fetch("https://api.tapetide.com/v1/stocks/TCS/quote", {
headers: { Authorization: `Bearer ${process.env.TAPETIDE_TOKEN}` },
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${res.status} ${error.code}: ${error.message}`);
}
const { data, meta } = await res.json();
console.log(data.symbol, data.price, meta.as_of);
```
4. **Read the response.** Every success has the same envelope (abridged here).
```json
{
"data": {
"symbol": "TCS",
"name": "Tata Consultancy Services Ltd",
"price": 2427,
"change": 77,
"change_pct": 3.28,
"prev_close": 2350,
"volume": 5532201,
"market_cap": 878109.84,
"pe_ttm": 17.63,
"high_52w": 3350,
"low_52w": 1976.8,
"updated_at": "2026-10-16T05:57:16+00:00"
},
"meta": { "as_of": "2026-10-16T06:01:12.418Z", "route": "getStockQuote" }
}
```
`market_cap` is in INR crore. `meta.as_of` is when the response was assembled; `data.updated_at` is when the price was observed.
## Next requests to try
[Section titled “Next requests to try”](#next-requests-to-try)
```bash
# Find a symbol by name, BSE code or ISIN
curl -s -H "Authorization: Bearer $TAPETIDE_TOKEN" "https://api.tapetide.com/v1/stocks?q=hdfc%20bank"
# Quarterly P&L with the date each quarter became public
curl -s -H "Authorization: Bearer $TAPETIDE_TOKEN" "https://api.tapetide.com/v1/stocks/TCS/financials?section=quarterly"
# 30 days of daily OHLCV
curl -s -H "Authorization: Bearer $TAPETIDE_TOKEN" "https://api.tapetide.com/v1/stocks/RELIANCE/price?days=30"
# Up to 20 quotes in one call
curl -s -H "Authorization: Bearer $TAPETIDE_TOKEN" "https://api.tapetide.com/v1/quotes?symbols=RELIANCE,TCS,HDFCBANK"
```
Every operation, with parameters and response schemas, is in the [API reference](/api/). To try requests in the browser, open the [playground](/playground/).
# Authentication
> Bearer tokens for the Tapetide API, how to create them, and how they relate to the MCP server.
Send a token on every request:
```http
GET /v1/stocks/TCS/quote HTTP/1.1
Host: api.tapetide.com
Authorization: Bearer tpt_rt_...
```
## Token types
[Section titled “Token types”](#token-types)
| Token | Prefix | Where it comes from | Use it for |
| -------------- | --------- | ------------------------------------------------------------------------ | ------------------------------------------ |
| Personal token | `tpt_rt_` | Created by you at [tapetide.com/settings](https://tapetide.com/settings) | Scripts, servers, notebooks, agents |
| Access token | `tpt.` | Issued by Tapetide sign-in (OAuth) to an MCP client | Short-lived; you rarely handle it directly |
Both are accepted by the REST API and the MCP server. A personal token works until you revoke it in settings.
## One account, one quota
[Section titled “One account, one quota”](#one-account-one-quota)
REST and MCP share the same account and the same quota. A REST request costs exactly what an MCP tool call costs, and a token created for one works on the other. See [Rate limits and quota](/rate-limits/).
## Failures
[Section titled “Failures”](#failures)
| Status | `error.code` | Meaning |
| ------ | ------------------------- | ----------------------------------------------------------------------- |
| 401 | `authentication_required` | No `Authorization: Bearer` header was sent. |
| 401 | `invalid_token` | The token is unknown, expired or revoked. Create a new one in settings. |
401 responses carry `WWW-Authenticate: Bearer realm="tapetide"` and are never charged.
## Keeping tokens safe
[Section titled “Keeping tokens safe”](#keeping-tokens-safe)
* Store tokens in environment variables or a secret manager, not in code or notebooks you share.
* Use one token per application so you can revoke one without breaking the others.
* Browser code exposes its token to anyone who opens dev tools. Call the API from a server you control, or use the [playground](/playground/) for experiments.
# Pagination
> How Tapetide collections page with an opaque cursor, and how price history pages with end_date.
Tapetide never truncates a response to fit. When a result is larger than one page, the response says so and gives you the exact value to ask for the next page.
## Cursor pagination (collections)
[Section titled “Cursor pagination (collections)”](#cursor-pagination-collections)
Collection endpoints return an array in `data`, paging fields in `meta`, and a ready-made next URL in `links`:
```json
{
"data": [
{ "date": "2026-10-20", "name": "Diwali Laxmi Pujan", "exchange": "NSE", "type": "FULL" }
],
"meta": {
"as_of": "2026-10-16T09:30:00.000Z",
"route": "listMarketHolidays",
"count": 1,
"limit": 100,
"has_more": true,
"next_cursor": "eyJkIjoiMjAyNi0xMC0yMCJ9"
},
"links": { "next": "/v1/market/holidays?from=2026-01-01&cursor=eyJkIjoiMjAyNi0xMC0yMCJ9" }
}
```
| Field | Meaning |
| ------------------ | -------------------------------------------------------------------------------------------------------------- |
| `meta.count` | Items in this page. |
| `meta.limit` | The page size that was applied. |
| `meta.has_more` | `true` when another page exists. |
| `meta.next_cursor` | Opaque string for the next page, or `null` on the last page. |
| `links.next` | Path and query for the next page with your filters kept, or `null`. Prefix it with `https://api.tapetide.com`. |
### The rules
[Section titled “The rules”](#the-rules)
* **`limit`** defaults per endpoint (shown in the reference) and has a per-endpoint maximum. A value above the maximum is rejected with `400 invalid_request`. It is never silently clamped.
* **`cursor`** is opaque. Pass `meta.next_cursor` back unchanged, with the same filters. A cursor the API did not issue returns `400 invalid_request` with `details.param = "cursor"`.
* Paging is keyset, not offset, so pages stay stable while new rows arrive at the other end of the range.
* Each page is one request and costs one unit.
* Unknown query parameters are rejected with a `400` that lists the accepted ones, so a typo never silently returns unfiltered data.
### Follow every page
[Section titled “Follow every page”](#follow-every-page)
```python
import os, requests
BASE = "https://api.tapetide.com"
s = requests.Session()
s.headers["Authorization"] = f"Bearer {os.environ['TAPETIDE_TOKEN']}"
url = "/v1/market/holidays?from=2020-01-01&limit=500"
rows = []
while url:
body = s.get(BASE + url, timeout=30).json()
rows.extend(body["data"])
url = body["links"]["next"]
print(len(rows))
```
```js
let url = "/v1/market/holidays?from=2020-01-01&limit=500";
const rows = [];
while (url) {
const res = await fetch(`https://api.tapetide.com${url}`, {
headers: { Authorization: `Bearer ${process.env.TAPETIDE_TOKEN}` },
});
const body = await res.json();
rows.push(...body.data);
url = body.links.next;
}
```
## Window pagination (price history)
[Section titled “Window pagination (price history)”](#window-pagination-price-history)
`/v1/stocks/{symbol}/price` serves at most 2,000 calendar days per call. It reports the window it actually served in `meta.window`:
```json
"window": {
"requested_days": 2000,
"served_days": 2000,
"max_days": 2000,
"truncated": false,
"first_date": "2021-04-26",
"last_date": "2026-10-14",
"has_more": true,
"next_cursor": "2021-04-25"
}
```
To page further back, pass `meta.window.next_cursor` as `end_date` on the next call and repeat until `has_more` is `false`. Always read `truncated`: when it is `true` you asked for more days than one call serves.
## Bounded lists without a cursor
[Section titled “Bounded lists without a cursor”](#bounded-lists-without-a-cursor)
Some older routes (for example `/v1/stocks/{symbol}/events`, `/deals`, `/v1/market/news`) return the most recent N items with a `limit` parameter and no cursor. The reference states the default and maximum for each.
# Errors
> The Tapetide API error envelope, every error code, and which errors are charged.
Every error has the same shape and an HTTP status that matches it:
```json
{
"error": {
"code": "invalid_request",
"message": "\"limit\" number must be less than or equal to 500.",
"details": { "param": "limit" }
}
}
```
* `code` is stable. Branch on it, not on `message`.
* `message` is for people and may change wording.
* `details` is optional. For parameter errors it names the offending `param`.
## Error codes
[Section titled “Error codes”](#error-codes)
| Status | `code` | When | What to do |
| ------ | ------------------------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| 400 | `invalid_request` | A parameter is unknown, malformed, out of range, or a cursor was not issued by the API. | Fix the parameter named in `details.param`. |
| 401 | `authentication_required` | No bearer token was sent. | Send `Authorization: Bearer `. |
| 401 | `invalid_token` | The token is invalid, expired or revoked. | Create a new token at [tapetide.com/settings](https://tapetide.com/settings). |
| 404 | `not_found` | The symbol, index or document does not exist. | Look the symbol up with `GET /v1/stocks?q=`. |
| 404 | `route_not_found` | No such path. | Check the path against the [reference](/api/). |
| 405 | `method_not_allowed` | A method other than `GET` (or `OPTIONS`). | The API is read-only. |
| 429 | `rate_limited` | Per-minute burst cap reached. | Wait `Retry-After` seconds. |
| 429 | `quota_exhausted` | Your plan’s daily or monthly quota is used. | Wait until `X-RateLimit-Reset`, or upgrade. |
| 500 | `tool_error` | The request reached a dataset that could not answer it. | Retry once; report it if it persists. |
| 500 | `internal_error` | An unexpected failure. | Retry with backoff. |
| 502 | `upstream_unavailable` | A data dependency was briefly unavailable. | Retry with backoff. |
| 503 | `service_unavailable` | Tapetide is briefly unavailable. | Wait `Retry-After` seconds. |
## Charging
[Section titled “Charging”](#charging)
Only a `200` costs a request unit. Every error above is free, including `429`.
## Retrying
[Section titled “Retrying”](#retrying)
Retry `429`, `500`, `502` and `503`. Do not retry `400`, `401`, `404` or `405` without changing the request.
```python
import time, requests
def get(session, url, attempts=4):
for i in range(attempts):
r = session.get(url, timeout=30)
if r.status_code not in (429, 500, 502, 503):
return r
wait = int(r.headers.get("Retry-After", 2 ** i))
if r.status_code == 429 and r.json()["error"]["code"] == "quota_exhausted":
return r # waiting will not help within this run
time.sleep(min(wait, 60))
return r
```
# Data conventions
> Dates, units, nulls and point-in-time fields in Tapetide API responses.
These rules hold across every endpoint unless the reference for a field says otherwise.
## Dates and times
[Section titled “Dates and times”](#dates-and-times)
| Kind | Format | Example |
| ---------------------- | -------------------------------------------------- | ---------------------- |
| Trading date | `YYYY-MM-DD`, the IST calendar date of the session | `2026-10-14` |
| Timestamp | ISO-8601 in UTC | `2026-10-16T05:57:16Z` |
| Month | `YYYY-MM`, IST | `2026-10` |
| Financial period label | Month and year the period ends | `Jun 2026` |
`meta.as_of` is when the response was assembled. A field like `updated_at` or `snapshot_ts` is when the underlying value was observed. Quote both when freshness matters.
## Units
[Section titled “Units”](#units)
| Quantity | Unit |
| ------------------------------------------- | ----------------------------------------------------------------------- |
| Prices, values, P\&L | INR, as numbers |
| Market capitalisation and statement figures | INR crore unless a field says otherwise |
| Percentages | Numbers where `1.5` means 1.5% (`change_pct`, `iv_pct`, `delivery_pct`) |
| Volume, open interest | Shares or contracts, as integers |
## Null is not zero
[Section titled “Null is not zero”](#null-is-not-zero)
A missing value is `null`. It means the figure is not published or not available for that row. It is never a stand-in for `0`. Treat `null` as unknown: exclude it from averages, do not plot it as zero, and do not compute a return across it.
## Symbols
[Section titled “Symbols”](#symbols)
* Paths take NSE symbols such as `RELIANCE`, `TCS`, `HDFCBANK`. Search by name, BSE code or ISIN with `GET /v1/stocks?q=`.
* Percent-encode `&`: `M&M` is `/v1/stocks/M%26M/quote`.
* Responses carry `symbol` and, where relevant, `isin`. Internal ids are not part of the contract.
## Point-in-time fields
[Section titled “Point-in-time fields”](#point-in-time-fields)
Historical research must use only what was known on each date. Tapetide exposes the fields that make that possible:
* **Financial statements** carry an `availability` array per section: each period’s `available_from` date and a `basis` of `reported` (the actual result-declaration date) or `estimated` (a regulatory-lag estimate when the declaration date is unknown). The values are the latest reported figures and can include later restatements.
* **Price history** `close` is adjusted for splits and bonuses, not for dividends. `raw_close` is the unadjusted print where available, and `null` where it is not. Never substitute `close` for a missing `raw_close`: the two are on different scales.
* **Option chains** are end-of-day snapshots stamped with `snapshot_ts`.
See [Build a backtest with point-in-time data](/guides/backtest-point-in-time/).
## Field names
[Section titled “Field names”](#field-names)
`snake_case`, plural kebab-case paths, and no abbreviations beyond the market’s own (`pe_ttm`, `oi`, `iv`).
# Agents: use Tapetide via MCP or REST
> Connect Claude, ChatGPT, Cursor and other AI clients to Tapetide over MCP, or call the REST API from your own agent.
Tapetide has two front doors to the same data, account and quota.
| | MCP server | REST API |
| -------- | ------------------------------------------------ | --------------------------------------------- |
| Endpoint | `https://mcp.tapetide.com/mcp` (Streamable HTTP) | `https://api.tapetide.com/v1` |
| Best for | Chat apps and coding assistants that speak MCP | Your own code, pipelines and custom agents |
| Auth | Google sign-in (OAuth) or a personal token | Personal token |
| Shape | 55 tools with LLM-oriented descriptions | Typed JSON documents described by OpenAPI 3.1 |
Calls on either side count against one quota: 50 successful calls a day on the free plan.
## Connect an MCP client
[Section titled “Connect an MCP client”](#connect-an-mcp-client)
Most clients only need the server URL, then a Google sign-in when the browser opens.
**Claude Code**
```bash
claude mcp add --transport http tapetide https://mcp.tapetide.com/mcp
```
Then open `/mcp` in Claude Code, select Tapetide and sign in.
**Cursor** (`.cursor/mcp.json`)
```json
{
"mcpServers": {
"tapetide": { "url": "https://mcp.tapetide.com/mcp" }
}
}
```
**Codex**
```bash
codex mcp add tapetide --url https://mcp.tapetide.com/mcp
codex mcp login tapetide
```
**Claude.ai and ChatGPT**: add a custom connector named Tapetide with the URL `https://mcp.tapetide.com/mcp` and sign in with Google.
**Clients that cannot open a browser** send a personal token instead: `Authorization: Bearer tpt_rt_...`. Claude Desktop uses the local helper:
```json
{
"mcpServers": {
"tapetide": {
"command": "bunx",
"args": ["tapetide-mcp"],
"env": { "TAPETIDE_TOKEN": "YOUR_TOKEN" }
}
}
}
```
Step-by-step pages for each client are canonical on tapetide.com:
* Chat apps: [Claude.ai](https://tapetide.com/mcp/claude-ai), [ChatGPT](https://tapetide.com/mcp/chatgpt), [Grok](https://tapetide.com/mcp/grok), [Claude Desktop](https://tapetide.com/mcp/claude-desktop)
* Editors: [Cursor](https://tapetide.com/mcp/cursor), [VS Code](https://tapetide.com/mcp/vscode), [Windsurf](https://tapetide.com/mcp/windsurf), [Zed](https://tapetide.com/mcp/zed), [Kiro](https://tapetide.com/mcp/kiro), [Antigravity](https://tapetide.com/mcp/antigravity)
* Agents and CLIs: [Claude Code](https://tapetide.com/mcp/claude-code), [Codex](https://tapetide.com/mcp/codex), [Gemini CLI](https://tapetide.com/mcp/gemini-cli), [Cline](https://tapetide.com/mcp/cline), [OpenCode](https://tapetide.com/mcp/opencode), [Command Code](https://tapetide.com/mcp/commandcode)
Confirm the connection with a prompt such as “Use Tapetide to show Reliance’s latest price and when it was updated.” The answer should include a timestamp.
Full MCP tool reference: [tapetide.com/mcp/llms-full.txt](https://tapetide.com/mcp/llms-full.txt). For when to pick which, see [MCP vs API for Indian stock data](https://tapetide.com/mcp/guides/mcp-vs-api-indian-stock-data).
## Give your own agent the REST API
[Section titled “Give your own agent the REST API”](#give-your-own-agent-the-rest-api)
If you are building the agent, REST is usually simpler to control and test:
1. Load the OpenAPI document from `https://api.tapetide.com/v1/openapi.json` and turn operations into tools. Most agent frameworks accept OpenAPI directly.
2. Point the model at [`/llms.txt`](/llms.txt) or [`/llms-full.txt`](/llms-full.txt) for the conventions: units, nulls, paging.
3. Put the token in the HTTP client, never in the prompt.
4. Have the agent quote `meta.as_of` and any observation timestamp (`updated_at`, `snapshot_ts`) with numbers it reports.
A minimal tool for an agent loop:
```python
def tapetide_get(path: str, **params) -> dict:
"""GET a Tapetide API path such as /v1/stocks/TCS/quote. Returns the JSON body."""
r = session.get(f"https://api.tapetide.com{path}", params=params, timeout=30)
return r.json() # errors come back as {"error": {"code", "message"}} for the model to read
```
Returning error bodies to the model works well: messages name the bad parameter and list accepted values.
# Build a backtest with point-in-time data
> Assemble prices and fundamentals for a backtest without look-ahead bias, using Tapetide's availability dates and adjusted price series.
A backtest is only as honest as its inputs. The common failure is look-ahead: using a quarterly result on the day the quarter ended, weeks before the company published it. This guide builds a small daily panel of prices and trailing earnings for one stock where every value was public on its date.
## 1. Pull the full price history
[Section titled “1. Pull the full price history”](#1-pull-the-full-price-history)
Price history pages backwards with `end_date`. Each call serves up to 2,000 calendar days.
```python
import os, requests, pandas as pd
BASE = "https://api.tapetide.com/v1"
s = requests.Session()
s.headers["Authorization"] = f"Bearer {os.environ['TAPETIDE_TOKEN']}"
def price_history(symbol):
rows, end = [], None
while True:
params = {"days": 2000, **({"end_date": end} if end else {})}
body = s.get(f"{BASE}/stocks/{symbol}/price", params=params, timeout=60).json()
rows.extend(body["data"])
win = body["meta"]["window"]
if not win["has_more"]:
break
end = win["next_cursor"]
df = pd.DataFrame(rows).drop_duplicates("date")
df["date"] = pd.to_datetime(df["date"])
return df.sort_values("date").set_index("date")
px = price_history("TCS")
```
`close` is adjusted for splits and bonuses, so returns computed from it are continuous across corporate actions. It is not dividend-adjusted: add dividends separately if you need total return. `raw_close` is the unadjusted print, `null` where unavailable.
## 2. Pull fundamentals with their availability dates
[Section titled “2. Pull fundamentals with their availability dates”](#2-pull-fundamentals-with-their-availability-dates)
```python
fin = s.get(f"{BASE}/stocks/TCS/financials", params={"section": "quarterly"}, timeout=60).json()
q = fin["data"][0] if isinstance(fin["data"], list) else fin["data"]
eps = pd.Series(q["data"]["EPS in Rs"]) # {"Jun 2026": 36.9, ...}
avail = {a["period"]: a["available_from"] for a in q["availability"]}
eps_pit = pd.DataFrame({
"eps": eps,
"available_from": pd.to_datetime(pd.Series(avail)),
}).dropna().sort_values("available_from")
```
Each period’s `available_from` is the result-declaration date when `basis` is `reported`, or a regulatory-lag estimate when it is `estimated`. Treat estimated rows with care, or drop them, in sensitive tests.
## 3. Join on the date the data became public
[Section titled “3. Join on the date the data became public”](#3-join-on-the-date-the-data-became-public)
```python
eps_pit["ttm_eps"] = eps_pit["eps"].rolling(4).sum()
panel = pd.merge_asof(
px[["close"]].reset_index(),
eps_pit[["available_from", "ttm_eps"]].rename(columns={"available_from": "date"}),
on="date",
direction="backward", # only rows already published on each date
)
panel["pe"] = panel["close"] / panel["ttm_eps"]
```
`merge_asof(..., direction="backward")` gives each trading day the latest quarter that had been published by then, never one from the future.
## 4. Respect the trading calendar
[Section titled “4. Respect the trading calendar”](#4-respect-the-trading-calendar)
Use the holiday list rather than a weekday calendar. Exchanges sometimes open on weekends for special sessions and close on weekdays.
```python
holidays, url = [], "/v1/market/holidays?from=2015-01-01&limit=500"
while url:
body = s.get("https://api.tapetide.com" + url, timeout=30).json()
holidays += [h["date"] for h in body["data"]]
url = body["links"]["next"]
```
A trading date with no bar is not a zero return. Mask it, do not fill it with `0`.
## Caveats to state in your results
[Section titled “Caveats to state in your results”](#caveats-to-state-in-your-results)
* Statement values are the latest reported figures and can include restatements made after `available_from`.
* Today’s index constituents are not yesterday’s. Building a universe from a current index list adds survivorship bias.
* Prices are end-of-day. Intraday bars are not served by these routes.
Each call above costs one request unit. A full price history is a handful of calls; cache it locally rather than refetching per run.
# LLM-friendly docs
> llms.txt, llms-full.txt, Markdown twins and the raw OpenAPI document for feeding these docs to a model.
Everything on this site is available in plain text for models and tools.
| URL | What it is |
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`/llms.txt`](/llms.txt) | Index of every page with a one-line description, per [llmstxt.org](https://llmstxt.org/). |
| [`/llms-full.txt`](/llms-full.txt) | Every page concatenated as Markdown. Paste it into a context window. |
| [`/llms-small.txt`](/llms-small.txt) | A compact version with notes and examples trimmed. |
| `/.md` | A Markdown twin of any page: [`/quickstart.md`](/quickstart.md), [`/errors.md`](/errors.md), [`/api/operations/getstockquote.md`](/api/operations/getstockquote.md). |
| [`/openapi.json`](/openapi.json) | The OpenAPI 3.1 document this site was built from. The live copy is `https://api.tapetide.com/v1/openapi.json`. |
## Suggested use
[Section titled “Suggested use”](#suggested-use)
* **Coding assistant writing a client:** give it `/llms-full.txt` plus `/openapi.json`.
* **Agent at runtime:** keep `/llms.txt` in the system prompt and let it fetch the `.md` twin of the page it needs.
* **MCP users:** the MCP server’s own tool guide is at [tapetide.com/mcp/llms.txt](https://tapetide.com/mcp/llms.txt).
The site is rebuilt whenever the API’s OpenAPI document changes and once a day, so these files track production.
# Pull option chains
> Fetch index option chains, IV history and per-expiry analytics from the Tapetide API, and read the fields correctly.
Three routes cover options:
| Route | What it returns | Coverage |
| ------------------------------------- | --------------------------------------------------------------------------- | --------------------------------------------------------- |
| `GET /v1/options/{symbol}/chain` | Strike ladder with IV, Greeks, bid/ask, OI and volume | Index underlyings: NIFTY, BANKNIFTY, FINNIFTY, MIDCPNIFTY |
| `GET /v1/options/{symbol}/iv-history` | ATM IV, IV rank and percentile, realised vol, PCR, max pain, skew over time | About 556 underlyings including stocks |
| `GET /v1/stocks/{symbol}/options` | The same analytics per expiry for one underlying, latest snapshot | Stocks and indices with listed options |
## Fetch a chain
[Section titled “Fetch a chain”](#fetch-a-chain)
```bash
curl -s -H "Authorization: Bearer $TAPETIDE_TOKEN" \
"https://api.tapetide.com/v1/options/NIFTY/chain?strikes=10"
```
Omit `expiry` for the nearest one. `strikes` is the number of strikes each side of ATM. The response lists every expiry in `available_expiries`, so a second call can target a later one:
```bash
curl -s -H "Authorization: Bearer $TAPETIDE_TOKEN" \
"https://api.tapetide.com/v1/options/NIFTY/chain?expiry=2026-10-27&strikes=10"
```
Abridged response:
```json
{
"data": {
"underlying": "NIFTY",
"expiry_date": "2026-10-19",
"snapshot_ts": "2026-10-15 10:00:00+00",
"grain": "eod",
"spot": 22997.35,
"atm_strike": 23000,
"atm_iv_pct": 11.71,
"pcr": 1.65,
"max_pain_strike": 22900,
"lot_size": 65,
"ladder": [
{
"strike": 23000,
"atm_offset": 0,
"call": { "ltp": 91.85, "bid": 91.45, "ask": 91.85, "iv_pct": 8.05, "delta": 0.5496, "oi": 8564465, "iv_unsolved": false, "illiquid": false },
"put": { "ltp": 140, "bid": 139.3, "ask": 140, "iv_pct": 15.38, "delta": -0.4716, "oi": 5971355, "iv_unsolved": false, "illiquid": false }
}
]
}
}
```
## Read it correctly
[Section titled “Read it correctly”](#read-it-correctly)
* **It is a snapshot, not a stream.** Quote `snapshot_ts` with any number you take from the chain.
* **IV fields are percents.** `iv_pct: 8.05` means 8.05%. Do not multiply by 100.
* **Nulls mean unpublished.** `iv_unsolved: true` means IV and Greeks are `null` for that leg (common deep in the money). `illiquid: true` means no OI or volume, so the premium is indicative. Render these as missing, never as `0`.
* **`atm_offset`** is the signed distance in strikes from ATM, handy for selecting “ATM±2” without arithmetic on strike steps.
## IV history
[Section titled “IV history”](#iv-history)
```bash
curl -s -H "Authorization: Bearer $TAPETIDE_TOKEN" \
"https://api.tapetide.com/v1/options/RELIANCE/iv-history?range=1y"
```
`range` of `2y` and longer returns weekly bars: read `bar_interval` before counting points as sessions. `iv_rank_pct` (position in the trailing high-low band) and `iv_percentile_pct` (share of sessions below today) are different measures, both in percent.
Data is for information only and is not investment advice.
# Rate limits and quota
> Tapetide plan quotas, the per-minute burst cap, the headers that report them, and /v1/me/usage.
Two limits apply to every token. Both are shared between the REST API and the MCP server.
| Limit | Free plan | Paid plans | Error when reached |
| ---------- | -------------------------------------------------- | -------------------------------------------------------------------------- | --------------------- |
| Plan quota | 50 successful requests per IST day, no monthly cap | Higher daily and monthly caps, see [pricing](https://tapetide.com/pricing) | `429 quota_exhausted` |
| Burst cap | 60 requests per minute | 60 requests per minute | `429 rate_limited` |
* Only a `200` counts against the plan quota. Errors are refunded.
* Days and months reset on IST (Asia/Kolkata) boundaries: midnight IST and the first of the month IST.
* `/v1/me/usage` and `/v1/openapi.json` are free.
## Headers
[Section titled “Headers”](#headers)
| Header | On | Meaning |
| ------------------- | --------------------- | -------------------------------------------- |
| `X-RateLimit-Reset` | Every `200` and `429` | Unix seconds when the binding window resets. |
| `Retry-After` | Every `429` and `503` | Seconds to wait before retrying. |
## Check your position
[Section titled “Check your position”](#check-your-position)
```bash
curl -s -H "Authorization: Bearer $TAPETIDE_TOKEN" https://api.tapetide.com/v1/me/usage
```
```json
{
"data": {
"plan": "free",
"day": { "period": "2026-10-16", "used": 12, "limit": 50, "remaining": 38, "resets_at": "2026-10-16T18:30:00.000Z" },
"month": { "period": "2026-10", "used": 212, "limit": null, "remaining": null, "resets_at": "2026-10-31T18:30:00.000Z" }
},
"meta": { "as_of": "2026-10-16T06:01:12.418Z", "route": "getMyUsage" }
}
```
A `limit` of `null` means unlimited for that window.
## Spending fewer units
[Section titled “Spending fewer units”](#spending-fewer-units)
* Use `/v1/quotes?symbols=A,B,C` for up to 20 quotes in one unit.
* Ask for the widest page you need: `limit` up to the endpoint maximum, `days=2000` on price history.
* Cache reference data such as holidays and financial statements; they change on a schedule, not by the minute.
# Changelog
> Changes to the Tapetide API contract.
The API reference on this site is rebuilt from the live OpenAPI document, so it always matches production. This page records changes that affect clients.
## 2026-10
[Section titled “2026-10”](#2026-10)
* Developer docs launched at developers.tapetide.com, with a generated API reference, playground, `llms.txt` and Markdown twins.
* In preview: typed data endpoints with cursor pagination (`meta.next_cursor`, `links.next`), starting with `GET /v1/market/holidays`. They appear in the reference as they go live.
## 2026-09
[Section titled “2026-09”](#2026-09)
* REST API at `https://api.tapetide.com/v1`: stocks, market, indices, options and account routes, sharing the MCP token and quota.
* Parsed filings: `/v1/stocks/{symbol}/documents`, `/documents/summary`, `/documents/read`.
# API reference
Base URL: https://api.tapetide.com. OpenAPI: https://developers.tapetide.com/openapi.json
## GET /v1/stocks
operationId: searchStocks. Search stocks.
Search ~8,200 Indian stocks by name, symbol, BSE code or ISIN. Results are ranked exact-symbol > prefix > contains. Use this to find a symbol before calling the per-stock routes.
| Parameter | In | Required | Description |
|---|---|---|---|
| `q` | query | yes | Search text: a company name, symbol, BSE code or ISIN. |
| `sector` | query | no | Filter by sector, e.g. 'Information Technology'. |
| `industry` | query | no | Filter by industry, e.g. 'Private Bank'. |
| `limit` | query | no | Max results (default 10, max 50). |
Docs: https://developers.tapetide.com/api/operations/searchstocks/
## GET /v1/stocks/{symbol}
operationId: getStockProfile. Company profile.
Company overview: sector, about, pros/cons, fundamentals (PE, PB, market cap, ROE, ROCE, debt/equity), growth metrics and the current quote. Add `include` for technicals, analyst ratings or the peer table.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
| `include` | query | no | Comma-separated extra sections: technicals, ratings, peers. |
Docs: https://developers.tapetide.com/api/operations/getstockprofile/
## GET /v1/stocks/{symbol}/quote
operationId: getStockQuote. Latest quote.
Latest price quote: LTP, change, change %, volume, market cap, PE, PB, 52-week high/low.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
Docs: https://developers.tapetide.com/api/operations/getstockquote/
## GET /v1/stocks/{symbol}/financials
operationId: getFinancials. Financial statements.
Financial statements. `section` is one of quarterly (quarterly P&L), profit_loss, balance_sheet, cash_flow, ratios (all annual). Omit it for every section. Each section carries `periods` (oldest first), `data` {row: {period: value}}, `pct_changes`, `row_order` and an `availability` array with the point-in-time `available_from` date per period. Unlike the MCP tool, this route returns the FULL document: `periods` defaults to every period held, and nothing is trimmed to fit a context window. ETFs, index funds and bonds have no statements and return 404.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
| `section` | query | no | quarterly \| profit_loss \| balance_sheet \| cash_flow \| ratios. Accepted spellings include quarters, quarterly_results, income_statement, pnl, bs, cf. |
| `periods` | query | no | Latest N periods per section (max 40). Default: all periods held. Also accepted as: quarters. |
Docs: https://developers.tapetide.com/api/operations/getfinancials/
## GET /v1/stocks/{symbol}/price
operationId: getPriceHistory. Price history (OHLCV).
Row-per-day OHLCV with delivery %. `days` sets the lookback window (default 365, max 2000); `interval` is the bar size (daily or weekly). `meta.window` states the window actually served and `next_cursor` gives the `end_date` for the preceding page, so a multi-year series is paged with `end_date` until `has_more` is false.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
| `days` | query | no | Lookback window in calendar days (default 365, max 2000). |
| `interval` | query | no | Bar size: daily (default) or weekly. Intraday bars are not served here. |
| `end_date` | query | no | Inclusive YYYY-MM-DD upper bound; the paging cursor. Pass `meta.window.next_cursor` from the previous page. |
Docs: https://developers.tapetide.com/api/operations/getpricehistory/
## GET /v1/stocks/{symbol}/shareholding
operationId: getShareholding. Shareholding pattern.
Promoter, FII, DII, government and public holdings over time. Every period held is returned; there is no period-type filter (the handler serves the same document to MCP).
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
Docs: https://developers.tapetide.com/api/operations/getshareholding/
## GET /v1/stocks/{symbol}/forecasts
operationId: getForecasts. Analyst forecasts.
Analyst estimates vs actuals: EPS, revenue, EBITDA, net income, ROA, ROE and price targets, quarterly and annual.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
Docs: https://developers.tapetide.com/api/operations/getforecasts/
## GET /v1/stocks/{symbol}/events
operationId: getStockEvents. News, corporate actions or filings.
Stock events. `type` selects sentiment-tagged news (default), corporate actions (dividends, splits, bonuses, AGMs) or company filings (results, presentations, concall transcripts, annual reports, credit ratings, announcements).
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
| `type` | query | no | Event type (default news). |
| `limit` | query | no | Max results (default 20, max 50). |
Docs: https://developers.tapetide.com/api/operations/getstockevents/
## GET /v1/stocks/{symbol}/deals
operationId: getStockDeals. Bulk, block, insider and SAST deals.
Large-trade history with counterparty, side, quantity, price and value. Optionally filter to one deal type.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
| `type` | query | no | Deal type. Omit for all. |
| `limit` | query | no | Max deals (default 25, max 100). |
Docs: https://developers.tapetide.com/api/operations/getstockdeals/
## GET /v1/stocks/{symbol}/pledge
operationId: getPromoterPledge. Promoter share pledge.
Percentage of promoter holding pledged over recent quarters plus recent pledge creation/release events.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
Docs: https://developers.tapetide.com/api/operations/getpromoterpledge/
## GET /v1/stocks/{symbol}/ratings
operationId: getCreditRatings. Credit ratings.
Credit-rating actions: agency, rating, action (upgrade/downgrade/reaffirm) and outlook over time.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
Docs: https://developers.tapetide.com/api/operations/getcreditratings/
## GET /v1/stocks/{symbol}/options
operationId: getOptionsAnalytics. Options analytics per expiry.
Derivatives analytics for one underlying: ATM IV, IV rank/percentile, realised vol, put-call ratios, max pain, 25-delta skew and OI, per expiry.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
Docs: https://developers.tapetide.com/api/operations/getoptionsanalytics/
## GET /v1/stocks/{symbol}/earnings-calls
operationId: getEarningsCallSummary. Earnings call summaries.
AI-generated digests of recent earnings-call transcripts and investor presentations: summary, highlights, risks, guidance and headline metrics.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
| `limit` | query | no | Number of recent summaries (default 2, max 5). |
Docs: https://developers.tapetide.com/api/operations/getearningscallsummary/
## GET /v1/stocks/{symbol}/documents
operationId: listCompanyDocuments. List parsed filings.
Index of a company's filings parsed to text — concall transcripts, annual reports, investor presentations, IPO documents — with doc_id, type, period, date, page count, availability flags and public links to the PDF, full Markdown and summary. No prose. Newest first.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
| `doc_types` | query | no | Comma-separated document types to include (default: all). |
| `since` | query | no | Only filings dated on/after this date, YYYY-MM-DD. |
| `limit` | query | no | Max documents (default 20, max 50). |
Docs: https://developers.tapetide.com/api/operations/listcompanydocuments/
## GET /v1/stocks/{symbol}/documents/summary
operationId: getDocumentSummary. Document investor digest.
Investor digest of one parsed filing: summary (capped at 6,000 chars with a truncated flag), highlights, risks, guidance, key metrics, plus links to the PDF and full Markdown. Pass doc_id, or doc_type for the newest of that type.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
| `doc_id` | query | no | A doc_id from the documents index. |
| `doc_type` | query | no | Newest document of this type when doc_id is omitted. |
Docs: https://developers.tapetide.com/api/operations/getdocumentsummary/
## GET /v1/stocks/{symbol}/documents/read
operationId: readDocument. Read filing text by page range.
Markdown text of a parsed filing by doc_id and page range, with markers. At most 12 pages / 24,000 chars per call (max_chars up to 60,000); the response states pages_returned and next_pages and carries links to the full Markdown and PDF for local search.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
| `doc_id` | query | yes | A doc_id from the documents index. |
| `pages` | query | no | Inclusive 1-based range: "1-8", "12", "40-". Default "1-12". |
| `max_chars` | query | no | Character cap for this call (default 24,000). |
Docs: https://developers.tapetide.com/api/operations/readdocument/
## GET /v1/quotes
operationId: getBatchQuotes. Batch quotes.
Latest quotes for up to 20 symbols in one call. Over 20 is rejected with 400; nothing is dropped silently.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbols` | query | yes | Comma-separated symbols, max 20. |
Docs: https://developers.tapetide.com/api/operations/getbatchquotes/
## GET /v1/market/pulse
operationId: getMarketPulse. Market pulse.
Today's snapshot: FII/DII net flows, Nifty 50 valuations (PE/PB/DY) and the India VIX.
Docs: https://developers.tapetide.com/api/operations/getmarketpulse/
## GET /v1/market/fii-dii
operationId: getFiiDii. FII/DII institutional flows.
Daily cash-market flows for the last 30 sessions, F&O participant positioning, weekly/monthly/yearly aggregates, streaks and cumulative flows. Add `chart_interval` for the cumulative-flow series.
| Parameter | In | Required | Description |
|---|---|---|---|
| `chart_interval` | query | no | Include cumulative flow chart data for this interval. |
Docs: https://developers.tapetide.com/api/operations/getfiidii/
## GET /v1/market/vix
operationId: getIndiaVix. India VIX.
Latest India VIX, daily change and recent history.
Docs: https://developers.tapetide.com/api/operations/getindiavix/
## GET /v1/market/fpi-sectors
operationId: getFpiSectors. FPI sector flows.
Foreign portfolio investor sector-wise AUM share, fortnight change and 1-year cumulative flow.
Docs: https://developers.tapetide.com/api/operations/getfpisectors/
## GET /v1/market/news
operationId: getMarketNews. Market news.
Latest sentiment-tagged market-wide news with category and related symbols.
| Parameter | In | Required | Description |
|---|---|---|---|
| `limit` | query | no | Max results (default 20, max 50). |
| `category` | query | no | Category filter, e.g. global, markets, ipo, companies. |
| `sentiment` | query | no | Sentiment filter. |
Docs: https://developers.tapetide.com/api/operations/getmarketnews/
## GET /v1/market/valuations
operationId: getMarketValuations. Index valuations.
Index PE, PB and dividend yield over time. Default Nifty 50, 5 years.
| Parameter | In | Required | Description |
|---|---|---|---|
| `index` | query | no | nifty-50 \| nifty-500 \| nifty-bank \| nifty-midcap-50 \| nifty-it \| nifty-next-50 (default nifty-50). |
| `years` | query | no | Years of history (default 5, max 20). |
Docs: https://developers.tapetide.com/api/operations/getmarketvaluations/
## GET /v1/indices
operationId: getIndexPerformance. Rank indices by return.
Rank ~140 NSE indices by return over completed weeks or months using official closing levels. Use `category=sectoral` for sector rankings.
| Parameter | In | Required | Description |
|---|---|---|---|
| `periods` | query | no | Completed periods to measure (default 3). |
| `granularity` | query | no | Period length (default week). |
| `category` | query | no | Index family: sectoral, broad, thematic, strategy, ... |
| `names` | query | no | Explicit index names, comma-separated. Overrides category. |
| `limit` | query | no | Indices to return after ranking (default 10). |
| `order` | query | no | Sort direction (default gainers). |
Docs: https://developers.tapetide.com/api/operations/getindexperformance/
## GET /v1/indices/{name}/history
operationId: getIndexHistory. Index level history.
OHLC plus PE/PB/dividend-yield series for one NSE index (Nifty 50, Nifty Bank, Nifty IT, India VIX, ...). `interval` is the lookback window: 1m, 3m, 6m, 1y (daily bars) or 2y, max (weekly bars).
| Parameter | In | Required | Description |
|---|---|---|---|
| `name` | path | yes | Index display name, e.g. "Nifty 50", "Nifty IT", "India VIX". Matched case-insensitively. |
| `interval` | query | no | Lookback window (default 3m). |
Docs: https://developers.tapetide.com/api/operations/getindexhistory/
## GET /v1/options/{symbol}/chain
operationId: getOptionChain. Index option chain.
End-of-day stamped option chain for an index underlying (NIFTY, BANKNIFTY, FINNIFTY, MIDCPNIFTY): IV, Greeks, bid/ask and OI by strike. Read `snapshot_ts`; IV fields are percents.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
| `expiry` | query | no | Expiry as YYYY-MM-DD. Omit for the nearest expiry in the snapshot. |
| `strikes` | query | no | Strikes each side of ATM. |
Docs: https://developers.tapetide.com/api/operations/getoptionchain/
## GET /v1/options/{symbol}/iv-history
operationId: getOptionIvHistory. Option IV history.
Daily ATM IV, IV rank/percentile, realised vol, PCR, max pain and skew series for ~556 underlyings including stocks. Ranges of 2y and longer are weekly bars; read `bar_interval`.
| Parameter | In | Required | Description |
|---|---|---|---|
| `symbol` | path | yes | Stock or index symbol, e.g. "RELIANCE", "TCS", "NIFTY". Percent-encode symbols containing "&" (M%26M). |
| `range` | query | no | Lookback window (default 1y). |
Docs: https://developers.tapetide.com/api/operations/getoptionivhistory/
## GET /v1/me/usage
operationId: getMyUsage. Your quota position.
The caller's plan and current day/month usage against the counters every request is metered on. Free: this route never charges.
Docs: https://developers.tapetide.com/api/operations/getmyusage/