Skip to main content
Ottili AI API

Ottili AI API — Rate limits & quotas

How rate limiting and quotas work in the public Ottili AI API, the response headers returned, free vs paid usage, and how to back off safely.

Rate limits & quotas

The Ottili AI API applies two related protections: rate limits* (a short-window throttle that protects shared

infrastructure) and quotas* (the plan-scoped allowance your company can consume per period). Both are returned on

every response so your client can self-regulate instead of guessing.

Rate-limit headers

Every response — successful or throttled — includes standard rate-limit headers:

RateLimit-Limit: 600
RateLimit-Remaining: 597
RateLimit-Reset: 1752364800
HeaderDescription
RateLimit-LimitMax requests allowed in the current window for your key/company.
RateLimit-RemainingRequests left in the current window.
RateLimit-ResetUnix timestamp (seconds) when the current window resets.
The exact numeric ceiling depends on your plan and API key scopes. Always read the live values from these headers rather than hardcoding them — they may change as plans evolve.

Quotas and free vs paid usage

Your company's quota* is the total allowance your plan grants for a period (for example, requests per day and the

AI credit pool). How the two relate:

  • Free / included allowance* — every plan ships an included monthly quota (request quota + included AI credits). It

resets at the start of each billing period and unused included amounts do not roll over.

  • Paid plans* — raise both the request quota and the included credit pool, and unlock higher rate-limit ceilings.
  • Credits* — AI requests are metered against the shared company credit wallet. See

[Credits & usage](/docs/ottili-ai-api-credits). When the credit balance or monthly budget is exhausted, generation

stops with a clear insufficient_balance (HTTP 402) or rate_limit_exceeded

(HTTP 429) error instead of over-spending.

The live numbers for your company are always shown in Settings → Billing* in the dashboard and in the response

headers above. Do not poll the generation endpoint to discover your limits — watch the headers and react to limit

errors.

When you are limited

When a rate limit is exceeded the API responds with HTTP 429 Too Many Requests, a Retry-After header telling you

how many seconds to wait, and the RateLimit-* headers reflecting the reset:

HTTP/1.1 429 Too Many Requests
Retry-After: 12
RateLimit-Limit: 600
RateLimit-Remaining: 0
RateLimit-Reset: 1752364860
{
  "detail": {
      "code": "rate_limit_exceeded",
    "message": "Too many AI API requests. Please retry after the indicated delay."
  },
  "code": "HTTP_429",
  "request_id": "b1c2d3e4-0000-1111-2222-333344445555"
}

The request_id is present on every response and is the handle to share with support (see

[Errors → Support](/docs/ottili-ai-api-errors)).

Backing off (retries)

Honour Retry-After exactly, then add a small jitter so many clients do not retry in lockstep. Exponential backoff

without Retry-After is a safe fallback:

import time, requests

def complete_with_retry(url, headers, body, max_retries=4):
    for attempt in range(max_retries):
        r = requests.post(url, headers=headers, json=body)
        if r.status_code != 429:
            return r
        wait = int(r.headers.get("Retry-After", 2 ** attempt))
        time.sleep(wait)
    raise RuntimeError("Rate limited after retries")

Authenticated, scoped requests receive higher ceilings than anonymous traffic. Cache static metadata and model lists

(GET /v1/models) to stay well under the limit, and send an Idempotency-Key on retried POST calls so a

retry never double-charges (see [Errors → Idempotency](/docs/ottili-ai-api-errors)).

Was this article helpful?