사용 한도와 402
잔액이 떨어지면 무슨 일이 일어나는가
MyIP OpenRouter 에는 두 종류의 한도가 있습니다. 얼마나 쓸 수 있는가(크레딧)와 얼마나 자주 부를 수 있는가(요청 빈도)입니다. 전자는 402, 후자는 429 로 돌아옵니다.
| 한도 | 무엇을 제한하나 | 오류 | 어디서 확인하나 |
|---|---|---|---|
| 계정 잔액 | 계정 전체가 쓸 수 있는 금액 | 402 insufficient_credits | GET /api/v1/credits |
| 키별 한도 | 개별 API 키가 쓸 수 있는 금액 | 402 key_limit_exceeded | GET /api/v1/key → limit_remaining |
| 요청 빈도 | 초당 요청 수 | 429 rate_limit_exceeded | 응답의 Retry-After |
지금 한도를 확인하기
curl https://openrouter.myip.co.kr/api/v1/key \
-H "Authorization: Bearer $MYIP_API_KEY"응답의 주요 필드입니다. 금액은 전부 원(KRW) 입니다.
limitnumber | null이 키에 설정된 사용 한도. null 이면 무제한입니다.
limit_remainingnumber | null남은 한도. limit 이 null 이면 이 값도 null 입니다.
limit_resetstring | null한도가 초기화되는 주기. never · daily · weekly · monthly 중 하나이거나 null 입니다.
usagenumber현재 한도 주기 안에서 이 키가 쓴 금액. limit_reset 이 never 이거나 null 이면 전체 누적액입니다.
usage_daily / usage_weekly / usage_monthly오늘·이번 주·이번 달 사용액. 경계는 Asia/Seoul 기준입니다.
계정 전체 잔액은 별도 엔드포인트입니다.
curl https://openrouter.myip.co.kr/api/v1/credits \
-H "Authorization: Bearer $MYIP_API_KEY"{ "data": { "total_credits": 11000, "total_usage": 42.317 } }잔액 = total_credits - total_usage 입니다.
402 — 크레딧 부족
요청을 받으면 업스트림에 보내기 전에 잔액을 먼저 확인합니다.
{
"error": {
"code": 402,
"message": "크레딧이 부족합니다.",
"metadata": { "error_type": "insufficient_credits", "balance_krw": "-5000.000000" }
}
}5,000원의 완충 구간
잔액이 정확히 0이 되는 순간 바로 막지 않습니다. -5,000원까지는 요청을 통과시킵니다.
이 완충 구간은 스트리밍 때문에 있습니다. 여러 스트리밍 요청이 동시에 잔액 검사를 통과한 뒤 각자 끝나면서 정산되면, 마지막 몇 건이 잔액을 잠깐 음수로 만들 수 있습니다. 그 초과분을 흡수하는 값입니다.
경계는 배타적입니다. 잔액이 -5000 이하이면 이미 완충을 다 쓴 것이므로 새 요청이 402 로 거절됩니다.
잔액 0 이하 → 키 자동 정지
정산 직후 잔액이 0 이하가 되면 그 계정의 활성 키 전부가 suspended_no_credit 으로 자동 정지됩니다. 이 상태의 키로 요청하면 402 insufficient_credits 입니다.
충전에 성공하면 자동으로 다시 활성화됩니다. 키를 새로 만들 필요가 없습니다.
402 를 푸는 방법
/settings/credits에서 충전합니다. 잔액이 양수가 되는 순간 자동 정지된 키가 되살아납니다.- 키별 한도에 걸린 것이라면(
key_limit_exceeded)/settings/keys에서 한도를 올리거나,limit_reset주기가 지나기를 기다립니다. - 미리 감시합니다 —
GET /api/v1/key의limit_remaining과GET /api/v1/credits를 주기적으로 확인하세요.
402 인데 충전해도 안 풀린다면
세 가지 키 상태를 구분해야 합니다.
| 키 상태 | 누가 걸었나 | 누가 푸나 | 응답 |
|---|---|---|---|
suspended_no_credit | 시스템 (잔액 0 이하) | 충전하면 자동 복구 | 402 insufficient_credits |
suspended_admin | 관리자 | 관리자만 | 403 key_suspended |
revoked | 사용자 또는 관리자 | 아무도 풀 수 없음 (영구) | 401 invalid_api_key |
403 key_suspended 를 받았다면 잔액과 무관합니다. 충전해도 풀리지 않으니 문의해 주세요. 폐기(revoked)한 키는 되살릴 수 없으므로 새 키를 발급하셔야 합니다.
429 — 요청이 너무 잦음
요청 빈도 제한은 IP 주소 단위로 걸립니다. 계정이나 키를 나눠도 같은 IP 라면 같은 한도를 공유합니다. 아주 심하게 초과하는 트래픽은 애플리케이션에 닿기 전에 리버스 프록시가 먼저 끊습니다 — 이때는 JSON 이 아니라 프록시의 오류 페이지가 돌아옵니다.
애플리케이션이 직접 거절할 때는 다음 형식입니다.
{
"error": {
"code": 429,
"message": "요청이 너무 잦습니다. 잠시 후 다시 시도하세요.",
"metadata": { "error_type": "rate_limit_exceeded", "retry_after_sec": 60 }
}
}metadata.retry_after_sec 가 있으면 응답에 Retry-After 헤더도 함께 나갑니다. 지수 백오프로 재시도하되 이 값을 우선 존중하세요.
업스트림 provider 가 자기 쪽 한도에 걸려 429 를 준 경우에는 502 provider_error 로 감싸 metadata.provider_code 에 원래 코드를 실어 보냅니다. 이때는 모델 폴백 이나 Provider 라우팅 으로 다른 후보를 태우는 편이 낫습니다.
스트리밍 도중에 한도에 걸리면
첫 바이트를 보낸 뒤에는 HTTP 상태를 바꿀 수 없습니다. 그래서 오류가 SSE 이벤트로 도착합니다.
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"}]}스트림을 읽는 코드는 각 청크에 error 키가 있는지, finish_reason 이 "error" 인지 확인해야 합니다. 자세한 예제는 스트리밍 에 있습니다.
그 밖의 한도
| 항목 | 값 |
|---|---|
| 업스트림 응답 타임아웃 | 600초 (초과 시 408 timeout) |
| 요청 본문 크기 | 25MB |
| 로컬 모델 기동 대기 예산 | 기본 25초 (초과 시 다음 후보로 폴백, 폴백이 없으면 503 model_loading) |
| 대기 중인 결제 주문 | 계정당 10건 |
503 model_loading 은 로컬 GPU 모델이 아직 올라오는 중일 때 나옵니다. metadata.retry_after_sec 만큼 기다렸다가 다시 부르면 대개 성공합니다. 콜드 스타트에 대한 설명은 자주 묻는 질문 을 보세요.
오류 본문 형식
모든 오류는 같은 형식입니다. HTTP 상태 코드와 error.code 는 항상 같습니다.
{
"error": {
"code": 402,
"message": "사람이 읽을 수 있는 설명",
"metadata": { "error_type": "insufficient_credits" }
}
}프로그램은 error.metadata.error_type 으로 분기하세요. message 는 사람이 읽으라고 있는 것이고 문구가 바뀔 수 있습니다. 전체 목록은 오류와 디버깅 에 있습니다.
마지막 수정 2026. 9. 5.