오류
모든 4xx/5xx 응답은 동일한 JSON envelope를 가집니다.
{
"code": 400,
"message": "invalid_input",
"details": [
{ "field": "items[0].unit_price", "message": "must be a positive decimal string" }
]
}code— 숫자 HTTP 상태(400,401,404, …). 일반 HTTP 레이어 처리에는 유용하지만, 분기 로직에는 대신message로 분기하세요 —code는 예를 들어invalid_input과payment_method_not_supported(둘 다 400)를 구분하지 못합니다.message— 소문자 스네이크 케이스로 표기한 센티넬 이름 (예:INVALID_INPUT은"invalid_input"이 됩니다). 릴리스 간 안정적 입니다 — 이것으로 분기하세요.details— 검증 오류 시 채워집니다. 클라이언트가 오류를 입력에 매핑할 수 있도록{ field, message }객체 배열입니다. 그 외에는 생략됩니다.
오류 본문에는 trace ID나 타임스탬프가 포함되지 않습니다. 문제를 신고할 때는
응답 Date 헤더, X-RateLimit-* 헤더, 가맹점 ID, 엔드포인트, 대략적인 요청
시각을 지원팀에 보내세요.
인증 실패는 다른 형식을 사용합니다. 위의 envelope는 대부분의 오류에서
API가 반환하는 형식입니다. 처리되기 전에 거부된 요청(/b2b/v1/* 호출에서
누락/잘못된 X-Signature, 알 수 없는 X-Client-ID, 또는 오래된
X-Timestamp)은 { "error": "...", "message": "..." } 형태로 돌아옵니다.
여기서 error는 거친 슬러그(unauthorized / bad_request /
service_unavailable)이고 message는 세부 사항을 전달합니다. 숫자 code도,
details도 없습니다. 먼저 HTTP 상태로 분기한 다음 message를 읽으세요.
예시(401):
{ "error": "unauthorized", "message": "invalid signature" }HTTP 상태 → 일반적인 코드
| HTTP | 일반적인 code 값 | 의미 |
|---|---|---|
| 400 | INVALID_INPUT, MISSING_REQUIRED, INVALID_FORMAT, INVALID_LENGTH, INVALID_VALUE, PAYMENT_METHOD_NOT_SUPPORTED, AMOUNT_BELOW_MINIMUM | 잘못된 요청 — details를 확인 |
| 401 | INVALID_CREDENTIALS, INVALID_TOKEN, TOKEN_EXPIRED, INVALID_SIGNATURE (B2B); SESSION_EXPIRED (대시보드만) | 인증 실패 — 잘못된 키, 만료된 타임스탬프, 잘못된 서명. 대시보드 로그인 코드는 B2B 통합과 무관합니다. |
| 402 | INSUFFICIENT_CREDIT | 가맹점 선불 잔액 소진 — 재시도 전 충전 필요 |
| 403 | FORBIDDEN, IP_BLOCKED | 키는 유효하지만 이 호출에 대한 스코프/IP 허용 권한 없음 |
| 404 | NOT_FOUND, RECORD_NOT_FOUND | 리소스가 존재하지 않음(또는 가맹점에 대해 존재하지 않음) |
| 409 | ALREADY_EXISTS | 다른 본문으로 멱등성 재시도, 또는 상태 머신이 전이를 거부함 |
| 429 | TOO_MANY_REQUESTS, TOO_MANY_ATTEMPTS | 레이트 리밋 도달. 백오프 후 재시도 |
| 500 | INTERNAL_SERVER_ERROR, EXTERNAL_SERVICE_ERROR | 저희 측 문제. 백오프로 재시도 안전. |
| 503 | SERVICE_UNAVAILABLE | 다운스트림 종속성 다운. 백오프 후 재시도 |
전체 코드 레퍼런스
볼 수 있는 code 값:
인증 (401)
INVALID_CREDENTIALS— API 키 조합 거부됨INVALID_TOKEN— 토큰이 파싱 불가하거나 변조됨TOKEN_EXPIRED— 토큰 만료SESSION_EXPIRED— 대시보드 세션 만료INVALID_SIGNATURE— B2B / 웹훅 호출의 HMAC 서명 불일치
권한 (403)
FORBIDDEN— 인증되었지만 이 작업을 수행할 권한이 없음IP_BLOCKED— 이 IP 주소의 요청이 차단됨
찾을 수 없음 (404)
NOT_FOUND— 일반RECORD_NOT_FOUND— 주어진 ID에 대한 행 누락
충돌 (409)
ALREADY_EXISTS— 일반
검증 (400)
INVALID_INPUT— 일반.details확인MISSING_REQUIRED— 필수 필드 누락INVALID_FORMAT— 값이 예상 형식과 일치하지 않음(예: UUID, URL, email)INVALID_LENGTH— 값이 너무 짧거나 너무 길음INVALID_VALUE— 값이 허용된 enum/범위를 벗어남PAYMENT_METHOD_NOT_SUPPORTED— 제공자/자산 조합이 가맹점에 활성화되지 않음AMOUNT_BELOW_MINIMUM— 주문 금액이 네트워크별 또는 env 레벨 하한선 미만. 응답의details.floor_usd에 구성된 하한선(USD)이 담겨 있으므로 바로 노출할 수 있습니다 —message텍스트에도 동일한 내용이 표시됩니다.INSUFFICIENT_BALANCE— 구매자 지갑이 전송 결제 자산을 충분히 보유하고 있지 않음.INSUFFICIENT_GAS— 구매자 지갑에 전송을 브로드캐스트할 네이티브 토큰(네트워크 수수료용)이 부족함.
결제 / 청구 (402)
INSUFFICIENT_CREDIT— 가맹점 선불 잔액으로 네트워크 수수료(가스)와 플랫폼 수수료를 커버할 수 없음. 대시보드에서 충전 후 재시도
레이트 리밋 (429)
TOO_MANY_REQUESTS— IP 레이트 리밋 초과TOO_MANY_ATTEMPTS— 동일 리소스에 반복된 실패 시도(예: OTP)가 스로틀 발동
서버 오류 (500)
EXTERNAL_SERVICE_ERROR— 서드파티 제공자 실패INTERNAL_SERVER_ERROR— 예상치 못한 오류. 응답Date헤더와X-RateLimit-*헤더를 지원팀에 전달하여 문의
가용성 (503)
SERVICE_UNAVAILABLE— 서비스를 일시적으로 사용할 수 없음. 백오프 후 재시도
검증 오류 (400)
문제가 잘못된 요청 본문인 경우 details는 배열이므로 오류를 필드에 다시
매핑할 수 있습니다.
{
"code": 400,
"message": "invalid_input",
"details": [
{ "field": "items[0].unit_price", "message": "must be a positive decimal string" },
{ "field": "success_url", "message": "must be a valid https URL" }
]
}인증 오류 (401)
INVALID_SIGNATURE의 일반적인 원인은 세 가지입니다.
- 잘못된 시크릿 키(env 변수 재확인)
- 타임스탬프 드리프트 > 5분(NTP 동기화)
- 잘못된 정규 문자열(가장 흔한 경우:
\n구분자 누락, 또는 보낸 것과 다른 파싱-후-재문자열화된 본문 서명)
정확한 서명 알고리즘은 인증을 참조하세요.
레이트 리밋 (429)
| 표면 | 제한 |
|---|---|
모든 API 경로(/b2b/v1/* 포함) | IP 주소당 — 500 req/min, 공유 버킷. 가맹점당이 아님. |
공개 체크아웃(/checkout/*) | 더 엄격한 서브 버킷 — IP당 20 req/min |
X-RateLimit-Limit과 X-RateLimit-Remaining은 레이트 리밋이 적용된 모든
응답(성공 응답뿐 아니라)에 포함됩니다. IP에 대한 실시간 예산으로 다루세요.
레이트 리밋 응답은 Retry-After 헤더(윈도우가 재설정될 때까지의 초)를
포함합니다 — 이를 준수하세요. 폴백으로 지터를 사용한 백오프 — 1s 베이스 +
30s까지 지수적 증가 — 를 적용하세요.
레이트 리밋은 변경될 수 있습니다. 정상적인 트래픽으로 한도에 도달하는 경우(예: 큰 과거 범위 리컨실리에이션), 지원팀에 문의하세요.
잔액 부족 (402)
INSUFFICIENT_CREDIT(HTTP 402 Payment Required)는 선불 잔액이
수행하려는 작업에 대한 네트워크 수수료(가스)와 플랫폼 수수료를 커버할 수 없음을
의미합니다. 일반적으로 암호화폐 결제 정산 또는 네트워크 수수료를 후원하는 온체인
작업에서 발생합니다. 가맹점 대시보드(Billing → Add credit)에서 충전한 후
작업을 재시도하세요. 이미 진행 중인 작업은 잔액이 충전되면 자동으로 이어집니다.
서버 오류 (5xx)
500은 요청을 처리할 수 없었음을 의미합니다. 백오프로 재시도하세요 —
idempotency_key는 원래 요청이 부분적으로 성공했더라도 이중 청구를
방지합니다.
재시도가 1분 이내에 회복되지 않으면 구매자에게 일반적인 “결제 일시
사용 불가” 메시지를 노출하고 실패한 엔드포인트, 가맹점 ID, 응답 Date
헤더와 X-RateLimit-* 값, 대략적인 요청 시간을 지원팀에 문의하세요 —
이는 저희가 해당 요청을 찾기에 충분합니다.
웹훅 전달 오류
웹훅 전달은 별도의 실패 채널입니다 — 호출하는 것이 가맹점 서버가 아니므로 API 오류로 노출되지 않습니다. 전달이 non-2xx를 반환하거나 타임아웃되면, 0s, 1min, 5min, 15min, 1h, 6h(총 6회 시도 — 웹훅 → 개요와 동일한 스케줄)에서 지수 백오프로 재시도됩니다. 전달별 전체 이력은 대시보드의 Developers → Webhooks → [endpoint] → Delivery log 패널에 표시됩니다. 여섯 번째 시도가 실패하면 대시보드에서 해당 전달이 “Failed”로 표시되며, 서버가 정상화된 후 수동으로 재생할 수 있습니다.