Rate limits and spend limits
Two independent protections: how fast you may send, and how much you may spend.
Rate limits
Requests are rate limited per API key. Exceeding the limit returns
429 with type rate_limit_error. Back off and retry —
a rejected request is never charged, and never reaches a model.
Rate-limit headers
POST /v1/chat/completions returns these on successes and on
429 alike, so the same parsing works either way.
| Header | Meaning |
|---|---|
X-RateLimit-Limit-Requests | Requests permitted in the window. |
X-RateLimit-Remaining-Requests | Requests left in the window. |
X-RateLimit-Reset-Requests | Upper bound, in seconds, until capacity frees. The window slides, so this is a bound and not a prediction. |
Retry-After | Seconds to wait. Present on `429` when known. |
Absent headers mean unknown, not unlimited
If Astrodyne cannot compute a truthful count for a request — during a limiter
degradation, for example — the headers are omitted rather than
filled with a guess. Treat their absence as "no information", never as "no
limit".
Retry-After appears on 429 when a wait time is
known.
X-RateLimit-Reset-Requests is an upper bound in seconds,
not a countdown: the window slides, so capacity may free sooner. Never treat
it as an exact time.
Spend limits
Three separate ceilings apply, and the tightest one wins.
- Your balance. A hard ceiling. A request that would exceed
it is refused with
402 insufficient_fundsbefore anything runs. - Per-key monthly spending limit. Optional, set when you
create a key. Exceeding it returns
429with codespending_limit_exceeded. - Account caps during the invite-only rollout. Accounts in the current cohort carry daily request and spend caps. Reaching one stops further requests for that window.
A prepaid balance is a spending limit
This is the reason a runaway agent loop cannot produce a surprise invoice: there
is no credit line to draw on. The worst case is that you spend what you already
put in.
Request size
An oversized request body is refused with 413 and code
request_too_large rather than being truncated.
Handling limits in code
- Treat
429as retryable with backoff. - Treat
402as not retryable — add funds first. - Read the
codefield, not the message text, when branching.