Rate limiting
The Qudra Partner API enforces a per-minute rate limit per API key. Limits scale with your plan.
Limits by plan
| Plan | Requests / minute | Monthly job quota | Bulk endpoint | Webhooks | |---------|-------------------|-------------------|---------------|----------| | Free | 100 | 100 | — | — | | Growth | 1,000 | 1,000 | ✓ (100/req) | ✓ | | Scale | 10,000 | Unlimited | ✓ (100/req) | ✓ |
Response headers
Every response includes three headers so you can plan your traffic shaping without hitting limits blindly:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 873
X-RateLimit-Reset: 1747700400| Field | Type | Description |
|---|---|---|
| X-RateLimit-Limit | integer | Total requests allowed in the current minute window. |
| X-RateLimit-Remaining | integer | Requests left in the current window. |
| X-RateLimit-Reset | integer | Unix timestamp (seconds) when the window resets. |
Hitting the limit
When you exceed the limit, the API responds with 429 partner.rate_limit and a Retry-After header (in seconds):
HTTP/1.1 429 Too Many Requests
Retry-After: 17
Content-Type: application/json
{
"error": {
"code": "partner.rate_limit",
"message": "Rate limit exceeded. Try again in 17 seconds.",
"messageAr": "تم تجاوز حد الطلبات. أعد المحاولة بعد 17 ثانية.",
"request_id": "req_01HXY…"
}
}Honor Retry-After
Always respect Retry-After instead of busy-looping. Our SDKs do this automatically with exponential backoff and jitter.
Backoff strategy
We recommend exponential backoff with full jitter, capped at 60 seconds:
async function withRetry<T>(fn: () => Promise<T>, max = 5): Promise<T> {
for (let attempt = 0; attempt < max; attempt++) {
try {
return await fn();
} catch (e) {
if (!(e instanceof QudraError) || e.code !== 'partner.rate_limit') throw e;
const base = Math.min(60, 2 ** attempt);
const jitter = Math.random() * base;
await new Promise((r) => setTimeout(r, jitter * 1000));
}
}
throw new Error('Rate limit retries exhausted');
}Bulk endpoints
If you regularly need to post more than 50 jobs/minute, use the bulk endpoint — one request counts as one against your rate limit but creates up to 100 jobs.
Monthly job quota
The monthly_job_limit is a separate quota from the per-minute rate limit. When you hit it, you'll get 429 partner.plan_limit_exceeded (not rate_limit). The counter resets at the start of each calendar month (Asia/Riyadh time).