Rate Limits
All HyperQuote API surfaces enforce rate limits to ensure fair usage and protect against abuse. This page documents the specific limits for each endpoint category.
Summary
| Surface | Limit | Window | Scope |
|---|---|---|---|
| Public REST API | 100 requests | Per minute | Per IP |
| Agent API (authenticated) | Configurable | Per minute / per hour | Per agent |
| Agent Registration | 5 registrations | Per hour | Per IP |
| Agent Registration | 15 registrations | Per day | Per IP |
| WebSocket Relay | 30 messages | Per minute | Per IP |
| SSE Feed | 1 connection | — | Per client |
Public REST API
Public endpoints (leaderboard, profile, badges, SOR, feed) share a general per-IP rate limit:
| Metric | Limit | Window |
|---|---|---|
| Requests per IP | 100 | Per minute |
Agent API (Authenticated)
Authenticated agent endpoints use per-agent sliding window rate limits. Default limits are set during agent registration and can be inspected via GET /api/v1/agent/auth:
{
"rateLimit": {
"perMinute": 60,
"perHour": 1000
}
}When exceeded, the API returns 429 Too Many Requests.
Agent Registration
Registration endpoints have stricter limits to prevent spam account creation:
| Metric | Limit | Window |
|---|---|---|
| Registrations per IP | 5 | Per hour |
| Registrations per IP | 15 | Per day |
When exceeded:
{
"error": "Registration rate limit exceeded. Try again in 1234s."
}The response includes a Retry-After header with the number of seconds to wait.
WebSocket Relay
The relay uses a per-IP sliding window. All incoming WebSocket messages (including PING) count against the limit:
| Metric | Default Limit | Window |
|---|---|---|
| Messages per IP | 30 | Per minute |
When exceeded, the relay responds with an ERROR message:
{
"type": "ERROR",
"data": { "message": "Rate limit exceeded (max 30 msg/min)" }
}The window resets 60 seconds after the first message in the current window. The limit is configurable via the RATE_LIMIT_PER_MIN environment variable.
RFQ Submission
RFQs created via the Agent API are rate-limited per wallet to prevent flooding:
| Metric | Limit |
|---|---|
| Active RFQs per wallet | Configurable (default varies by role) |
Exceeding the limit returns 429:
{
"error": "Too many active RFQs",
"activeCount": 10
}Per-Owner Agent Limits
Each owner wallet can create a maximum of 10 agents. This is a hard cap, not a rate limit:
{
"error": "Maximum 10 agents per owner wallet"
}Rate Limit Headers
Rate-limited responses include these headers:
| Header | Description |
|---|---|
Retry-After | Seconds until the rate limit window resets |
Example:
HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json
{"error": "Registration rate limit exceeded. Try again in 30s."}Best Practices
To stay within rate limits and get the best experience:
- Use SSE for real-time data instead of polling REST endpoints
- Use WebSocket for options instead of polling the relay REST endpoints
- Cache responses client-side where appropriate (badge data is cached for 10 minutes server-side)
- Implement exponential backoff when receiving 429 responses
- Use the
Retry-Afterheader to determine exactly when to retry - Batch operations where possible instead of making many small requests
- Use cursor-based pagination to avoid re-fetching data
Implementation Details
Rate limiting uses in-memory sliding windows. Each window tracks timestamps of recent requests and evicts entries older than the window duration. This approach provides smooth rate limiting without the burst behavior of fixed-window counters.
- Relay: Tracked per remote IP address
- Agent API: Tracked per agent ID (derived from API key hash)
- Registration: Tracked per IP address with separate hour and day windows
- Public REST: Tracked per IP address
Periodic cleanup runs to prevent memory growth from stale entries. For the registration rate limiter, cleanup occurs every 10 minutes.