Rate limits
Per-key limits for REST and WebSocket, the usage headers on every response, and what happens when you hit a limit.
The numbers
| Limit | All plans | Type |
|---|---|---|
| Sustained rate (REST) | 2 req/sec | Hard |
| Burst (REST) | Bursts up to 10 requests, then 2/sec | Hard |
| Daily allowance | Governed by credits — see Credits below | Hard |
| Concurrent WS connections | 5 per key | Hard |
| Historical depth | Every event since coverage began · growing weekly | Hard |
| Concurrent in-flight HTTP | 10 | Soft |
For context: a client polling /pm/v2/newsevery 15 seconds uses about 5,760 calls a day (comfortably inside the quota), and if you're on the WebSocket, you don't need to poll at all. If your use case genuinely needs more, talk to us.
Retry-After and a warning email at 80% utilisation. Hard limits return 429 immediately and stay in 429 until the window resets. These protective limits apply to every plan — credits, not rate, are what differ by plan.Headers on every response
Every REST response carries rate-limit state. Your client can back off without parsing the body.
HTTP/1.1 200 OK Content-Type: application/json X-Vera-Tier: standard X-Vera-RPS-Limit: 2 X-Vera-Burst-Limit: 10 X-Vera-Burst-Remaining: 9 X-Request-Id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
Quota headers (X-Vera-Quota-Remaining-Day, X-Vera-Quota-Remaining-Minute) appear only when your daily quota is close to exhaustion, not on every response.
What 429 looks like
There are two kinds of 429 with different bodies. Check the status code, then the body, to tell them apart.
Protective rate limit — a flat object; type tells you which limit fired. Never billed; just slow down and retry. Retry-After is usually a fraction of a second for burst:
HTTP/1.1 429 Too Many Requests Retry-After: 0.18 Content-Type: application/json { "type": "per_second_burst", "limit": "burst capacity exceeded (10 req/s burst, 2 req/s sustained)", "message": "Rate limit exceeded: burst capacity exceeded (10 req/s burst, 2 req/s sustained). Please retry after 0.18s.", "request_id": "req_8jJw3Fk1pQzN", "documentation_url": "https://vera.cryptobriefing.com/docs/rate-limits" }
type is one of per_second_burst, per_minute, or per_day.
Credit exhaustion— you're out of allowance/wallet. A distinct body nested under detail and keyed by code, carrying the reset time and remaining wallet:
HTTP/1.1 429 Too Many Requests Content-Type: application/json { "detail": { "code": "credit_quota_exhausted", "message": "Credit allowance exhausted for this period.", "resets_at": "2026-07-17T00:00:00+00:00", "wallet_balance": 0, "pricing_url": "https://vera.cryptobriefing.com/#pricing" } }
Backoff strategy
Always honour Retry-After. If it's missing (it shouldn't be, but just in case), back off with exponential jitter starting at 1 second. The reference clients in Quickstart already implement this pattern.
import time, random, httpx def get_with_backoff(client: httpx.Client, url: str, params: dict | None = None): for attempt in range(5): resp = client.get(url, params=params) if resp.status_code != 429: return resp # Retry-After can be fractional (e.g. "0.18" for a burst hit) — parse as # float, not int, or fractional values raise ValueError. retry_after = float(resp.headers.get("Retry-After", 0)) if retry_after > 0: time.sleep(retry_after) else: time.sleep((2 ** attempt) + random.random()) resp.raise_for_status()
Warning emails
We email the subscription owner (and any team members on a future team plan) at these milestones:
- 80% of your daily credit allowance consumed
- 100% consumed — further billable calls return
429 credit_quota_exhausteduntil the UTC-midnight reset - 3+ rate-limit responses within 60 seconds (suggests a misconfigured client)
Asking for more
Need higher caps? Email vera@cryptobriefing.com with what you're building. Enterprise plans lift these limits — tell us your use case and we'll quote you against the actual numbers you need.
Credits
Access is metered in credits. One successful (2xx) response on a billable data route costs one credit; requests that fail auth, get rate-limited, error out, or hit a non-billable route cost nothing.
Credits are drawn from your plan's allowance first, then from any prepaid wallet:
- Free — a daily allowance of real-time calls (shown in your dashboard) that resets at 00:00 UTC and does not roll over.
- Builder — a one-time pack adds prepaid wallet credits that never expire and cover usage beyond the daily allowance.
- Pro — a monthly REST-credit allowance for queries and backfill, with WebSocket streaming as the real-time channel.
When your available credits are exhausted, billable requests return 429 credit_quota_exhausted (with the reset time and wallet balance in the body) until the allowance resets or you add credits. Rate limits (burst / RPM) are separate protective limits and are never billed.
Kalshi coverage
Kalshi is on the roadmap for a forthcoming Multi-Venue add-on. We'll share coverage and upgrade details when it ships.