Skip to content

Reference

Rate limits & idempotency

Requests are rate limited per key and per workspace, by requests-per-minute. When you are limited, unoblox tells you exactly how long to wait. An Idempotency-Key identifies a request so a retry of it is refused rather than executed twice — it does not replay the original response.

How rate limiting works

The limiter counts requests (not tokens) in a fixed 60-second window, at two levels, checked together:

ScopeSet byDefault
Per keyThe rpm you set when creating the key (1–600).60 if you don't set one
Per workspaceA workspace-wide cap configured for the account.Unlimited unless configured

A request is rejected if either the key or the workspace is over its cap for the current window. There is no separate tokens-per-minute limit — throughput is governed by your ₹ balance and any budgets, not a TPM cap. A key created with no explicit rpm gets 60, not unlimited — set one explicitly, up to 600, if you need more. Freemium models add a separate fair-use limit (currently 10 requests per minute per workspace, at any balance; see Freemium access). Give each service or environment its own key with its own rpm so one runaway client cannot starve the others.

When you hit a limit

You get a 429 with type: rate_limit_exceeded and a set of headers telling you the cap and when it resets:

429 response
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 12
Content-Type: application/json

{ "error": { "message": "rate limit exceeded", "type": "rate_limit_exceeded", "code": 429, "request_id": "7b679c45-424f-4153-b72e-e7217758065f" } }
HeaderMeaning
Retry-AfterSeconds to wait before retrying.
X-RateLimit-LimitThe applicable per-minute request cap.
X-RateLimit-RemainingRequests left in the window (0 on a 429).
X-RateLimit-ResetSeconds until the window resets.

These headers are attached to the 429 response only — successful responses do not carry rate-limit headers.

Backing off

Respect Retry-After and retry with exponential backoff. The OpenAI SDK raises RateLimitError on a 429, exposing the response headers:

python
import os, time
from openai import OpenAI, RateLimitError

client = OpenAI(
    base_url="https://api.unoblox.ai/v1",
    api_key=os.environ["UNOBLOX_API_KEY"],
)

def create_with_retry(**kwargs):
    for attempt in range(5):
        try:
            return client.chat.completions.create(**kwargs)
        except RateLimitError as e:
            # Honor Retry-After; fall back to exponential backoff.
            wait = float(e.response.headers.get("retry-after", 2 ** attempt))
            time.sleep(wait)
    raise RuntimeError("still rate limited after retries")

Idempotency

Idempotency-Key becomes this request’s id. Its purpose is the opposite of a typical idempotency key: it lets unoblox detect and refuse a retry, not replay one. A durable claim on the id is taken before any money effect; reusing an id you’ve already sent — even after a timeout, a network blip, or a 429/5xx — gets a 400, not the earlier response:

reused key → 400
{ "error": { "message": "This request ID has already been used; the response can't be replayed automatically.", "type": "invalid_request", "code": 400, "error_code": "UB-GW-059" } }
curl
curl https://api.unoblox.ai/v1/chat/completions \
  -H "Authorization: Bearer $UNOBLOX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-4821-attempt-1" \
  -d '{
    "model": "<model-id>",
    "messages": [{ "role": "user", "content": "Draft a shipping update." }]
  }'
BehaviorDetail
Retry with the SAME keyRefused with 400 UB-GW-059. There is no dedup window or response replay — the claim is permanent.
Retry with a NEW keyThis is the correct way to retry after a timeout/429/5xx: generate a fresh key for the retry attempt.
Length1–256 bytes, or 400 UB-GW-060.
Not a response cacheThis is a billing/replay guard, not a cache — it never returns the earlier completion. Deterministic response caching is separate and requires its own opt-in header (see Pricing).
No key sentunoblox generates a request id for you, so accounting still works — you just lose the ability to detect your own retries.

Inspecting a key's limits

A key's current RPM cap, spend limit, model scope and window usage are shown in the portal under API Keys, and can be read back programmatically via the key-introspection endpoint (it returns rpm_limit, spend_limit, models_scope and usage). See the API reference.

Need a higher limit?

Raise a key's rpm in the portal, or split traffic across keys. Enterprise workspaces can lift the workspace-wide cap — talk to us.