Rate Limits
API requests are rate-limited per tenant based on your plan tier. Rate limits protect the platform and ensure fair usage across all tenants.
Per-tier limits
| Tier | Requests/min | Requests/hour | Monthly verifications |
|---|---|---|---|
| Basic | 10 | 300 | 1,000 |
| Professional | 50 | 1,500 | 10,000 |
| Enterprise | 200 | 6,000 | Unlimited |
Rate limit headers
Every API response includes rate limit headers:
| Header | Description | Example |
|---|---|---|
X-RateLimit-Limit | Maximum requests per minute for your tier | 50 |
X-RateLimit-Remaining | Requests remaining in the current window | 47 |
X-RateLimit-Reset | Unix timestamp when the current window resets | 1705312800 |
Example response headers:
HTTP/1.1 200 OK
X-RateLimit-Limit: 50
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1705312800
Handling 429 responses
When you exceed your rate limit, the API returns a 429 Too Many Requests response:
{
"code": "RATE_LIMIT_EXCEEDED",
"error": "Rate limit exceeded. Please retry after the reset time.",
"details": {
"retryAfter": 30
}
}
The response includes a Retry-After header with the number of seconds to wait.
Exponential backoff
Implement exponential backoff for rate-limited requests:
- Node.js
- Python
- Go
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get("Retry-After") || "1");
const delay = retryAfter * 1000 * Math.pow(2, attempt);
await new Promise((resolve) => setTimeout(resolve, delay));
continue;
}
return response;
}
throw new Error("Max retries exceeded");
}
import time
import requests
def fetch_with_retry(url, headers, max_retries=3):
for attempt in range(max_retries):
response = requests.get(url, headers=headers)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 1))
delay = retry_after * (2 ** attempt)
time.sleep(delay)
continue
return response
raise Exception("Max retries exceeded")
func fetchWithRetry(url string, maxRetries int) (*http.Response, error) {
for attempt := 0; attempt < maxRetries; attempt++ {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
if resp.StatusCode == 429 {
retryAfter, _ := strconv.Atoi(resp.Header.Get("Retry-After"))
if retryAfter == 0 {
retryAfter = 1
}
delay := time.Duration(retryAfter) * time.Second * time.Duration(1<<attempt)
time.Sleep(delay)
continue
}
return resp, nil
}
return nil, fmt.Errorf("max retries exceeded")
}
Best practices
- Monitor remaining requests — Check
X-RateLimit-Remainingto proactively slow down before hitting the limit - Batch where possible — Create verifications in batches rather than rapid-fire individual requests
- Cache responses — Cache
GETresponses (verification status, document types) to avoid unnecessary API calls - Use webhooks — Instead of polling
GET /verifications/{id}for status updates, use webhooks to receive results asynchronously - Contact us for higher limits — If you need higher rate limits, contact your account manager or reach out to support@korastratum.com