Skip to main content
Rate limits are enforced per user (shared across that user’s API keys) based on subscription level. Exceeding a limit returns 429 with RATE_LIMIT_EXCEEDED. As of API v2.5.0 there are two dimensions:
  1. Per-minute burst - short-window ceiling (headers X-RateLimit-*).
  2. Monthly request quota - UTC calendar-month budget (headers X-Quota-*). Sustained polling at the burst rate will exhaust the month early.
WebSocket sessions count against the concurrent connection cap only. They do not draw down the monthly REST quota.

Limits by level

The starter burst is 30/min rather than a rate matched to its monthly allowance: a single question in an AI client fires several tool calls in quick succession, and a tight burst cap would fail mid-answer. The monthly allowance is the number that defines the plan. Plan mapping notes (2.5.0):
  • Crypto API plans api_only_monthly / api_only_yearlystandard.
  • Terminal Yearly (yearly) includes starter API access.
  • Bundle api_monthly maps to pro (120/min). Legacy api is also treated as pro.
Get or upgrade access at backquant.com/api-access.

Response headers

Every authenticated REST response includes: The per-minute triple is also echoed in meta.rate_limit when present. GET /v2/meta returns the full per-level ladder under rate_limits.
X-RateLimit-Fallback: true means our rate-limit store was briefly unreachable and a stricter per-machine counter took over, so X-RateLimit-Limit will read lower than your plan’s normal cap. It is rare and self-healing, and the header is absent the rest of the time. If you surface your remaining budget to users, read the limit from the header rather than hardcoding your plan’s number, or it will look wrong during one of these windows.

What happens at the limit

  1. Burst or monthly exhaustion returns HTTP 429 with RATE_LIMIT_EXCEEDED. Monthly messages name the monthly cap.
  2. Respect Retry-After, but check X-Quota-Remaining first. On a burst 429 it is the seconds left in the minute. On a monthly 429 (X-Quota-Remaining: 0) it is the seconds until the month rolls over, so stop retrying and surface the message rather than sleeping on it.
  3. Do not spin-retry without backoff.

Auth vs entitlement

Clients that treat every 401 as “refresh credentials” must treat 403 as “upgrade / wrong plan,” not as a bad key. API access requires subscription status active. trialing grants the terminal but not the API until the trial converts.

Historical depth

Separate from request limits, your plan sets how far back history endpoints may reach. A request beyond your window is clamped, never rejected. You receive the data you are entitled to, plus a meta.extra.history_clamp block saying what was asked for and what was served:
Call GET /v2/meta to see the full ladder and, under your_plan, the window that applies to your own key.
Your window is what you may REQUEST, not a promise the data exists. Options history (used by as_of and the GEX endpoints) begins when ingestion did, and market series depth varies by interval: coarser intervals are stored for longer. GET /v2/meta publishes data_coverage alongside this ladder so you can size a backtest against both numbers, and a short market window is reported on the response as meta.extra.available_hours.
For existing paid plans the clamp is currently reported but not enforced: meta.history_depth_enforced is false and your request is served in full. Evaluation keys are the exception and are enforced today, so a trial reflects the plan being trialled. Check whether history_clamp appears in your traffic now, and you will know in advance whether enforcement affects you.

Strategy

Cache aggressively. Chain/GEX snapshots refresh ~30s server-side. Polling once per 30s per panel is enough. Use multi-symbol bundling. /v2/multi/gex/levels for several symbols counts as one request. Use composable ?include= / ?fields. Fewer round trips, lighter payloads. Prefer WebSocket for tape. Live prints over WS avoid burning monthly REST quota on /tape/recent polling.

See also

Errors

Meta

Authentication