Rate Limits & Error Handling
To ensure consistent performance and protect our multi-tenant infrastructure against abuse, the XeCubes API enforces rate limits on all incoming requests.
Tier Quotas​
Limits are evaluated based on your organization tier:
| Plan Tier | Read Requests | Resume Parser Ingest | Concurrency Cap |
|---|---|---|---|
| Starter | 60 req / min | 10 resumes / min | 5 parallel connections |
| Professional | 300 req / min | 60 resumes / min | 25 parallel connections |
| Enterprise / Custom | 2,500+ req / min | 500+ resumes / min | 100+ parallel connections |
Need elevated rate limits for high-volume migration? Contact our enterprise team at +44 7471 530754 or email
contact@xecubes.com.
Rate Limit Headers​
Every HTTP response includes standard rate limit headers indicating your remaining quota:
HTTP/1.1 200 OK
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 284
X-RateLimit-Reset: 1717588800
X-RateLimit-Limit: Maximum requests permitted within the current time window.X-RateLimit-Remaining: Number of requests remaining in the active window.X-RateLimit-Reset: Unix epoch timestamp (in seconds) when the current window resets.
Inspecting Limits via Code​
- cURL
- Node.js
- Python
curl -I -X GET "https://api.xecubes.com/recruiter/bootstrap" \
-H "X-API-Key: xh_live_your_secret_key"
const res = await fetch('https://api.xecubes.com/recruiter/bootstrap', {
method: 'HEAD',
headers: {
'X-API-Key': 'xh_live_your_secret_key'
}
});
console.log('Limit:', res.headers.get('X-RateLimit-Limit'));
console.log('Remaining:', res.headers.get('X-RateLimit-Remaining'));
console.log('Reset Time:', res.headers.get('X-RateLimit-Reset'));
import requests
response = requests.head(
"https://api.xecubes.com/recruiter/bootstrap",
headers={"X-API-Key": "xh_live_your_secret_key"}
)
print("Limit:", response.headers.get('X-RateLimit-Limit'))
print("Remaining:", response.headers.get('X-RateLimit-Remaining'))
Handling HTTP 429 Too Many Requests​
If you exceed your quota, the API will reject requests with 429 Too Many Requests and provide a Retry-After header specifying how many seconds to wait:
{
"status": "error",
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Quota exceeded for your organization tier.",
"retry_after_seconds": 12
}
Exponential Backoff & Jitter Implementation​
async function fetchWithRetry(url: string, options: RequestInit, maxRetries = 4) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429) {
return response;
}
const retryAfter = parseInt(response.headers.get('Retry-After') || '1', 10);
const jitter = Math.random() * 500;
const waitTime = (retryAfter * 1000) + (Math.pow(2, attempt) * 200) + jitter;
console.warn(`Rate limited. Waiting ${Math.round(waitTime)}ms before retry ${attempt + 1}...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
}
throw new Error('Max retries exceeded due to rate limiting.');
}