Short answer: On AICredits every inference key can carry an INR budget (over budget means HTTP 402) and a per-minute request limit (over it means 429), and teams let you give each member a rupee allocation from your wallet. Use one key per project, always set a budget, and handle 402 and 429 differently in code.
Disclosure: the aicredits.in links are affiliate links and I use the service. Limits are taken from AICredits' docs as read on 16 Oct 2026; the code is untested against the live API and labelled as such.
A loop with a bad exit condition does not care that your wallet is shared with three other services. One runaway worker, a leaked key in a public repo, or an enthusiastic intern with a long-context habit can drain a prepaid balance in an afternoon. The fix is cheap and boring: split keys, cap each one, and decide in advance what your code does when the cap bites.
This post lays out the controls, the numbers the docs state, a policy table, and a script that turns a plan into keys.
Which controls does AICredits give you?
| Control | Scope | Fails with |
|---|---|---|
| Per-key INR budget | One inference key | HTTP 402 |
| Per-key RPM limit | One inference key | HTTP 429 |
| Concurrency cap | Per user | HTTP 429 (concurrency message) |
| Team member allocation | One member of a team | Budget-exceeded error on their key |
| Key expiry | One key | Request refused after expiry |
| Wallet balance | Whole account | HTTP 402 when empty |
Budgets bound money. Rate limits bound speed. Neither replaces the other: a slow loop still drains a wallet, and a fast but cheap loop can still hammer your latency budget.
What are the exact limits?
From the rate-limits documentation:
- RPM per key: you set it from 1 up to 10,000; anything above is rejected with a
400. The dashboard form suggests 1,000 RPM. A key created through the API withoutrate_limitgets 10,000. Editing a key without sendingrate_limitkeeps the current value. - Window: a rolling one-minute window backed by Redis.
- Concurrency: default of 5 simultaneous requests per user.
- Headers on every response:
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset(seconds until the window resets). - Management keys (
akm-) have their own limit, 60 RPM by default. These are for the control plane, not inference.
Two things in the docs don't line up neatly, so I'm flagging them rather than smoothing them over. The management API page says a key created through it has rate_limit capped at 600 RPM and budget must be above zero, while the rate-limits page says 10,000 as the maximum. And a summary file elsewhere on the site mentions 60 RPM as a default. My reading is that the caps differ by creation path and that 60 is the management-key default, but I have not tested it. Read the X-RateLimit-Limit header on a real response from your own key; that is the number that counts.
How do budgets behave in practice?
The key's cumulative usage is compared with its INR budget. When usage exceeds it, requests fail with 402. The monitoring docs describe the same behaviour and say you can raise or reset it from Dashboard, then API Keys. Through the management API, PATCH with "budget": 0 means unlimited, so be careful: a zero is not a zero cap.
Practical rules I'd apply:
- Every key gets a budget, including your own dev key.
- Set the budget to what the task should cost times a safety factor, not to "whatever is in the wallet".
- Production keys get a budget that comfortably covers a month; development keys get a small one.
- Put an alert on the wallet too. The low-balance alert fires below ₹10, which is late for production.
For the cost side of the sums, use the cost-per-1000-requests worked examples and the formula in the AICredits review: provider USD price x live USD/INR x 1.05 x 1.05.
How do teams and member caps work?
Teams let a wallet owner allocate part of the wallet to other people. The docs describe it this way: the owner creates a team and invites a member by email with a rupee cap; the member makes API calls that are charged to the owner's wallet; the owner can see per-member usage and adjust or reclaim the allocation. At the cap, the member's key returns a budget-exceeded error, so your wallet is not overdrawn beyond what you committed. Unused allocation costs you nothing.
Two behaviours matter if you script this:
- Inviting does not send an email or create an account. The person must sign up with that exact address to be linked.
- Repeated invites add to the allocation unless you send an
Idempotency-Keyheader or use the absolute form ({"set": true, "amount_inr": 200}). Allocation can never drop below what the member has already spent.
Teams are a fit for students, contractors and interns. For a product, use separate keys instead, since a key is the unit your code carries.
How should your code handle 402 versus 429?
They need opposite reactions. A 429 is transient: back off and retry. A 402 is a budget decision: retrying burns time and fixes nothing.
This helper separates them. It is untested against the live API, and I have not confirmed the exact error body, so it relies only on the HTTP status:
import os
import random
import time
from openai import OpenAI, APIStatusError, RateLimitError
client = OpenAI(
api_key=os.environ["AICREDITS_API_KEY"],
base_url="https://api.aicredits.in/v1",
)
class BudgetExhausted(RuntimeError):
"""Key budget or wallet is empty. Do not retry; alert a human."""
def chat(messages, model, max_retries=4):
for attempt in range(max_retries):
try:
return client.chat.completions.create(model=model, messages=messages, max_tokens=512)
except RateLimitError: # 429: rate or concurrency limit
if attempt == max_retries - 1:
raise
time.sleep((2 ** attempt) + random.uniform(0, 1))
except APIStatusError as e:
if e.status_code == 402:
raise BudgetExhausted("402: key budget or wallet exhausted") from e
raise
For a fuller retry strategy, including timeouts and fallback models, see gateway retry, timeout and fallback patterns and the general rate limits and backoff guide. Agents need a second line of defence beyond the gateway, which token budgeting for agents covers, and the agent design lesson frames why.
A key plan: policy table to script
Decide the plan first, in a table anyone can read:
| Key name | Owner | Environment | Budget (INR) | RPM | Notes |
|---|---|---|---|---|---|
| support-bot-prod | Priya | prod | 3000 | 120 | Alerts at 80% |
| support-bot-dev | Priya | dev | 200 | 30 | Reset monthly |
| batch-summaries-prod | Arjun | prod | 1500 | 60 | Off-peak runs only |
| intern-sandbox | team cap | dev | 150 | 20 | Via team allocation |
The numbers above are placeholders to show the shape; pick yours from your own traffic. Then turn the plan into keys with the beta management API. The script below is untested: it follows the documented POST /api/v1/mgmt/keys request (name, budget, rate_limit) and the optional Idempotency-Key header, needs an akm- key with keys:write, and prints each secret once because the API returns it once.
import os
import requests
BASE = "https://api.aicredits.in/api/v1/mgmt"
MGMT = os.environ["AICREDITS_MGMT_KEY"] # akm- key with keys:write
PLAN = [
{"name": "support-bot-prod", "budget": 3000, "rate_limit": 120},
{"name": "support-bot-dev", "budget": 200, "rate_limit": 30},
{"name": "batch-summaries-prod", "budget": 1500, "rate_limit": 60},
]
def create_key(entry):
r = requests.post(
f"{BASE}/keys",
headers={
"Authorization": f"Bearer {MGMT}",
"Content-Type": "application/json",
"Idempotency-Key": f"plan-2026-10-{entry['name']}",
},
json=entry,
timeout=30,
)
r.raise_for_status()
return r.json()["api_key"]
for entry in PLAN:
assert entry["budget"] > 0, "budget must be above zero"
assert entry["rate_limit"] <= 600, "management API caps rate_limit at 600"
secret = create_key(entry)
print(entry["name"], "->", secret[:12] + "...") # store the full value in your secret manager
Re-running with the same idempotency key and body replays the cached response for 24 hours instead of creating a duplicate, which is the main reason to send one. Never print full secrets into CI logs; the truncation above is for the demo. More patterns, including rotation, are in the management API post.
What about leaks and shared keys?
A budget is also your blast-radius limit if a key leaks. Combine it with the habits in the API key leak prevention checklist: environment variables, no keys in client code, and revocation when owners leave. If you evaluate self-hosted alternatives for budgets and virtual keys, the LiteLLM proxy comparison shows what you would run yourself.
A monthly review checklist
- Export usage per key and compare with each budget.
- Raise budgets only with a named reason; lower any key that never exceeded 30% of its cap.
- Revoke keys whose owner has left.
- Confirm the RPM header on a real response from each production key.
- Check wallet balance against the next month's forecast and top up with the UPI flow.
Bottom line
Caps are the cheapest insurance you can buy for LLM spend. One key per project, a rupee budget on every key, separate handling for 402 and 429, and team allocations for people rather than services. If you do not yet have an account, create one and set the first key's budget before you paste it anywhere.



