All posts

7 min readparanine

Rate limits, spend caps and expiry, one key at a time

A key that cannot outspend its budget, outlive its purpose or reach the wrong model is a smaller incident than one that can. The four limits on a P/9 API key.

Every P/9 API key carries four limits: a rate in requests per minute, a credit limit in rupees, an expiry date, and the list of models it is allowed to call. All four are enforced by the gateway rather than by the application holding the key, which is the difference between a limit and a convention.

This post is what each one does, which error it produces, and how to choose them. The error codes are the useful part, because they are what you will actually be reading when something is wrong.

The single unlimited key is the incident you have not had yet

The default state of most integrations is one key, shared across environments, with no ceiling and access to every route. It works perfectly until one of three things happens: it leaks, a loop retries forever, or a job that was supposed to run nightly runs continuously after a deploy.

None of those are exotic. What decides how bad they are is whether the key could spend the whole balance, and that is a decision made months earlier by whoever created it.

Rate: requests per minute

A new key starts at 60 requests per minute. The rate is not chosen at creation time; it is changed afterwards from the key's detail panel, alongside the other limits. Over the limit, the gateway answers 429.

Treat the rate limit as a blast radius control rather than a capacity control. It is what stops a misbehaving client from turning a bug into a bill, and it is the cheapest of the four to set, because a well-behaved service never notices it.

Spend: a rupee ceiling per key

Each key can carry a credit limit in rupees. Once that key has spent it, the gateway rejects further calls with 402 instead of serving them. Left unset, the key is limited only by the organisation's balance, which means one key can spend everything.

There are two ceilings, and one error. A 402 means either the organisation's budget is exhausted or that key reached its own limit, and the response does not say which, so check both. Two edits are refused outright and both messages carry the real figure: a limit set below what the key has already spent this cycle, and a limit that would push the sum of every key's limit past the organisation's budget.

That second rule is the one worth understanding, because it is what makes the caps mean something. If the limits could sum past the balance they would be advisory, and the first incident would be the one that proved it.

How to pick a number for that ceiling before you need one

Expiry: a key that stops on a date

A key can carry an expiry, after which it stops working. Left unset, it never expires, which is the right default for a production service and the wrong one for everything else.

The useful case is access that was always temporary: a contractor, a proof of concept, a demo environment, a vendor integration on a trial. The failure mode without it is not dramatic, it is just permanent. An expired key answers 401 with a message naming expiry, so read the message before concluding a key was revoked.

Scope: which models a key may call

A key can be restricted to specific model routes. A request for anything outside that list is rejected with 403 and a model scope error, even though the key is valid and funded.

This is the limit that pairs best with the credit limit, because most runaway-cost stories involve a cheap workload reaching an expensive route. A key scoped to the one model a service actually uses cannot participate in that story at all.

The error codes, and what each one really tells you

Read these as a decision tree rather than a list. Each points at a different thing to fix, and the common mistake is treating all four as authentication problems.

  • 404: the model id does not name a live route. Resolved before the key is checked, so this is about the model string, not the key
  • 401: the key is wrong, revoked, or expired. An expired key says so in the message, which is the fastest way to tell the two apart
  • 402: out of funds, either the organisation's budget or this key's own credit limit. The body does not say which, so check both
  • 403 model scope error: valid, funded key asking for a route it is not allowed to call
  • 429: over the key's requests-per-minute rate. Back off and retry; a retry storm here is also a spend event

What this looks like when it is done properly

One key per service per environment, so revoking one takes down one thing. A credit limit on every key, sized at something like a month of expected spend rather than the whole balance. An expiry on anything that was never meant to be permanent. And scope narrowed to the routes that service genuinely calls.

None of this is difficult and all of it is done at creation time in a minute. The reason it usually is not done is that the cost of skipping it is zero until it is very much not.

Why these controls belong in the gateway rather than in your application

The short version

Four limits, four errors, one principle: the platform should be the thing that says no, because the application asking politely is not a control. Set them when the key is created, because that is the only moment when doing so costs nothing.

Common questions

Can I cap spending on a single API key?
Yes. Each P/9 key carries a credit limit in rupees, and once the key has spent it the gateway answers 402 rather than serving the request. The limit is enforced at the gateway, so it holds regardless of which service is holding the key.
What does a 402 from the P/9 API mean?
Insufficient funds, fired either because the organisation's budget is exhausted or because that key has reached its own credit limit. The response body does not distinguish the two, so check both before assuming which ceiling was hit.
What is the default rate limit on a new key?
A new key starts at 60 requests per minute. The rate is not settable at creation time and is changed afterwards from the key's detail panel in the dashboard, alongside its credit limit and expiry.
What does a 403 model_scope_error mean?
The key is valid and funded, but the model you asked for is not in the list that key is allowed to call. It is the error you want a narrowly scoped key to produce, and the fix is either to use a key with wider scope or to widen this one deliberately.
Why does an unknown model return 404 rather than 401?
The gateway resolves the model id before it checks the key, so a request naming a route that does not exist is rejected as a missing route rather than as an authentication failure. A 404 therefore points at the model string, not at the key, which is worth knowing at three in the morning.