Rate Limits
이벗 API 의 요청 제한은 게이트웨이의 초당 속도 제한(IP 단위)과 인증키의 월 호출 한도(계정 단위) 두 단계로 나뉩니다. 둘 다 HTTP 429 를 반환하지만 응답 형식이 서로 다르므로 구분해 처리하셔야 합니다. 운영(live) 인증키와 JWT 에는 월 호출 한도가 적용되지 않습니다.
제한은 두 단계로 적용됩니다
| 단계 | 제한 단위 | 제한 | 적용 대상 |
|---|---|---|---|
| ① 게이트웨이 일반 API |
출발지 IP 당 초당 요청 수 | IP 당 30 req/s (순간 버스트 50) | /v3/ 전체 — 인증 방식과 무관하게 적용됩니다. |
| ① 게이트웨이 MCP API |
출발지 IP 당 초당 요청 수 | IP 당 10 req/s (순간 버스트 10) | /v3/mcp/ 전용 — 일반 경로보다 엄격합니다. |
| ② 인증키 | 계정 당 월 누적 호출 수 | 아래 표 참조 | 테스트(test) API Key 로 호출한 요청만 |
error.code 도 모두
RATE_LIMIT_EXCEEDED 입니다. 다만 게이트웨이가 차단한 429 에는
Retry-After 와 X-RateLimit-* 헤더가 붙지 않습니다.
Retry-After 유무로 어느 쪽인지 구분하실 수 있습니다 —
없으면 속도 제한(곧 회복), 있으면 월 한도 소진(재시도로 해결되지 않음)입니다.
셀러 입장에서 무슨 뜻인가요?
게이트웨이 제한은 인증키가 아니라 호출하는 서버의 공인 IP 를 기준으로 셉니다. 인증키를 몇 개 쓰시든, 어느 서비스를 호출하시든 같은 IP 에서 나간 요청은 하나로 합산됩니다.
| 호출 환경 | 적용되는 방식 |
|---|---|
| 서버 1대에서 호출 | 그 서버의 공인 IP 하나로 잡혀 초당 30요청을 씁니다. |
| 서버 여러 대에서 호출 | 서버마다 공인 IP 가 다르면 각 IP 별로 독립된 한도가 적용됩니다. 호출을 분산하시면 그만큼 여유가 생깁니다. |
| 여러 서버가 같은 NAT·프록시를 통해 나감 | 밖에서는 IP 가 하나로 보이므로 모두 합쳐 초당 30요청입니다. 서버를 늘려도 한도는 늘지 않습니다. |
월 호출 한도 (인증 방식별)
| 인증 / 환경 | 제한 | 비고 |
|---|---|---|
| API Key — 테스트(test) | 월 1,000회 | 계정 단위로 합산합니다. 인증키를 여러 개 발급하셔도 한도는 하나입니다. |
| API Key — 운영(live) | 월 한도 없음 | 호출량은 집계하지만 차단하지 않습니다. 공정 사용에 관하여는 이용약관 제28조를 따릅니다. |
| JWT | 월 한도 없음 | 내부 서비스 연동용입니다. |
응답 헤더로 잔여 확인
한도가 적용되는 요청의 응답에는 현재 사용량을 알려주는 헤더가 포함됩니다.
| 헤더 | 의미 |
|---|---|
X-RateLimit-Limit | 이번 달 허용량 (예: 1000) |
X-RateLimit-Remaining | 이번 달 남은 호출 수 |
X-RateLimit-Reset | 한도 초기화 시각 — 다음 달 1일 00:00 (Unix epoch 초) |
Retry-After | 429 응답에만 포함. 대기 권장 초 |
-1 이나 unlimited 같은 값을 대신 넣지 않습니다 —
없는 것보다 틀린 값이 나쁘기 때문입니다.
헤더가 없을 때를 대비해 parseInt 결과를 그대로 쓰지 마시고
값이 있을 때만 사용하도록 작성해주세요.
429 응답 처리
① 게이트웨이 속도 제한 초과
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "요청 한도를 초과했습니다."
}
}
Retry-After · X-RateLimit-* 헤더가 없습니다.
초당 요청 수를 줄이고 지수 백오프로 재시도하세요.
버스트를 넘긴 순간에만 발생하므로 대개 수백 밀리초 안에 회복됩니다.
② 월 호출 한도 초과 (테스트 인증키)
HTTP/1.1 429 Too Many Requests
Retry-After: 1987200
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1718352000
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "이번 달 호출 한도(1,000회)를 초과했습니다. 다음 달 1일에 초기화됩니다."
}
}
이쪽은 재시도로 해결되지 않습니다. 다음 달 1일에 초기화되거나
운영(live) 인증키로 전환하셔야 합니다. Retry-After 값이
수십만 초인 이유가 이것입니다.
Node.js 재시도 예시
async function callWithRetry(url, options, maxRetry = 3) {
for (let i = 0; i < maxRetry; i++) {
const res = await fetch(url, options);
if (res.status !== 429) return res;
// 429 — Retry-After 만큼 대기 (없으면 지수 백오프)
const wait = res.headers.get("Retry-After");
const ms = wait ? parseInt(wait) * 1000 : Math.pow(2, i) * 1000;
await new Promise(r => setTimeout(r, ms));
}
throw new Error("Rate limit retry exhausted");
}
모범 사례
1. 지수 백오프 (Exponential Backoff)
429 응답을 받으면 즉시 재시도하지 말고, 대기 시간을 점차 늘려가며 재시도하세요. 여러 클라이언트가 동시에 차단됐다가 한꺼번에 재시도하는 "썬더링 허드" 문제를 방지할 수 있습니다.
대기 시간: 1초 → 2초 → 4초 → 8초 → 16초 ... (최대 60초)
지터 추가: ±20% 랜덤 가산 (동시 재시도 분산)
2. 배치 호출 활용
같은 종류 데이터를 N개 가져올 때는 개별 호출 대신 페이징을 활용하세요.
- ❌
GET /orders/{id}× 100번 - ✅
GET /orders?size=100&date_from=...1번
3. 캐싱
자주 변하지 않는 데이터(상품 마스터, 공급사 정보 등)는 클라이언트에 캐싱하여 호출 자체를 줄이세요. 일반적인 TTL 기준:
- 상품 / 옵션 / 공급사: 30분 ~ 1시간
- 주문 목록: 30초 ~ 1분 (실시간성 필요)
- 재고 수량: 캐싱 비권장 (실시간)
4. 비동기 큐
대량 호출(수천 건 일괄 동기화)은 동기적으로 한 번에 처리하지 말고 작업 큐(예: BullMQ, Sidekiq, Celery)에 분산시켜 월 한도 안에서 순차 처리하세요.
5. 변경 감지 후 호출 (Polling 최소화)
같은 endpoint 를 짧은 주기로 반복 호출(polling)하지 마세요.
updated_after 같은 변경 시각 필터를 활용해 새로 변경된 데이터만 가져오는 것이 한도와 부하 면에서 유리합니다.
한도 초과 모니터링
반복적으로 429 를 받는 경우 다음을 확인하세요.
- 여러 프로세스(또는 컨테이너)가 동일 키로 동시 호출하고 있지 않은지
- 예기치 못한 무한 루프 / 재시도 폭주가 없는지 (로그·모니터링 확인)
- 현재 요금제 한도가 운영 부하에 맞는지 (Pricing 검토)