Skip to content

OmnAPI Rate Limits

OmnAPI applies request limits in layers. A request must pass the shared IP limit and, for authenticated endpoints, the API-key limit for the key’s tier or custom key settings.

LayerDefault behaviorScope
IP fixed window2000 requests / 60 secondsClient IP
FREE API key5 requests / second, 5,000 / day, 100,000 / monthAPI key
PREMIUM API key25 requests / second, 25,000 / day, 500,000 / monthAPI key
ENTERPRISE API key200 requests / second, 500,000 / day, 10,000,000 / monthAPI key

API-key daily and monthly windows use UTC calendar boundaries. Custom limits on an API key override the tier default for that dimension. A limit value of 0 means unlimited for that dimension.

GET /api/v1/pricing/catalog is public and does not require an API key, but it still passes through the shared IP limit.

In addition to request rate limits, each tier has a cap on non-terminal tasks. These caps prevent a single account or key from filling the worker queues with long-running generations.

TierAccount in-flight capPer-key in-flight cap
FREE2020
PREMIUM100100
ENTERPRISE10001000

An in-flight task is any task that has not reached COMPLETED, FAILED, or CANCELLED.

Successful responses include the shared IP-layer headers:

HeaderMeaning
X-RateLimit-LimitActive IP-window limit
X-RateLimit-RemainingRequests left in the current IP window
X-RateLimit-ResetUnix timestamp when the IP window resets

When an API-key limit fires, the 429 response headers describe the API-key limit that fired. Retry-After is included on rate-limited responses.

{
"success": false,
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Please retry after 42 seconds.",
"details": {
"type": "rps",
"limit": 5,
"current": 6,
"retryAfterSec": 1
}
}
}

details.type can be rps, daily, or monthly for API-key limits. IP-limit responses may omit details and should be handled from Retry-After.

async function callWithRateLimitRetry(url: string, apiKey: string) {
for (let attempt = 0; attempt < 5; attempt++) {
const response = await fetch(url, { headers: { "x-api-key": apiKey } });
if (response.status !== 429) return response.json();
const waitSec = Number(response.headers.get("Retry-After") ?? 1);
await new Promise((resolve) => setTimeout(resolve, waitSec * 1000));
}
throw new Error("Rate limit retry budget exhausted");
}

For long-running generation tasks, avoid aggressive polling. Use the polling schedule in The Task Model or subscribe to Webhook Events.

Contact support before production traffic exceeds your tier. Enterprise keys can be assigned higher API-key limits and task caps after capacity review.