파트너 API (B2B)
오류와 요청 한도
파트너 API 오류 코드, 키당 요청 한도와 X-RateLimit 헤더, 재시도 방법이에요.
오류 응답 형식#
오류 본문은 { statusCode, code, message } 예요. message 는 사람이 읽는 영어 문구라 바뀔 수 있으니 항상 code 로 분기하세요.
json
// Success
{ "success": true, "data": ..., "total": 128, "page": 1, "limit": 20 }
// Error
{ "statusCode": 401, "code": "INVALID_API_KEY", "message": "The API key is invalid." }참고
쿼리 값 검증 오류(400)는 표준 형식 { statusCode: 400, message: [...], error: "Bad Request" } 로 오고 code 가 없어요.
오류 코드#
| HTTP | code | 의미와 대처 |
|---|---|---|
| 401 | API_KEY_REQUIRED | 키를 보내지 않음 — X-API-Key 헤더를 넣으세요 |
| 401 | INVALID_API_KEY | 형식이 틀리거나 없는 키 — 복사가 잘렸는지, 공개 API 키를 넣지 않았는지 확인 |
| 401 | KEY_REVOKED | 폐기된 키 — 새 키를 발급하세요 |
| 401 | KEY_EXPIRED | 만료된 키 (교체 유예가 끝난 옛 키 포함) — 새 키를 쓰세요 |
| 403 | PARTNER_SUSPENDED | 계정이 정지됨 — 이심모아에 문의하세요 |
| 403 | INSUFFICIENT_SCOPE | 키 권한 범위 밖의 요청 |
| 403 | IP_NOT_ALLOWED | 허용 IP 목록 밖에서 호출 — 서버 egress IP 를 추가하세요 |
| 404 | PRODUCT_NOT_FOUND | 없거나 판매가 끝난 상품 |
| 429 | RATE_LIMITED | 요청 한도 초과 — Retry-After 초 뒤 재시도 |
요청 한도#
참고
기업용 API는 키별로 기본 시간당 20,000회까지 요청할 수 있습니다.
첫 요청부터 3,600초 동안 집계하며 기존 분당 제한도 함께 적용합니다. 이는 전송량(MB)이 아닌 요청 횟수 제한입니다. 운영 설정에 따라 실제 한도가 달라질 수 있습니다.
X-RateLimit-Hour-Limit · X-RateLimit-Hour-Remaining · X-RateLimit-Hour-Reset
위 헤더는 시간당 한도·남은 횟수·초기화 시각(Unix 초)을 나타냅니다. 시간당 한도 초과 시 HTTP 429와 Retry-After(재시도까지 기다릴 초)를 반환합니다. 분당 제한에서 거부된 요청은 시간당 집계에 포함되지 않습니다.
키마다 분당 300회가 기본이에요 (60초 창 단위, 모든 서버가 공유). 계약에 따라 이심모아가 계정별로 올려 드릴 수 있어요. 인증을 통과한 모든 응답에 남은 횟수 헤더가 붙어요.
X-RateLimit-Limit— 분당 허용 횟수X-RateLimit-Remaining— 이번 창에서 남은 횟수X-RateLimit-Reset— 창이 초기화되는 시각 (Unix 초)Retry-After— 429 일 때 다시 시도하기까지 기다릴 초
http
HTTP/1.1 200 OK
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57
X-RateLimit-Reset: 1790000000
HTTP/1.1 429 Too Many Requests
Retry-After: 18
{ "statusCode": 429, "code": "RATE_LIMITED", "message": "Rate limit exceeded (300 requests per minute)." }재시도#
- 429 는 Retry-After 만큼 기다렸다가 재시도하세요.
- 5xx 는 지수 백오프로 몇 번만 재시도하세요.
- 400·401·403·404 는 재시도해도 결과가 같아요 — 원인을 고치세요.
- 카탈로그는 몇 분 단위로 캐시하면 한도에 거의 닿지 않아요.
javascript
async function b2bFetch(url, attempt = 0) {
const res = await fetch(url, { headers: { 'X-API-Key': process.env.ESIMOA_PARTNER_KEY } });
if (res.status === 429 && attempt < 3) {
const wait = Number(res.headers.get('Retry-After') ?? 1);
await new Promise((r) => setTimeout(r, wait * 1000));
return b2bFetch(url, attempt + 1);
}
const body = await res.json();
if (!res.ok) throw Object.assign(new Error(body.message), { code: body.code, status: res.status });
return body;
}