DevelopersDocsConcepts

Rate limits

Trust tiers T0 to T3, requests a second and daily spend limits, the RateLimit headers on every response, and how to back off when you get a 429.

Two limits apply to a live key: how many requests a second, and how many rupees a day. Both rise as the account earns trust. A test key has 50 requests a second and no spend, because it spends nothing.

#Trust tiers

Every account sits in a tier. It moves up on its own as you pay and as the account ages.

T02 requests a second₹100 a dayfree, never paidT15 requests a second₹10,000 a daypaid once, or KYC savedT220 requests a second₹50,000 a day₹10,000 paid, 7 days oldT3100 requests a second₹5,00,000 a day₹1,00,000 paid, 30 days old
Trust tiers
Tier Who Requests a second Spend a day
T0 Free, never paid, no KYC 2 ₹100
T1 Paid once (a top-up or a plan), or KYC saved 5 ₹10,000
T2 At least ₹10,000 paid in all, and the account is 7 days old 20 ₹50,000
T3 At least ₹1,00,000 paid, and the account is 30 days old 100 ₹5,00,000
  • A paid plan sets a floor: Build is never below 25 requests a second, Growth never below 100.
  • Enterprise and partner accounts have limits set by the platform admin.
  • KYC means saving the firm's PAN or GSTIN in the firm settings.
  • Your tier is in GET /account as tier, with your limits under limits. See authentication.

A call that would take the day's spend over the limit is refused before it runs, with 402 and the code daily_spend_cap. It is free. The limit resets at midnight IST.

#The headers

Every response carries three rate-limit headers, success or error:

Header Meaning
RateLimit-Limit Requests a second your key may make.
RateLimit-Remaining Requests left in the current second.
RateLimit-Reset Seconds until the window resets.
RateLimit-Limit: 5
RateLimit-Remaining: 0
RateLimit-Reset: 1

#When you get a 429

Over the limit, the API returns 429 with the error type rate_limited and the code rate_limited, plus a Retry-After header in seconds. A 429 is never billed and the request did not run. (A different 429, with the code too_many_reports, means 100 reports are already being made; see reports.)

  1. Stop sending on that key.
  2. Wait RateLimit-Reset seconds, plus a little random jitter.
  3. Send again with the same Idempotency-Key if it was a POST, so a retry that did run cannot run twice. See idempotency.
  4. If you hit it often, spread calls out (a queue with a fixed rate does this) or move up a tier.
async function call(url: string, init: RequestInit, tries = 5): Promise<Response> {
  for (let i = 0; i < tries; i++) {
    const res = await fetch(url, init);
    if (res.status !== 429 && res.status !== 503) return res;
    const wait = Number(res.headers.get("RateLimit-Reset") ?? 1) * 1000;
    await new Promise((r) => setTimeout(r, wait * 2 ** i + Math.random() * 250));
  }
  throw new Error("still limited after retries");
}
import random, time, requests

def call(method, url, tries=5, **kw):
    for i in range(tries):
        res = requests.request(method, url, timeout=30, **kw)
        if res.status_code not in (429, 503):
            return res
        wait = float(res.headers.get("RateLimit-Reset", 1))
        time.sleep(wait * 2**i + random.random() * 0.25)
    raise RuntimeError("still limited after retries")

Retry 429 and 503 only. A 400, 401, 402, 403 or 404 will fail again the same way; read its doc_url instead.

#Staying under the limit

  • Ask for a list once and keep it, instead of one call per row.
  • Use POST /cause-lists/match to check many CNRs against a cause list in one call.
  • Use a watch and a webhook instead of polling a case. A poll that finds nothing still counts against your limit.
  • Cache case details yourself. GET /cases/{cnr} is already cached for up to 24 hours on our side.