호출 제한
읽기·쓰기 요청 버킷, 각각에 포함되는 요청, 기타 한도와 동시 실행이 별개인 이유를 설명합니다.
호출 제한은 짧은 시간에 보낼 수 있는 요청 수의 상한입니다. 넘으면 API는 작업을 수행하지 않고 429(요청 과다)를 반환하며 대기 시간을 안내합니다. 통제되지 않는 스크립트를 막는 안전장치이며 생성 총량에 대한 할당량은 아닙니다.
한도 한눈에 보기
| 한도 | 기본값 | 도달 시 응답 | 자세한 설명 |
|---|---|---|---|
| 계정별 요청 | 읽기 10초당 1,000회, 쓰기도 별도 동일 한도 | 429와 Retry-After | 아래 |
| 업로드 URL 요청 | 10초당 1,000회 | 429와 Retry-After | 아래 |
| 요청했지만 미사용인 업로드 URL | 파일 128개 또는 1 GiB | 429, 기다려도 해결되지 않음 | 아래 |
| 사용량 보고서 | 분당 30회, 92일 범위 | 429 / 400 | 아래, 과금 |
| 사용 가능 잔액 | — | 40201 | 과금 |
| 키 지출 한도(일·월·누적) | 직접 설정하지 않으면 없음 | 40202 | 과금 |
| 팀 일·월 한도 | 없음 | 40202 | 과금 |
| 소유 팀 수 / 팀별 회원 수 | 10 / 100 | 콘솔 409 | 콘솔과 팀 |
계정별 읽기·쓰기 버킷 두 개
/api/v1/* 전체와 호환 /v1/*·/v1beta/* 엔드포인트의 호출 제한은 키가 아니라 계정별입니다. 키별이면 키를 추가하여 누구나 우회할 수 있기 때문입니다.
읽기와 쓰기는 같은 허용량을 가진 별도 버킷으로 집계됩니다. 기본 보호 임계값은 각각 10초당 1,000회로, 약 100 RPS(초당 요청)의 지속 호출과 1,000회 순간 호출을 허용합니다. 악용이나 통제되지 않는 클라이언트를 막는 높은 수준의 안전장치이며 일반 유료 생성 트래픽을 위한 낮은 할당량이 아닙니다.
고정 시간 창 카운터가 아니라 토큰 버킷입니다. 용량은 1,000이고 10초에 걸쳐 보충됩니다(대략 초당 100토큰). 요청마다 토큰 하나를 사용하고 토큰은 꾸준히 복구됩니다. 고정 시간 창과 달리 경계에서도 보충이 부드럽게 이루어집니다.
읽기와 쓰기는 서로 다른 버킷을 사용합니다
읽기는 모든 GET 요청인 recordInfo, jobs 목록, chat/credit, usage, models와 요청 가격만 산정하는 jobs/quote입니다. 쓰기는 나머지 모두인 createTask, retry, stream, purge, common/upload-url, common/download-url, 호환 chat/completions, messages 및 Gemini 생성 엔드포인트입니다. 네이티브와 호환 엔드포인트는 같은 두 버킷을 공유하므로 텍스트 통합을 /api/v1에서 /v1으로 옮겨도 추가 허용량은 생기지 않습니다.
폴링이 작업 제출을 막지 않습니다. 과도한 폴링은 읽기 버킷만 소진합니다. recordInfo가 429를 반환해도 createTask는 계속 승인될 수 있습니다. 폴링 역시 요청 수를 사용하므로 운영 통합은 불필요한 호출과 지연을 줄이는 webhook을 권장합니다.
모델 카탈로그는 읽기 버킷을 사용합니다. 작업마다 변경되지 않은 스키마를 읽지 말고 갱신 시각을 기준으로 캐시하며 검증 실패 후 새로 읽으세요.
upload-url에는 쓰기 버킷 외에 10초당 1,000회의 별도 안전장치가 있습니다. 객체 저장소의 쓰기 승인을 별도로 보호하며 일반 업로드는 여기에 근접하지 않아야 합니다.
usage는 반대로 읽기 버킷 외에 훨씬 엄격한 분당 30회 한도가 있습니다. 과거 작업을 집계하므로 일반 조회보다 호출 비용이 훨씬 크며 높은 수준의 안전장치만으로는 부족합니다. 정산 대조에 사용하고 폴링에는 사용하지 마세요. 이 버킷은 제한 판단이 불가능해도 요청을 허용하지 않습니다. 다른 버킷은 허용하도록 설정할 수 있지만 이 버킷은 항상 429를 반환합니다.
아직 사용하지 않은 업로드 URL
별도로 계정 하나는 미사용 업로드 URL을 최대 128개 또는 선언된 파일 크기 합계 1 GiB까지 보유할 수 있습니다. 추가 요청은 429와 Too many pending uploads; finish existing uploads before requesting more를 반환하며 Retry-After는 없습니다.
기다려도 해결되지 않으므로 일반 재시도 루프를 반복하지 마세요. 이미 요청한 파일을 업로드하고 확정하면 즉시 자리가 생깁니다. 또는 약 20분 후 업로드 URL이 만료되도록 기다릴 수 있습니다. 대개 스크립트가 URL을 대량 요청하고 사용하지 않을 때 발생합니다. 미디어를 참고하세요.
전체 버킷
한도는 API 영역별로 적용되어 같은 영역이 미들웨어 처리를 공유합니다. API 이용자가 만날 수 있는 버킷은 첫 다섯 개입니다.
| 버킷 | 대상 | 집계 기준 | 기본 허용량 |
|---|---|---|---|
| (네트워크) | 키 확인 이전의 모든 API 요청 | 출발지 IP 주소(IPv6는 /64 네트워크) | 분당 6,000회. 일반 이용량보다 훨씬 높으며 같은 회사 네트워크의 이용자가 공유 |
open_api | /api/v1/*, /v1/*, /v1beta/* 쓰기(jobs/quote를 제외한 GET/HEAD 외 모든 메서드) | 계정 | 10초당 1,000회(지속 약 100 RPS) |
open_api_read | 같은 경로의 GET/HEAD(models 카탈로그 포함)와 jobs/quote 읽기 | 계정 | 10초당 1,000회(지속 약 100 RPS) |
upload_url | /api/v1/common/upload-url | 계정 | 10초당 1,000회(open_api 외 추가) |
api_usage | /api/v1/usage | 계정 | 분당 30회(open_api_read 외 추가) |
| 콘솔 영역 | 인증된 /console/v1/* 엔드포인트 | 계정 | 읽기 분당 120회, 쓰기도 별도 동일 한도 |
catalog | 마케팅 사이트의 익명 공개 카탈로그(/api/v1/models가 아님) | 출발지 IP | 분당 300회 |
키별이 아니라 계정별입니다
open_api와 open_api_read는 계정 단위로 집계합니다. 키를 추가해도 허용량은 늘지 않습니다. 키별이면 콘솔 클릭 한 번으로 제한을 우회할 수 있기 때문입니다.
다만 upload_url과 api_usage는 실제로 별도 버킷입니다. 참조 이미지 업로드는 open_api와 upload_url에서 각각 토큰을 사용하고, usage 읽기는 open_api_read와 api_usage를 사용합니다. 어느 한쪽이 소진되어도 429입니다.
이 수치는 출시 없이 변경할 수 있는 기본값입니다. 현재 허용량은 항상 X-RateLimit-Limit 헤더와 콘솔 개요에 표시됩니다. 헤더를 기준으로 판단하고 기본값을 클라이언트에 하드코딩하지 마세요.
응답 헤더
| 헤더 | 포함되는 응답 | 의미 |
|---|---|---|
X-RateLimit-Limit | 모든 응답 | 현재 시간 창의 허용량 |
X-RateLimit-Remaining | 모든 응답 | 남은 토큰 |
Retry-After | 호출 제한 429 | 대기할 초, 최소 1 |
기본 허용량 계정의 일반 응답은 다음과 같습니다.
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 997X-RateLimit-Remaining은 성공 응답에도 포함되므로 429를 받은 뒤가 아니라 미리 속도를 낮출 수 있습니다.
401에서는 키를 식별하지 못했으므로 이 헤더가 계정 버킷이 아니라 네트워크별 버킷(6000)을 나타냅니다.
제한 응답 예시
{
"code": 429,
"msg": "Too many requests. Retry in a moment",
"request_id": "req_…"
}HTTP 상태는 429이며 Retry-After가 포함됩니다.
한도 초과 요청은 대기열에 넣지 않고 거절합니다
즉시 반환합니다. 대기열에 넣으면 지연이 쌓이고 응답 없는 연결이 생겨 명확한 429보다 처리하기 어렵습니다. 거절된 요청은 승인된 적이 없으므로 비용이 없습니다.
대응 방법
Retry-After를 읽으세요. 고정 간격으로 반복 호출하지 마세요. 예시는 다섯 번 시도 후 중단하여 앞서 설명한 ‘미사용 업로드’ 429에서도 무한 반복을 막습니다.
async function callRespectingLimits(url, init) {
for (let i = 0; i < 5; i++) {
const res = await fetch(url, init);
if (res.status !== 429) return res;
// The server already told you how long to wait; don't guess
const wait = Number(res.headers.get('retry-after') ?? 1);
await new Promise((r) => setTimeout(r, wait * 1000));
}
throw new Error('persistently rate-limited');
}import time, requests
def call_respecting_limits(method: str, url: str, **kwargs) -> requests.Response:
for _ in range(5):
res = requests.request(method, url, **kwargs)
if res.status_code != 429:
return res
# The server already told you how long to wait; don't guess
time.sleep(float(res.headers.get("retry-after", 1)))
raise RuntimeError("persistently rate-limited")동시 실행은 별개입니다
제출 속도를 제한하며 실행 중 작업 수를 제한하지 않습니다
작업이 대기열에 승인되면 호출 제한 허용량을 더 이상 사용하지 않습니다. 백 개가 동시에 생성 중이어도 그것만으로 429가 발생하지 않습니다.
진행 중 작업 수를 실제로 제한하는 요인은 다음과 같으며 모두 호출 제한과는 다릅니다.
- 사용 가능 잔액 — 진행 중 작업마다 금액을 선점합니다. 잔액이 소진되면 새 작업에
40201을 반환합니다. - 지출 한도 — 키의 일·월·누적 한도, 팀 소속 키에 적용되는 팀의 일·월 한도, 플랫폼 일 한도입니다. 하나라도 도달하면
40202입니다. 지출 한도 참조. - 실행 가능 용량 — 모델을 실행할 수 없으면
50301입니다.
따라서 ‘동시에 더 많은 작업을 실행하고 싶다’면 보통 호출 제한을 높이기보다 충전하거나 지출 한도를 올려야 합니다.
한도 상향 요청
현재 허용량은 콘솔 개요에서 확인합니다. 상향은 지원에서 API 통합 주제로 문의하세요. 초당 최대 요청 수, 배치 실행 여부와 최대 배치 크기를 설명하면 검토가 빨라집니다.
그전까지 클라이언트 동시 호출 수를 제한하고 Retry-After를 따르세요. 기본 호출 제한에 맞추려고 동시 실행 수를 인위적으로 낮추기보다 작업량, 생성 시간과 사용 가능 잔액을 기준으로 결정하세요.
제한 기능 자체를 사용할 수 없는 경우
호출 제한은 외부 카운터에 의존합니다. 장애 시 설정에 따라 요청을 허용하여 서비스를 유지하거나, 거절하여 허용량을 보호합니다. 기본값은 거절입니다. ‘설정을 읽지 못했다’가 ‘제한이 없다’로 이어져서는 안 됩니다.
거절 설정에서는 500이 아니라 429와 Retry-After: 1을 받습니다. 의도된 동작입니다. 500은 장애를 의미하며 대부분의 SDK가 즉시 재시도해 사고 중 부하를 늘립니다. 429와 Retry-After는 속도를 낮추고 다시 오라는 뜻으로 이 상황에 맞는 대응입니다.
따라서 429가 반드시 너무 빠르게 호출했다는 증거는 아닙니다. 두 경우 모두 Retry-After를 따르는 것이 올바릅니다.

