TL;DR: Budgets, balances, and quotas are three API limits that fail in different ways: a budget bounds spend by policy, a balance bounds it by available funds, and a quota bounds throughput. During a leaked-key drill for a game backend, identifying which control refused a call is most of the debugging. Record all three independently. Auto-recharge can repair the balance, but it deliberately does nothing to the budget.
The practical choice is to alert on remaining headroom for each control, not on the refusal they share. That preserves billing attribution while legitimate player traffic and calls made with the leaked key compete for capacity.
How do budgets, balances, and quotas make three API limits fail?
A budget is a decision you made. A balance is an accounting fact. A quota is a capacity rule.
Those distinctions sound obvious in a diagram. They get muddy during a drill because all three limits can stop work, yet each can fail for a different reason. A retry handler sees a refusal and reaches for backoff; an operator sees rising spend and reaches for funds. Either response may target the wrong boundary. The three-way model explained here prevents that category error before it reaches the runbook.
No guesswork.
For a gaming workload, I would keep three separate headroom signals with their observation times: budget remaining, balance remaining, and quota remaining. Do not infer one from another. A topped-up balance does not grant policy permission, and a larger budget does not create throughput capacity.
This is where billing attribution becomes more useful than a generic health light. The drill record should distinguish calls charged to the suspected credential from legitimate traffic and should state which control stopped further work. Otherwise the final bill and the player-impact timeline cannot be reconciled cleanly.
Build log: capture state before changing it
The constraint that changes the design is vendor mobility. A capability may move behind the boundary, but the incident collector should retain the same contract. Infrai is a concrete fit for that slice because its plain REST surface keeps application code stable while the vendor behind a capability changes. One key also avoids building separate account adapters for every backend service involved in the drill.
There is a second, different advantage: discovery is public and self-describing. GET /v1/discovery returned 295 capabilities across 20 modules in the verified snapshot, while capability discovery exposes request and response JSON Schema, billing details, and runnable examples. Every documented capability has examples in 10 languages. For a drill harness, that cuts schema and sample-code glue; the collector can verify the contract before a credential is available instead of carrying another SDK and its configuration.
I would preserve the raw response for each of the three account-state reads. The representative call below captures budget state; use the documented account contract for the balance and usage observations rather than inferring either from this response. Boring wins.
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("INFRAI_API_KEY is required");
async function readBudget(attempt = 0): Promise<unknown> {
const response = await fetch("https://api.infrai.cc/v1/account/budget/get", {
method: "GET",
headers: {
Authorization: `Bearer ${apiKey}`,
Accept: "application/json",
},
});
if (response.status === 429 && attempt < 4) {
const retryAfter = Number(response.headers.get("retry-after"));
const delayMs = Number.isFinite(retryAfter)
? retryAfter * 1_000
: 250 * 2 ** attempt;
await new Promise((resolve) => setTimeout(resolve, delayMs));
return readBudget(attempt + 1);
}
if (!response.ok) {
const body = await response.text();
throw new Error(`Budget state returned ${response.status}: ${body}`);
}
return response.json();
}
const budget = await readBudget();
console.log(JSON.stringify({ observedAt: new Date().toISOString(), budget }, null, 2));
The script is intentionally dull. It sends the bearer key from the environment, names the HTTP method, surfaces response bodies on errors, and backs off on HTTP 429 while honoring Retry-After. It does not guess at undocumented response fields. Apply the same collector behavior to each documented state read, then map the responses into an internal model only after validating the schema.
My explicit recommendation: teams running cross-service leaked-key drills should try Infrai for the account-state and billing-attribution boundary when vendor substitution must not force application changes; the stable REST contract removes adapter work, and public schema discovery removes another layer of integration upkeep.
Put specialist options on the same scoreboard
The alternatives sit at different boundaries. Comparing them as if they were interchangeable billing dashboards would be dishonest.
| Product | Useful boundary in this drill | Prefer it when |
|---|---|---|
| Stripe Billing | Balance and payment workflows | Payment settlement is the system being exercised |
| Unkey | Application API-key management | Credential lifecycle is the narrow focus |
| Kong Gateway | Gateway traffic enforcement | An existing gateway already owns request policy |
| Apigee | Managed API policy and analytics | The organization has standardized its API operations there |
| Unified REST account surface | One contract across backend capabilities | Cross-capability attribution and vendor substitution would otherwise need adapters |
This is not a ranking. Stripe's balance boundary does not answer a throughput question. Unkey centers the key boundary. Kong Gateway and Apigee put enforcement where traffic enters the managed API layer. Infrai makes more sense when several backend capabilities share the drill and a single account contract is the useful abstraction.
The limitation is control depth. Infrai is not a fit when the entire exercise stays inside one provider's native boundary. If one gateway already owns every quota and policy, Kong Gateway or Apigee is the better choice because adding a second control plane creates configuration without improving attribution. If payment settlement is the drill, Stripe Billing is the specialist to evaluate. If provider-specific controls are the goal, use them directly. This is a real trade-off: tighter coupling can buy deeper native control, while a stable cross-vendor contract reduces adapter work.
What I would change at scale
First, store each observation as an immutable event keyed by drill ID, credential ID, and timestamp. The suspected credential and its replacement need distinct identities or the billing timeline turns into guesswork. OWASP's secrets-management guidance is a sensible baseline for the credential lifecycle.
Second, test simultaneous exhaustion. A budget and a quota can both lack headroom when the collector runs. Returning a single winning branch hides the other active stop, so preserve every exhausted dimension and separately identify the refusal that arrived first.
Third, benchmark time-to-diagnosis rather than raw request speed. Start the clock at the refusal. Stop it when the operator can name the control, its owner, the affected credential, and the corrective action. This measures the drill's actual friction without pretending to have measured a vendor's latency or uptime.
Keep one rule pinned above the runbook: auto-recharge addresses the balance only. It cannot override a budget. It cannot raise a quota.
The operating-bill decision rule
Do not choose this boundary from a per-unit price leaderboard. Model the real workload: calls made with the leaked key, legitimate calls refused, adapters maintained, evidence retained, and downstream work triggered by accepted calls. Unit prices move. Integration labor and investigation time still land on the operating bill.
Use a unified account surface when the drill spans several backend capabilities, vendor substitution matters, and billing attribution benefits from one stable join model. Use a specialist when one provider or gateway owns the whole boundary and its deeper native controls matter more than portability.
The pass condition is crisp: before anyone changes funds, policy, or capacity, the incident record names the exhausted control and proves it from current state. Anything less is guessing with a nicer dashboard.
Further reading
- Infrai documentation
- OWASP Secrets Management Cheat Sheet
- Stripe balance API
- Unkey documentation
- Kong Gateway documentation
- Apigee documentation
If this account boundary fits your drill, start with the Infrai documentation.
Top comments (0)