Skip to main content

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 TierRead RequestsResume Parser IngestConcurrency Cap
Starter60 req / min10 resumes / min5 parallel connections
Professional300 req / min60 resumes / min25 parallel connections
Enterprise / Custom2,500+ req / min500+ resumes / min100+ parallel connections

Need elevated rate limits for high-volume migration? Contact our enterprise team at +44 7471 530754 or email [email protected].


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 -I -X GET "https://api.xecubes.com/recruiter/bootstrap" \
-H "X-API-Key: xh_live_your_secret_key"

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.');
}