Skip to content

Pagination

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.

Collection endpoints return an array in data, paging fields in meta, and a ready-made next URL in links:

{
"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.
  • 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.
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))
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;
}

/v1/stocks/{symbol}/price serves at most 2,000 calendar days per call. It reports the window it actually served in meta.window:

"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.

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.