---
title: "What a spending ceiling protects you from"
canonical: "https://router.xark.io/blog/what-a-spending-ceiling-protects-you-from"
description: "The balance is the only hard limit here. Four things that look like spend controls and are not, and the exact arithmetic of how fast a ceiling can go."
section: "blog"
updated: "2026-09-08"
source: "https://router.xark.io/blog/what-a-spending-ceiling-protects-you-from.md"
---

# What a spending ceiling protects you from

*Published 2026-09-08. Topics: cost-control, billing, credits, agents.*

The balance is the only hard limit here. Four things that look like spend controls and are not, and the exact arithmetic of how fast a ceiling can go.

Exactly one control here is a spending ceiling: the prepaid balance, which refuses at zero with 429 insufficient_credits and does not charge the refused request. Four things are commonly mistaken for one and are not -- API keys are minted with no per-key cap on purpose, rate limits bound requests rather than dollars and would still permit $330 an hour on Kimi K3, cancellation lands late, and max_completion_tokens bounds one request rather than a run. Auto-recharge, when enabled, raises the ceiling by up to $150 a day.

## The control that works, in one paragraph

The balance is a hard ceiling rather than an overdraft. At zero the API returns 429 with code insufficient_credits, and the refused request is not charged. No amount of code failure produces a bill you did not fund, because there is no mechanism for spending money that has not been loaded.

That is the whole of it, and its strength is that it requires no configuration. Every other control described on this page requires you to have thought of something in advance, which is precisely the assumption a runaway loop violates.

So the meaningful decision is the rung you choose. A $30 balance is a $30 worst case; a $500 balance is a $500 one. Choosing it deliberately is the control, and the rest of this page is about the things that quietly move it.

## Not a control: the API key

Keys here are created with unlimited quota at the key level and a remaining quota of zero, deliberately. The account balance is what actually stops spend, and a per-key cap layered on top of it would silently shadow the balance -- producing an insufficient-quota error on one key while the account still had credit, which is a support ticket that reads like an outage.

The consequence is that a key is a cost centre and not a budget. Spend is attributed per key at the gateway: every consumption row carries the name of the key that produced it alongside the model and both token counts, so a key named after a service tells you where the money went. It does not tell the money to stop.

This is a genuine gap and worth naming a provider who fills it. SiliconFlow publishes optional monthly spending limits alongside its pay-as-you-go billing; if a configurable cap per project is what you need today, that is a real product and we do not have one. Per-key caps here are a feature to build with a user interface, not a default to guess at.

## Not a control: the rate limit

Sixty requests a minute on chat sounds like a bound on damage. Multiply it out and it is not. Sixty a minute is 3,600 an hour, and at 1,000 input and 10,000 output tokens each that is 3.6M input and 36M output tokens in an hour -- which converts to money at the output rate, where the models separate most.

There is a second reason not to lean on it. The published per-endpoint limits are enforced by an in-process fixed-window counter, so each serving instance keeps its own, and the relayed path meets the gateway's own limiter keyed on the connection's address rather than on your key. You may observe more than the published numbers succeeding. The published numbers are the contract; the surplus is an artefact, and a spend control built on an artefact is not a spend control.

| Model | Output / 1M | An hour at the chat limit | How long a $30 rung lasts |
| --- | --- | --- | --- |
| Kimi K3 | $9.00 | $330.66 | About 5.5 minutes |
| GLM-5.2 | $2.55 | $94.75 | About 19 minutes |
| Kimi K2.6 | $2.30 | $84.78 | About 21 minutes |
| DeepSeek V4 Pro | $0.55 | $20.81 | About 1.4 hours |
| DeepSeek V4 Flash | $0.18 | $6.80 | About 4.4 hours |

## Not a control: hanging up

Closing a connection now propagates upstream -- the outbound request carries your own signal alongside a 300-second timeout, so a cancelled stream does stop generating. It is still not a refund and it is still not a budget.

Cancellation lands late, and everything produced before it lands is metered. Treating a disconnect as free is the mistake, and it is an expensive one in exactly the product where disconnects are normal: a user-facing chat where people interrupt.

The levers that reliably reduce that cost are not cancellation. They are a shorter output ceiling, a prompt that asks for shorter answers, and a cheaper model behind the interruptible surface.

## Not a control: max_completion_tokens, on its own

This one is closer than the others, and it is the only per-request bound that exists. It caps the worst single response, which is genuinely useful, because an evaluation suite exists precisely to find inputs that behave badly and an agent loop finds them by accident.

What it does not do is bound a run. Three thousand six hundred capped requests still multiply, and a cap chosen for the interface rather than for the model can quietly cost more than no cap at all -- generation stops at the ceiling with finish_reason length, and a client that retries a truncated answer has paid for the truncated one and then paid again.

Use it, and use it at the length your interface can actually display. Then stop treating it as the reason you do not need a balance you chose deliberately.

## The thing that raises the ceiling

Automatic top-up fires a $50 charge when the balance falls below $10, capped at three charges per rolling UTC day with a five-minute cooldown between them. That means the real first-day ceiling on any account with it enabled is the balance plus $150, for as long as the card keeps approving.

The guards around it are the feature rather than the charge. One attempt row per user-minute, enforced by a unique constraint, so two concurrent triggers cannot both charge and the lock survives a process dying mid-charge. A circuit that disables the whole thing after three consecutive declines, which is what stops a fraud-flagged card being retried into a merchant-account problem. And a latch that disables it entirely after a strong-authentication decline, because retrying can never clear that one -- only the customer coming back and authenticating can.

None of that is a zero. It is a bounded incident instead of an unbounded standing instruction against a card, which is a different and much better thing, but it is not the number you thought you had set. If a key runs somewhere you do not fully control, turn automatic top-up off before you do anything else: revoking a key stops the key, and only this stops the card.

## A ceiling can also be lower than what you paid

This is the failure nobody expects, and it runs the other way. Every crediting path in the gateway is gated on an administrator confirming payment compliance terms in its own dashboard, and that confirmation explicitly refuses an API token -- it is a deliberate human step.

Until it is cleared, a payment succeeds, the webhook records the event as failed, an operator is paged, and the credit is applied later by a replay script. Money taken is never money lost, only money not yet delivered. But in the interval your ceiling is whatever it was before the top-up, not what you just bought.

The check is the same one worth running after any top-up: read your balance, do not assume it. GET /api/me returns both the raw quota and its dollar value, and the raw figure is the authoritative one.

## How to actually bound a project's spend today

Choose the rung on purpose. The ladder is $30, $50, $100, $200 and $500, and the smallest one is a deliberate $30 worst case rather than a starter tier.

Turn automatic top-up off for anything running where you cannot watch it. Leave it on for production, where the failure you are actually preventing is a run stopping mid-flight at three in the morning.

Issue one key per project and name it for where it runs. worker-2026-09 and ci-eval are useful in a usage log; Default is a line item nobody can explain three months later. That gives you attribution, which is what you need before any cap would have been set to a sensible number anyway.

Cap max_completion_tokens at the length your interface can display, and choose the model for the shape of the work rather than for its reasoning reputation. On a workload that reads a lot and writes one word, the input rate decides the bill and a cheaper model is not a compromise.

Then log usage.cost_usd per request. A cost regression shows up in the distribution of that field long before it shows up on a balance, and a balance is a lagging indicator by construction.

## What we guarantee, and what we do not

Every model here is priced 36–42% below what its own publisher charges, rising to 65–68% on the workload this product is actually bought for -- 400M input tokens a month with a 60% repeated prefix, and 8M output. The guarantee published alongside those is deliberately looser than either, at 20% below the publisher's own rate, because a guarantee written at the exact current minimum breaks the first time a publisher cuts a price.

What none of those numbers is, is a cap. A percentage below somebody else's rate makes a fixed amount of work cheaper; it does nothing about an unbounded amount of work. The two are separate questions and conflating them is how a cost incident gets rationalised as a good deal.

And the honest summary of the spend controls themselves: one hard ceiling that you choose, one mechanism that raises it that you can switch off, and no per-key budget. If a configurable per-project cap is a requirement rather than a preference, that is a reason to choose someone else today, and we would rather you read it here.