Rate Limits & Plans
Limits are enforced per API key across both the REST API and WebSocket connections. Each plan has a per-second burst limit, a monthly request quota, and WebSocket connection/subscription caps.
Plan Limits
Need more? View all plan details or email api@predictionhunt.com for enterprise pricing.
WebSocket Limits
WebSocket connections enforce separate limits for concurrent connections, subscriptions, and channel access. These are independent of REST API quotas.
| Limit | Free | Dev | Pro | Enterprise |
|---|---|---|---|---|
| Max concurrent connections per API key | None | 3 | 10 | 50 |
| Max subscriptions per connection | None | 50 | 200 | 1000 |
| Max subscriptions per channel | None | 25 | 100 | 500 |
| Channel access | None | prices, smart_money, fade_finder | All | All |
Inbound message rate
WebSocket error codes
SUBSCRIPTION_LIMITSubscription cap reached for this connection or channel.CHANNEL_FORBIDDENYour tier cannot access this channel.CONNECTION_LIMITToo many concurrent WebSocket connections for your API key.RATE_LIMITEDInbound message rate exceeded.Rate Limit Headers
Successful authenticated requests include rate-limit headers on the response. There are two layers: global (per-second burst and monthly total for your key) and endpoint-group (extra monthly quotas for specific route families, e.g. matching and signals).
Global (every request)
X-RateLimit-Limit-SecondYour plan's maximum requests allowed in the current UTC second (burst / RPS cap).X-RateLimit-Remaining-SecondHow many requests you can still make in the current UTC second before hitting the burst limit.X-RateLimit-Limit-MonthYour plan’s total request quota for the current UTC calendar month.X-RateLimit-Remaining-MonthRequests remaining this month against the global monthly quota, after this request is counted.Endpoint-group (selected routes)
Some paths belong to a monthly group (matched markets, arbitrage, expected value). When the route applies, the response also includes a limit and remaining pair for each relevant group.
X-RateLimit-Limit-Matched-Markets-MonthMonthly cap for the matched-markets group (e.g. matching-markets, events, search).X-RateLimit-Remaining-Matched-Markets-MonthRemaining monthly quota for that group (decrements when the response JSON has success: true).X-RateLimit-Limit-Arb-MonthMonthly cap for arbitrage signal requests (paid tiers).X-RateLimit-Remaining-Arb-MonthRemaining arbitrage quota for the month.X-RateLimit-Limit-Ev-MonthMonthly cap for expected-value signal requests (paid tiers).X-RateLimit-Remaining-Ev-MonthRemaining EV quota for the month.Group counters advance only when the response JSON has success: true. The global monthly header still reflects usage after each completed handler response. Enterprise keys may omit per-group headers when no group limits apply to the tier.
429 responses
Retry-AfterIncluded on 429 Too Many Requests. Value is seconds to wait before retrying (for example 1 when the per-second burst is exceeded, or longer for monthly or group limits). On 429, the response also repeats the relevant X-RateLimit-* headers with remaining values set to 0 where applicable.Handling 429 Too Many Requests
When you exceed the burst limit, the API returns a 429 with a Retry-After header. Use exponential backoff to respect this limit:
import time, requests
def call_with_backoff(url, headers, max_retries=5):
for attempt in range(max_retries):
resp = requests.get(url, headers=headers)
if resp.status_code == 429:
wait = int(resp.headers.get("Retry-After", 2 ** attempt))
time.sleep(wait)
continue
resp.raise_for_status()
return resp.json()
raise Exception("Max retries exceeded")Upgrade Your Plan
Hitting your limits? Upgrade on the pricing page — changes take effect immediately.
View Plans & Pricing