Diese Seite ist noch nicht auf Deutsch übersetzt. Es wird das englische Original angezeigt.
Limits and 402
What happens when the balance runs out
MyIP OpenRouter enforces two kinds of limit: how much you can spend (credits) and how often you can call (request rate). The first returns 402, the second 429.
| Limit | What it governs | Error | Where to check |
|---|---|---|---|
| Account balance | What the whole account can spend | 402 insufficient_credits | GET /api/v1/credits |
| Per-key limit | What one API key can spend | 402 key_limit_exceeded | GET /api/v1/key → limit_remaining |
| Request rate | Requests per second | 429 rate_limit_exceeded | Retry-After on the response |
Checking your current limits
curl https://openrouter.myip.co.kr/api/v1/key \
-H "Authorization: Bearer $MYIP_API_KEY"The fields that matter. Every amount is in Korean won (KRW).
limitnumber | nullThe spending cap configured on this key. null means unlimited.
limit_remainingnumber | nullRemaining allowance. null whenever limit is null.
limit_resetstring | nullHow often the cap resets: one of never, daily, weekly, monthly, or null.
usagenumberWhat this key has spent inside the current reset window. With never or null, it is the all-time total.
usage_daily / usage_weekly / usage_monthlySpend today, this week, and this month. Period boundaries are in Asia/Seoul.
The account-wide balance has its own endpoint:
curl https://openrouter.myip.co.kr/api/v1/credits \
-H "Authorization: Bearer $MYIP_API_KEY"{ "data": { "total_credits": 11000, "total_usage": 42.317 } }Your balance is total_credits - total_usage.
402 — insufficient credits
Every request checks the balance before anything is sent upstream.
{
"error": {
"code": 402,
"message": "크레딧이 부족합니다.",
"metadata": { "error_type": "insufficient_credits", "balance_krw": "-5000.000000" }
}
}The 5,000 KRW buffer
We do not cut you off the instant the balance reaches zero. Requests are allowed down to -5,000 KRW.
That buffer exists because of streaming. Several streamed requests can pass the balance check together and then settle one after another as they finish, briefly pushing the balance negative. The buffer absorbs that overshoot.
The boundary is exclusive: at a balance of -5000 or below, the buffer is spent and new requests are rejected with 402.
Zero balance suspends keys
When settlement leaves the balance at zero or below, every active key on that account is automatically moved to suspended_no_credit. Requests with such a key return 402 insufficient_credits.
A successful top-up reactivates them automatically. You do not need to create new keys.
Clearing a 402
- Top up at
/settings/credits. The moment the balance is positive, auto-suspended keys come back. - If you hit a per-key cap (
key_limit_exceeded), raise the limit at/settings/keysor wait for thelimit_resetwindow to roll over. - Watch it proactively — poll
limit_remainingfromGET /api/v1/keyand the balance fromGET /api/v1/credits.
Blocked even after topping up?
There are three distinct key states:
| Key status | Set by | Cleared by | Response |
|---|---|---|---|
suspended_no_credit | System (balance ≤ 0) | Automatically, on top-up | 402 insufficient_credits |
suspended_admin | An administrator | An administrator only | 403 key_suspended |
revoked | You or an administrator | Nobody — permanent | 401 invalid_api_key |
A 403 key_suspended has nothing to do with your balance and will not clear on payment; contact us. A revoked key can never be restored, so issue a new one.
429 — too many requests
Rate limiting is applied per IP address. Splitting traffic across accounts or keys does not raise the limit for the same IP. Traffic that overshoots dramatically is cut off by the reverse proxy before it reaches the application, in which case you get the proxy's error page rather than JSON.
When the application itself rejects the request, the body looks like this:
{
"error": {
"code": 429,
"message": "요청이 너무 잦습니다. 잠시 후 다시 시도하세요.",
"metadata": { "error_type": "rate_limit_exceeded", "retry_after_sec": 60 }
}
}Whenever metadata.retry_after_sec is present, the response also carries a Retry-After header. Back off exponentially, but honour that value first.
When an upstream provider rate-limits us, the error reaches you as 502 provider_error with the provider's original code in metadata.provider_code. In that case model fallbacks or provider routing are usually the better fix.
Hitting a limit mid-stream
Once the first byte is out, the HTTP status can no longer change, so the error arrives as an SSE event instead:
data: {"id":"gen-01J...","object":"chat.completion.chunk","created":1788000000,"model":"lgai/exaone-4.0-32b","provider":"MyIP Local","error":{"code":502,"message":"upstream disconnected","metadata":{"error_type":"provider_error"}},"choices":[{"index":0,"delta":{"content":""},"finish_reason":"error"}]}Stream-reading code must check each chunk for an error key and for finish_reason: "error". See Streaming for worked examples.
Other limits
| Item | Value |
|---|---|
| Upstream response timeout | 600 seconds (then 408 timeout) |
| Request body size | 25 MB |
| Local model start-up budget | 25 seconds by default; then the next candidate, or 503 model_loading if there is none |
| Pending payment orders | 10 per account |
503 model_loading means a local GPU model is still coming up. Wait metadata.retry_after_sec and retry; it usually succeeds. Cold starts are explained in the FAQ.
Error body shape
Every error has the same shape, and the HTTP status always equals error.code.
{
"error": {
"code": 402,
"message": "A human-readable sentence",
"metadata": { "error_type": "insufficient_credits" }
}
}Branch on error.metadata.error_type in code. The message is for humans and its wording can change. The full table is in Errors and debugging.
Zuletzt aktualisiert am 05.09.2026