Rate Limits
API rate limits are enforced per API key based on your subscription tier.
Tiers
| Tier | Requests/min | Description |
|---|---|---|
| Standard | 100 | Default for all accounts |
| Professional | 1,000 | Higher-volume integrations |
| Enterprise | 10,000 | Custom limits available |
Rate Limit Headers
Every API response includes rate limit information:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests per minute for your tier |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the limit resets |
Example headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1717243260
429 Response
When the rate limit is exceeded, the API returns HTTP 429:
{
"code": "RATE_LIMITED",
"message": "Rate limit exceeded",
"request_id": "req_abc123"
}
Handling Rate Limits
Exponential Backoff
- Node.js
- Python
- Go
async function requestWithBackoff(url, options, maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429) {
return response;
}
const resetTimestamp = response.headers.get("X-RateLimit-Reset");
let waitMs;
if (resetTimestamp) {
waitMs = parseInt(resetTimestamp) * 1000 - Date.now();
} else {
waitMs = Math.min(1000 * Math.pow(2, attempt), 30000);
}
await new Promise((resolve) => setTimeout(resolve, Math.max(waitMs, 100)));
}
throw new Error("Rate limit exceeded after max retries");
}
import time
def request_with_backoff(url, headers, json_data, max_retries=5):
for attempt in range(max_retries):
response = requests.post(url, headers=headers, json=json_data)
if response.status_code != 429:
return response
reset_timestamp = response.headers.get("X-RateLimit-Reset")
if reset_timestamp:
wait_seconds = int(reset_timestamp) - time.time()
else:
wait_seconds = min(2 ** attempt, 30)
time.sleep(max(wait_seconds, 0.1))
raise Exception("Rate limit exceeded after max retries")
func requestWithBackoff(req *http.Request, maxRetries int) (*http.Response, error) {
for attempt := 0; attempt < maxRetries; attempt++ {
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusTooManyRequests {
return resp, nil
}
resp.Body.Close()
resetHeader := resp.Header.Get("X-RateLimit-Reset")
var waitDuration time.Duration
if resetHeader != "" {
resetTime, _ := strconv.ParseInt(resetHeader, 10, 64)
waitDuration = time.Until(time.Unix(resetTime, 0))
} else {
waitDuration = time.Duration(math.Pow(2, float64(attempt))) * time.Second
if waitDuration > 30*time.Second {
waitDuration = 30 * time.Second
}
}
time.Sleep(waitDuration)
}
return nil, fmt.Errorf("rate limit exceeded after %d retries", maxRetries)
}
Best Practices
- Check remaining quota — Monitor
X-RateLimit-Remainingto proactively slow down before hitting the limit - Use batch endpoints —
POST /v1/screenings/batchprocesses multiple subjects in one request, counting as a single API call - Use async mode — Async screenings don't block while processing, letting you submit more requests
- Cache results — Store screening results to avoid re-screening unchanged subjects
- Distribute requests — Spread requests evenly across the rate window rather than bursting
Upgrading Your Tier
To upgrade from Standard to Professional or Enterprise:
- Log in to app.korastratum.com
- Navigate to Settings → Billing
- Select your desired plan
For Enterprise custom limits, contact sales.