The refusals, and what each one means
Every refusal arrives in the standard error envelope, and the
code field is the one
to branch on. Messages are prose and may be reworded; the fields are the contract.
The per key request rate
Each API key has a request rate, counted per minute. Over it, the request is refused with HTTP 429, coderate_limit_exceeded, and a Retry-After header carrying the
number of seconds to wait:
The spend rate cap
The spend rate cap is the control that stops a key leaked into a public repository costing you your whole balance in the minute before you notice. The default is 5000 minor units per rolling 60 seconds. Over it, a request is refused with HTTP 429 and codespend_rate_exceeded:
What it counts, which is not what you spent
The cap counts money reserved, and a reservation is an estimated maximum. When a request is admitted we hold the most it could possibly cost. That figure comes from the request’s ownmax_tokens where it names one, and from the model’s published
maximum output length where it does not. The request then settles for what it actually
produced and the rest of the hold comes straight back.
The window counts what was reserved, when it was reserved, and nothing is ever taken
back out of it. A released hold, an expired hold and a settled hold all go on counting
for their full 60 seconds. That is deliberate rather than convenient: a leaked key
makes requests that finish, thousands a minute, holding almost nothing at any one
instant, and a ceiling computed from live holds would be a limit on concurrency that
such traffic never approaches.
Two consequences you can see:
- A minute of ordinary traffic that all completed successfully still counts against the ceiling for a minute afterwards.
- On an expensive model, requests that omit
max_tokenshold the model’s whole published maximum output. The cap can therefore bind well below 50.00 a minute of real spending, because the money it is counting is money you were never going to spend.
The lever: send max_tokens
The hold is the smaller of the max_tokens you asked for and the model’s published
maximum output length. A client that names a realistic ceiling gets several times
more requests a minute out of the same cap and is charged exactly what it was
before, because the charge has always been for what was actually produced.
Out of credit and over the cap at the same time
You are told about the money. An account that is both out of credit and over its ceiling gets the 402, because the cap clears itself in 60 seconds and telling someone with no credit to slow down is advice that cannot work.The limits that belong to one key
The limits above this line belong to the workspace or to the account, so they stop every key at once. Two limits belong to a single key, and the difference is the point: the rest of the workspace goes on serving while one key is refused. A key may carry its own expiry date. A key presented after that date is refused with HTTP 401 and codekey_expired, and the message names the instant it expired on,
so a workspace holding several keys can tell which one ran out. It is checked before
the per key request rate, so an expired key never consumes that allowance. Nothing
renews a key: create a new one on the Keys screen and replace the old one wherever it
is configured.
The code is its own rather than invalid_api_key because the two are opposite advice.
An invalid key means the string is not a key here, and the fix is to find the right
one. An expired key means this was your key and the date you chose has passed.
A key may also carry its own credit limit. A request that would take the key past
it is refused with HTTP 402 and code key_limit_exceeded, before any credit is held,
and the message names what that key has settled and holds inside its current window
against what it may spend.
That is a different refusal from insufficient_credit, which is the account having no
money and stops every key on it. A key at its own limit leaves the other keys in the
workspace serving from the same balance, and buying credit does not clear it. What
clears it is the window rolling, where the limit resets on a cadence, or somebody
raising or removing it on the Keys screen. A limit set never to reset does not clear
by waiting.
Requests served on your own provider key do not count against a key’s credit limit and
are never refused by it: the money it counts is money spent from your balance, and
those requests spend none of it. See Bring your own
key.
Nothing is charged when either refuses, and no credit is held.
Which limits are yours to raise
The Limits section of Settings lists your limits one unit at a time, and marks each one as yours or shared. The distinction is the rule, not a label:This protects your own money. You may raise it yourself, up to the limit shown.applies to the spend rate cap, and
This protects a provider account we share across every customer. Raising it is a decision we make, not one you can make yourself.applies to the request and token rates. Raising a shared rate trades away another customer’s room, so it is a decision made by someone weighing the whole pool. There is no self service path for those figures, and there is no hidden one either. Two of the rows carry no figure yet, and the screen says why:
Not yet enforced. We are not checking your traffic against this figure yet.They are drawn because the units we meter you in are fixed now rather than later. A row with no figure means nobody is checking it, and it never means you have no room.
Setting your own spend rate cap
The spend rate cap is a whole number of at least 100 minor units per rolling 60 seconds. The screen shows the highest value you may set yourself; above that, ask us. Lowering your cap always works, including from a figure above the ceiling. Setting a cap of 0 is refused. Stopping requests entirely is what the pause is for, and it has its own control, its own state and its own sentence.Only the workspace owner can manage its billing: the card and the buying of
credit are the owner’s own. Members may read the balance and the statement of
the workspace they are in.
Pausing everything
The pause refuses every request on the workspace’s keys straight away, without revoking anything. Requests are refused with HTTP 503 and codepaused_by_owner, and
nothing is charged for them. Lifting it starts everything again with no keys to
re-create.
Requests that were already running when you paused are not cut off. Each finishes and
is charged for what it really used.
Any member may read whether requests are paused. Only the owner may press it or lift
it. The full flow, including the numbers the screen states before you press, is in
Spend controls.
Next
Spend controls
Setting the cap, the low credit notice, and the pause, step by step.
Credits and billing
Holds, available balance, and what happens at zero.
Every response carries the same id on two headers:
x-uniblock-request-id,
which is ours, and x-request-id, which is the one the official OpenAI SDKs
surface on their error objects. Every error envelope repeats it as
request_id. Quote it when you ask us about a request. Without it we are
guessing at which of your requests you mean.