Skip to main content
Several limits can refuse a request, and they answer with different codes on purpose: you should be able to tell “too fast for this key” from “too much money attempted too quickly” from “this key is done” without asking us. Nothing is charged for a request we refuse, whichever limit refused it.

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, code rate_limit_exceeded, and a Retry-After header carrying the number of seconds to wait:
This limit is counted per key, so splitting work across two keys splits the counter. The figure in force is shown in the Limits section of Settings.

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 code spend_rate_exceeded:
It clears itself. Sixty seconds after the earliest reservation counted, requests are admitted again, with nothing for you to do in the meantime and nothing to reset.

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 own max_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_tokens hold 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.
If you are running a batch job, a load test or an evaluation sweep, this is the first thing to change.

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 code key_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.
Reading your limits is open to every member of the workspace. Changing the spend rate cap is the owner’s. The Limits section and the self service cap control are shipped: the figures and the sentences behind them are the platform’s own, read live rather than written into this page.

Pausing everything

The pause refuses every request on the workspace’s keys straight away, without revoking anything. Requests are refused with HTTP 503 and code paused_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.