Skip to content

DocsAPI reference

Rate & spend limits

INFRO gateway rate limits, provider account quotas, estimated-spend budgets, subscription access, and how to handle 429 and 402 errors.


INFRO is in private early access. Running these examples requires an early-access account, an active trial or subscription entitlement, and your own provider connection. Self-serve purchasing is not generally open. See Early access.

Every INFRO key is governed by two independent limits: a rate limit on requests per minute and an optional spend limit capping the dollars it can consume. Rate limits protect throughput; spend limits protect your budget. Both are enforced per key, so you can tune them per service in the console.

This page covers how each limit works, the headers that report your standing, and what the 429 and 402 failure modes look like. For the full error catalog and retry rules, see Errors.

Rate limits

Each key gets its own requests-per-minute ceiling, chosen when you create the key from fixed tiers: 60, 100, 200 (the default), 300, 500, 1,000, 2,000, 5,000, 10,000, 20,000 or 50,000 RPM. The console also takes a custom number and shows the tier it rounds down to before the key is created. It is a property of the key rather than of your subscription — a plan sets your monthly request allowance, not your per-minute rate — so different keys in one organization can carry different ceilings. Every response reports the ceiling actually in force in X-RateLimit-Limit, so read your live limit from there rather than assuming the base.

Your own provider accounts retain their model, token and request quotas. INFRO does not add a shared pool of purchased capacity. Failover can use another eligible connection you configured; retries count once toward the INFRO request allowance, while provider-side usage follows each provider's own billing rules.

Rate limit headers

Every response — success or error — carries three headers describing the key's current window.

HeaderExampleDescription
X-RateLimit-Limit200Requests allowed per minute for this key.
X-RateLimit-Remaining173Best-effort upper bound on requests left in the current window — see the note below.
X-RateLimit-Reset1755950520Unix timestamp (seconds) at which the current window resets. Exact.
Response headers
HTTP/2 200
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 173
X-RateLimit-Reset: 1755950520

X-RateLimit-Reset is exact. X-RateLimit-Remaining is not, and the difference matters. Rate limiting is enforced at the Cloudflare location serving your request rather than from one global counter, so Remaining counts only what that location has seen. It is therefore an upper bound on what is left: your key may have spent more than it says, never less. Back off as it approaches zero — that is what it is for — but do not schedule against it, and do not read a non-zero value as a guarantee that the next request is admitted. Reset is a property of the window rather than of any counter, so it is exact. The authoritative signal is still the 429 itself and its Retry-After.

When you hit the rate limit

Exceeding the RPM budget returns 429 with type rate_limit_exceeded and a Retry-After header giving the seconds to wait.

429 response
HTTP/2 429
Retry-After: 60
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1755950520

{
  "error": {
    "message": "Rate limit exceeded: 200 requests per minute for this key.",
    "type": "rate_limit_exceeded",
    "code": null
  }
}

Honor Retry-After when present, and retry with exponential backoff plus jitter. 429 is one of the four retryable statuses, alongside 408, 502, and 503; never auto-retry 400, 401, 402, or 404. Reference retry implementations are in Errors.

Spend limits

A key's spend limit is a hard USD ceiling on the estimated provider cost of its requests, set when you create the key in the console or changed later under Edit spend limit. Once the key has used its limit, every subsequent request fails with 402 budget_exceeded until the limit resets or you raise it. The same 402 is returned by an organization, project or member budget; the message names which one refused.

Each limit resets on a schedule you choose. Daily resets at midnight UTC, weekly at midnight UTC on Monday, and monthly at midnight UTC on your organization's budget cycle day. Never is a lifetime cap: it does not reset, so it bounds what a leaked key can spend in total. Every window is anchored to UTC, not to a time zone, so the limit resets at the same instant for everyone on your team.

Usage is measured in estimated provider cost. A request to a model with no price cannot be measured, so by default it is refused (402, code unpriced_model_under_budget) while a blocking limit applies, unless you enter a rate for the model under Prices or allow unpriced traffic under Budgets in the console.

402 response body
{
  "error": {
    "message": "Budget exceeded: this API key has used its weekly spend limit. Requests are refused until the limit resets at midnight UTC on Monday, or until you raise it under Keys in the console.",
    "type": "budget_exceeded",
    "code": "key_budget"
  }
}

A key's daily, weekly or monthly limit returns key_budget. A lifetime (never) cap returns key_lifetime_limit instead, because nothing but raising it will restore access.

A 402 is not transient. Retrying will not succeed until the budget that refused it is raised or removed — exclude it from automatic retry logic. Inspect error.code: subscription_required and trial_payment_failed mean software access must be restored. Budget-related failures require changing the named budget.

For per-request accounting, every response includes usage.cost — an estimate of your provider's charge — beside provider and connection; see Chat completions. For a key's cumulative estimated spend, query GET /v1/key.

Checking a key's usage

GET /v1/key returns the current key's label, spend limit, and usage against it, plus how often the limit resets and when it next does. Poll it from dashboards or pre-flight checks to see where a key stands.

curl https://api.infro.io/v1/key \
  -H "Authorization: Bearer $INFRO_API_KEY"
Response
{
  "label": "prod-checkout",
  "limit": 250.00,
  "usage": 187.42,
  "limit_remaining": 62.58,
  "limit_period": "weekly",
  "limit_resets_at": "2026-09-28T00:00:00.000Z"
}
labelstring
The name assigned to the key in the console. Useful for confirming which key a service is actually using — see Authentication.
limitnumber | null
The key's spend limit in USD. null if no limit is set. If a key carries both a resetting limit and a lifetime cap, this is whichever has less room left.
usagenumber
USD spent by this key against limit — inside the current window for a daily, weekly or monthly limit, or over the key's lifetime for never. With no limit set, the key's lifetime total.
limit_remainingnumber | null
limit minus usage, never below zero. null when the key has no spend limit.
limit_period"daily" | "weekly" | "monthly" | "never" | null
How often limit resets. never is a lifetime cap. null when the key has no limit.
limit_resets_atstring | null
When the limit next resets, as an ISO 8601 timestamp in UTC. null for never and when the key has no limit.

Handling burst traffic

  • Use one key per service. Each key has its own RPM budget and spend ceiling, so a spike in one service cannot starve another — and per-key labels make cost attribution trivial.
  • Watch X-RateLimit-Remaining. Throttle client-side as it approaches zero instead of absorbing 429s. It is a best-effort per-location count, so treat it as a hint to slow down rather than an exact budget, and keep honouring Retry-After on the 429 itself.
  • Respect Retry-After and add jitter. Synchronized retries from a fleet of workers re-trigger the limit in lockstep; randomized backoff breaks the herd.
  • Consolidate small calls. The RPM budget counts requests, not tokens — a streamed response is still one request, so fewer, larger calls stretch the budget further.
  • Pick a higher tier. The per-minute limit is set on the key, not by your plan, so moving up a plan does not raise it. If a service consistently runs near X-RateLimit-Limit, issue it a key on a higher tier (up to 50,000 RPM). The ceiling is per key, so splitting traffic across keys also spreads it. Remember that your provider accounts keep their own rate limits, which INFRO does not raise.

Subscription and trial access

Serving requires an active software entitlement. 402 subscription_required means the subscription or trial no longer grants access, and 402 trial_payment_failed means the charge at the end of a trial failed and its grace period ended. Request allowances are soft on every plan, trials included: past the allowance requests are served and counted, never refused for volume, and do not create automatic overage charges. These conditions are distinct from budget_exceeded. See Billing.

Response cache hits

A hit from the response cache counts against the key's rate limit and toward the plan's monthly request allowance like any other request. It takes no spend-limit or budget reservation, and it is served even when a blocking limit is exhausted, because a hit is not sent to your provider and adds nothing to its bill.

↑ ↓ navigate↵ open/ anywhere in docs