Rate Limits
The Sharpe API enforces rate limits per API key to keep usage fair and the platform stable. Limits are applied as requests per minute and requests per month.
Current limits
Limits are enforced per key at one of four internal plan tiers. Every API key is currently issued on the Free tier. There are no paid plans today, and higher tiers are granted on request.
| Tier | Requests / min | Requests / month |
|---|---|---|
| Free | 30 | 10,000 |
| Analyst | 500 | 500,000 |
| Pro | 1,000 | 3,000,000 |
| Enterprise | 5,000 | 50,000,000 |
Need higher limits? Contact us. Higher-tier keys are granted on request.
Rate limit and quota headers
Every authenticated v1 API response includes headers so you can track per-minute rate limits and monthly quota usage in real time:
- Name
X-RateLimit-Limit- Type
- integer
- Description
Maximum requests allowed per minute for your tier.
- Name
X-RateLimit-Remaining- Type
- integer
- Description
Requests remaining in the current one-minute window.
- Name
X-RateLimit-Reset- Type
- integer
- Description
Unix timestamp (seconds) when the current window resets.
- Name
X-Quota-Limit- Type
- integer
- Description
Monthly request quota for your tier.
- Name
X-Quota-Remaining- Type
- integer
- Description
Monthly requests remaining in the current billing period.
- Name
X-Quota-Reset- Type
- string
- Description
ISO 8601 timestamp when the monthly quota resets. Included when the quota store returns a reset timestamp.
- Name
X-Request-Id- Type
- string
- Description
Unique identifier for this request. Include when contacting support.
Example response headers
HTTP/2 200
x-ratelimit-limit: 30
x-ratelimit-remaining: 27
x-ratelimit-reset: 1743062460
x-quota-limit: 10000
x-quota-remaining: 9812
x-quota-reset: 2026-04-01T00:00:00.000Z
x-request-id: req_abc123def456
429 Too Many Requests
Both limits return a 429: the per-minute rate limit with type rate_limit_exceeded, and the monthly quota with type monthly_quota_exceeded. Both are temporary and retryable, and both carry a Retry-After header with the seconds until the limit reopens.
The response body follows the standard RFC 9457 error format. The type and detail fields tell you whether you hit the per-minute rate limit or the monthly quota.
Response properties
- Name
type- Type
- string
- Description
rate_limit_exceededfor per-minute limits,monthly_quota_exceededfor monthly caps. Both return status429.
- Name
detail- Type
- string
- Description
Human-readable explanation of which limit was exceeded.
- Name
doc_url- Type
- string
- Description
Link to relevant documentation page for the error.
Quota exhaustion used to answer 403, which tells most HTTP clients and
agent frameworks never to retry. It is now a 429 so a key that will work
again at the next monthly reset is not permanently parked.
429 response body
{
"type": "https://www.sharpe.ai/errors/rate_limit_exceeded",
"title": "Rate Limit Exceeded",
"status": 429,
"detail": "Rate limit of 30 requests per minute exceeded.",
"request_id": "req_abc123def456",
"doc_url": "https://www.sharpe.ai/docs/rate-limits",
"suggested_action": "Wait until the time in the X-RateLimit-Reset header before retrying. Upgrade your plan for higher limits."
}
429 response headers
HTTP/2 429
x-ratelimit-limit: 30
x-ratelimit-remaining: 0
x-ratelimit-reset: 1743062472
x-quota-limit: 10000
x-quota-remaining: 9811
x-quota-reset: 2026-04-01T00:00:00.000Z
retry-after: 12
x-request-id: req_abc123def456
Monthly quota response body
{
"type": "https://www.sharpe.ai/errors/monthly_quota_exceeded",
"title": "Monthly Quota Exceeded",
"status": 429,
"detail": "Monthly quota of 10,000 requests exceeded. Resets at 2026-04-01T00:00:00.000Z.",
"request_id": "req_abc123def456",
"doc_url": "https://www.sharpe.ai/docs/rate-limits",
"suggested_action": "Retry after the seconds given in the Retry-After header, when the monthly quota resets. Upgrade your plan for a higher monthly quota. Check usage at GET /v1/usage."
}
Best practices
Monitor your usage
Read X-RateLimit-Remaining and X-Quota-Remaining on every authenticated v1 response. When either drops below 10% of its limit, slow down, queue requests, or move heavy jobs to the next reset window.
Implement backoff
When you receive a 429, use the Retry-After header when present, or fall back to X-RateLimit-Reset to calculate how long to wait before retrying. A monthly_quota_exceeded 429 sets Retry-After to the seconds until the quota resets, which can be days: queue the work rather than spinning on retries.
Backoff example
async function fetchWithRetry(url: string, headers: HeadersInit) {
const res = await fetch(url, { headers })
if (res.status === 429) {
const retryAfter = parseInt(res.headers.get('Retry-After') ?? '0', 10)
const reset = parseInt(res.headers.get('X-RateLimit-Reset') ?? '0', 10)
const waitMs = retryAfter > 0
? retryAfter * 1000
: Math.max(reset * 1000 - Date.now(), 1000)
await new Promise((resolve) => setTimeout(resolve, waitMs))
return fetch(url, { headers })
}
return res
}
Cache responses
Many Sharpe API endpoints return data that updates on a known schedule (for example, current funding rates refresh every 5 minutes, while heatmap data refreshes every 2 hours). Cache responses locally and respect Cache-Control headers to avoid redundant requests.
Use conditional requests
The current funding book (/api/funding/rates?type=current) is served from a snapshot with a weak ETag. Send the last value back as If-None-Match and an unchanged book returns 304 Not Modified with an empty body. A 304 still counts against the per-IP protective limits on free endpoints, so conditional polling saves bandwidth, not request budget.
Use bulk endpoints
Prefer endpoints that return data for multiple symbols in a single request rather than making one request per symbol. For example, /v1/funding/rates?type=current without a coin parameter returns all rates at once.