에러 코드
v1 API 응답의 code 값마다 HTTP 상태와 발생 조건을 정리했어요.
v1 API 응답의 code는 처리 결과를 나타내는 문자열이에요. v2 API의 숫자 코드는 에러 코드를 참고하세요. 오류 응답에서는 data가 null이에요.
{
"code": "INVALID_AMOUNT",
"data": null
}
엔드포인트별로 나올 수 있는 코드는 각 API 페이지에도 적혀 있어요.
성공 (2xx)
code |
HTTP | 설명 |
|---|---|---|
OK |
200 | 요청을 처리했어요. |
CREATED |
201 | 리소스를 만들었어요. |
DELETED |
200 | 리소스를 삭제했어요. |
인증 (401)
code |
HTTP | 설명 |
|---|---|---|
NOT_AUTHORIZED |
401 | Authorization 헤더가 없거나, 키가 틀렸거나, 만료되거나 삭제되거나 비활성화된 키예요. |
권한과 상태 (403)
code |
HTTP | 설명 |
|---|---|---|
INSUFFICIENT_PERMISSIONS |
403 | API 키의 계좌 범위 밖의 주문이나 입금에 접근했거나, 읽기 전용 키로 쓰기 요청을 보냈거나, API 키가 아닌 로그인 토큰으로 요청했어요. |
LIMIT_EXCEEDS_MAXIMUM |
403 | 목록 조회의 limit이 100을 넘었어요. |
INVOICE_ALREADY_PAID |
403 | 이미 결제 완료된 주문을 삭제하거나 결제 완료 처리하려고 했어요. |
BANK_ACCOUNT_NOT_VERIFIED |
403 | 주문의 bankAccountIds에 1원 인증을 마치지 않은 계좌가 있어요. |
리소스 없음 (404)
code |
HTTP | 설명 |
|---|---|---|
INVOICE_NOT_FOUND |
404 | 주문이 없거나 삭제된 주문이에요. |
TRANSACTION_NOT_FOUND |
404 | 입금이 없어요. |
CASH_RECEIPT_NOT_FOUND |
404 | 현금영수증이 없어요. |
BANK_ACCOUNT_NOT_FOUND |
404 | 주문의 bankAccountIds에 없는 계좌 ID가 있어요. |
BUSINESS_INFO_NOT_REGISTERED |
404 | 현금영수증을 발급하려면 대시보드 설정 > 일반에서 사업자 정보를 먼저 등록해야 해요. |
충돌 (409)
code |
HTTP | 설명 |
|---|---|---|
INVOICE_ALREADY_EXISTS |
409 | 입금자명과 금액이 같고 받을 계좌가 겹치는 결제 대기 주문이 이미 있어요. 주문 충돌 규칙을 참고하세요. |
CASH_RECEIPT_NOT_REVOCABLE |
409 | 취소할 수 없는 현금영수증이에요. ISSUED 상태만 취소할 수 있어요. |
검증 실패 (422)
목록 조회
code |
HTTP | 설명 |
|---|---|---|
INVALID_OFFSET |
422 | offset이 0보다 작아요. |
INVALID_LIMIT |
422 | limit이 0 이하예요. |
INVALID_DATE_RANGE_FORMAT |
422 | dateAfter나 dateBefore가 YYYY-MM-DD 형식이 아니에요. |
주문 생성
code |
HTTP | 설명 |
|---|---|---|
INVALID_CUSTOMER_NAME |
422 | customer.name이 1~16자가 아니거나 공백이 있어요. |
INVALID_EMAIL |
422 | customer.email이 5~255자가 아니거나 이메일 형식이 아니에요. |
INVALID_PHONE_NUMBER |
422 | customer.phoneNumber가 숫자 10~11자리가 아니에요. |
INVALID_AMOUNT |
422 | amount가 0 이하예요. |
INVALID_DURATION |
422 | expireAfter를 기간으로 읽을 수 없어요. |
EXPIRE_AFTER_EXCEEDS_MAXIMUM |
422 | expireAfter가 365일을 넘어요. |
METADATA_KEY_VALUE_PAIR_LIMIT_EXCEEDED |
422 | metadata가 5쌍을 넘어요. |
METADATA_KEY_LENGTH_LIMIT_EXCEEDED |
422 | metadata 키가 64자를 넘어요. |
METADATA_VALUE_LENGTH_LIMIT_EXCEEDED |
422 | metadata 값이 1024자를 넘어요. |
INVALID_CASH_RECEIPT_IDENTIFIER |
422 | cashReceipt.identifier가 cashReceipt.type에 맞지 않아요. |
현금영수증 발급
code |
HTTP | 설명 |
|---|---|---|
INVALID_CASH_RECEIPT_IDENTIFIER |
422 | identifier가 type에 맞지 않아요. 소득공제용은 휴대폰 번호나 현금영수증 카드 번호 숫자 10~18자리, 지출증빙용은 사업자등록번호 숫자 10자리예요. |
INVALID_CASH_RECEIPT_AMOUNT |
422 | amount가 1원부터 999,999,999원 사이가 아니에요. |
서버 오류 (5xx)
code |
HTTP | 설명 |
|---|---|---|
INTERNAL_SERVER_ERROR |
500 | 서버에서 오류가 났어요. 잠시 뒤 다시 시도하세요. |
POPBILL_API_FAILED |
500 | 현금영수증 발급 대행사(팝빌) 호출이 실패했어요. 현금영수증 발급과 취소에서 나와요. |
요청 형식 오류 (400)
code |
HTTP | 설명 |
|---|---|---|
BAD_REQUEST |
400 | JSON 본문을 읽을 수 없거나, 필수 본문 필드가 없거나, type, status 같은 열거형 값이 목록에 없거나, paid 같은 불리언 쿼리가 true, false가 아니에요. |
{
"code": "BAD_REQUEST",
"data": null
}
코드 이름 규칙
INVALID_*: 요청 값이 검증을 통과하지 못했어요. 대부분 422예요.*_NOT_FOUND: 리소스가 없어요. 404예요.*_ALREADY_*: 이미 처리된 상태라 다시 처리할 수 없어요. 403이나 409예요.*_EXCEEDS_MAXIMUM,*_LIMIT_EXCEEDED: 허용 범위를 넘었어요.
처리 예시
const res = await fetch(url, options);
const { code, data } = await res.json();
switch (code) {
case "OK":
case "CREATED":
case "DELETED":
return data;
case "NOT_AUTHORIZED":
throw new Error("API 키를 확인하세요.");
case "INVALID_AMOUNT":
case "INVALID_CUSTOMER_NAME":
case "INVALID_EMAIL":
case "INVALID_PHONE_NUMBER":
throw new ValidationError(code);
case "INTERNAL_SERVER_ERROR":
case "POPBILL_API_FAILED":
return retryLater();
default:
// 새로 추가된 코드일 수 있어요. 기록하고 일반 오류로 처리하세요.
logger.warn({ code }, "unknown PaySync code");
throw new Error(`PaySync error: ${code}`);
}