API  /  Rate limits

Rate limits

Per-minute and per-day caps depend on your add-on tier. Both are rolling-window enforced server-side. When you cross a cap, you get HTTP 429 with a Retry-After header. This page is the contract; reference has a one-table summary.

Tier caps

TierPer minutePer dayBurst tolerance
Pro API6050,000None — rolling 60s window
Trader API300unlimitedNone — rolling 60s window

Caps reset at the boundary, not on a fixed timer. If you make 60 calls in a 30-second burst, you'll need to wait the remaining 30 seconds before any request succeeds.

The 429 response

When you cross a cap, you get a JSON body and a numeric Retry-After header:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 23

{
  "detail": "Rate limit exceeded. Try again in 23 seconds."
}

Retry-After is the number of seconds until your earliest queued request will succeed. Always honor it — if you ignore the header and keep hammering, repeated 429s extend the lockout window.

Polling guidance

The underlying chain refreshes every ~1 second for 0DTE during market hours and ~110 seconds for non-0DTE. Polling faster than that wastes rate limit without giving you fresher data.

Practical recommendations:

Backoff on 429

Honor the Retry-After header. If the header is missing for any reason, fall back to exponential backoff starting at 2 seconds, doubling, capped at 60 seconds.

import os, time, requests

KEY = os.environ["GEXBOARD_API_KEY"]

def get_with_retry(url, params=None, max_attempts=5):
    for attempt in range(max_attempts):
        r = requests.get(url, params=params, timeout=10,
            headers={"Authorization": f"Bearer {KEY}"})
        if r.status_code == 429:
            wait = int(r.headers.get("Retry-After", 2 ** attempt))
            time.sleep(min(wait, 60))
            continue
        r.raise_for_status()
        return r.json()
    raise RuntimeError("Rate limit not clearing after 5 attempts")
# Honor Retry-After then retry once
RESP=$(curl -sw "\n%{http_code}\n%header{Retry-After}" \
  -H "Authorization: Bearer $GEXBOARD_API_KEY" \
  "https://gexboard.com/api/v1/radar?ticker=SPY")
CODE=$(echo "$RESP" | tail -2 | head -1)
RETRY=$(echo "$RESP" | tail -1)

if [ "$CODE" = "429" ]; then
  sleep "${RETRY:-2}"
  curl -H "Authorization: Bearer $GEXBOARD_API_KEY" \
    "https://gexboard.com/api/v1/radar?ticker=SPY"
fi

Daily cap (Pro tier)

Pro keys hit a separate 50,000 requests / day cap measured in UTC. The day rolls over at 00:00 UTC. If you exhaust the daily cap, you'll get 429s with a Retry-After in the seconds-until-midnight-UTC range — back off to a long sleep or pause until next day.

Trader has no daily cap (unlimited daily) so you only need to handle the 60-second window.

Suspension

Repeated abuse — ignoring Retry-After, distributed key sharing across IPs, sustained 429-loops — can trigger automatic key suspension per API Terms § 5. We email the account address before suspending where feasible. To rotate a compromised key: /accountRegenerate.

Need higher limits?

Trader API at 300 req/min covers most quant workflows. If your use case genuinely needs more (high-frequency scanning, multi-tenant research platform, distributed agent system), Enterprise quotes are available: contact@gexboard.com. We respond within 24 business hours.