본문 바로가기
빌링플러스개발자센터
홈 로그인 도입 상담

API 규약

에러 응답

표준 에러 형식과 HTTP 상태, 에러 코드별 원인과 해결 방법.

에러는 모든 엔드포인트에서 같은 모양으로 옵니다. 분기는 error.code 로 하세요. message 는 사람이 읽는 한국어 문구라 바뀔 수 있습니다.

형식

에러 본문
{
  "error": {
    "code": "UNPROCESSABLE",
    "message": "확정된 청구서만 결제할 수 있습니다. 현재 상태: 작성중",
    "detail": {"invoice_status": "DRAFT"},
    "request_id": "req_4f1c9a2b7d3e5f60a1b2c3d4"
  }
}
  • request_id 는 응답 헤더 X-Request-Id 에도 있습니다. 성공 응답에도 붙습니다. 로그에 남겨 두고, 문의할 때 알려 주세요.
  • detail 은 코드마다 내용이 다릅니다. 비어 있으면 {} 입니다.
  • 결제사가 보낸 원래 코드는 그대로 내보내지 않습니다. 결제사를 바꿔도 가맹점 코드가 깨지지 않게 하기 위해서입니다.

HTTP 상태

상태뜻
200 · 201처리됨. 결제 거절도 200 입니다(아래).
400요청 형식 오류 — 필드 누락·형식 틀림·없는 메서드(405 도 이 형식으로)
401인증 실패(이유는 알리지 않음)
403허용 IP 밖에서 호출
404없는 자원, 또는 없는 API 경로. 다른 가맹점의 자원도 404 입니다(존재 여부를 알리지 않습니다).
405그 경로가 받지 않는 메서드. 본문 코드는 INVALID_REQUEST, Allow 헤더와 detail.allowed_methods 에 받는 메서드가 옵니다.
409같은 멱등키의 요청이 처리 중이거나, 같은 수시결제 동의로 다른 결제가 처리 중
422형식은 맞지만 지금 상태에서 할 수 없는 일, 또는 멱등키 재사용
429분당 호출 한도 초과
500 · 503빌링플러스 쪽 오류·일시 장애. 503 은 Retry-After 가 붙습니다.

에러 코드

code상태원인과 할 일
UNAUTHORIZED401키·서명·시각·난수 중 하나가 틀렸습니다. 서버 시각이 ±5분 안인지, 서명 경로에 쿼리가 들어갔는지 먼저 보세요 — 흔한 실수
FORBIDDEN_IP403허용 IP 밖에서 호출했습니다. detail.ip 를 API 연동 화면의 허용 IP 에 추가하세요.
INVALID_REQUEST400 · 405요청 형식 오류이거나 그 경로가 받지 않는 메서드입니다. detail.fields 에 어느 필드가 왜 틀렸는지 옵니다.
IDEMPOTENCY_KEY_REQUIRED400POST 에 Idempotency-Key 헤더가 없습니다.
IDEMPOTENCY_KEY_REUSED422같은 멱등키로 다른 본문·경로·메서드를 보냈습니다. 새 요청에는 새 키를 쓰세요.
REQUEST_IN_PROGRESS409앞 요청이 아직 처리 중입니다. Retry-After 초 뒤 같은 키로 다시 보내세요.
NOT_FOUND404없는 회원·청구서·결제를 가리켰거나 API 경로를 잘못 적었습니다. message 에 무엇을 못 찾았는지 나옵니다.
RATE_LIMITED429분당 한도를 넘었습니다. Retry-After 초만큼 기다렸다 보내세요 — 레이트리밋
UNPROCESSABLE422지금 상태에서는 할 수 없는 요청입니다(확정 전 청구서 결제, 이미 취소된 결제 취소 등). message 를 확인하세요. 수시결제·월별 금액 API 는 detail.reason 에 사유 코드가 옵니다.
INTERNAL_ERROR500 · 503빌링플러스 쪽 오류입니다. 서버 오류 결과는 멱등 저장이 되지 않으므로 같은 멱등키로 다시 보내도 됩니다. 계속되면 request_id 와 함께 문의해 주세요.

형식 오류(400) 예

400
{
  "error": {
    "code": "INVALID_REQUEST",
    "message": "요청 값이 올바르지 않습니다.",
    "detail": {"fields": {"phone": ["휴대전화 번호를 확인해 주세요. 숫자 9~11자리로 입력합니다."]}},
    "request_id": "req_9a8b7c6d5e4f3a2b1c0d9e8f"
  }
}

detail.fields 의 모양은 엔드포인트에 따라 조금 다릅니다(필드 이름 → 문구 목록, 또는 검증 항목 목록). 화면에 그대로 보여 주기보다 로그로 남겨 개발 중에 고치는 용도입니다.

422 의 사유 코드

일부 API 는 422 UNPROCESSABLE 에 detail.reason 을 함께 줍니다. 사유 코드 목록은 각 문서에 있습니다.

결제 승인(POST /api/v1/payments)이 결제사로 나가기 전에 막히면 422 UNPROCESSABLE 의 detail.kind 로 원인을 구분합니다.

detail.kind뜻할 일
PAYMENT_IN_FLIGHT같은 청구서에 결과를 기다리는 결제(PENDING·UNKNOWN)가 있습니다. detail.payment_id · detail.payment_status 에 그 결제가 실립니다.다시 승인하지 마세요. 그 결제가 실제로 승인됐을 수 있습니다. GET /api/v1/payments/{payment_id} 로 결과가 확정될 때까지 확인합니다. 실패로 확정된 뒤에만 새 멱등키로 승인합니다.
PG_CONFIGURATION결제사 연결이나 수수료 정책이 아직 준비되지 않았습니다. message 에 이유가 적혀 있습니다.다시 보내도 같은 결과입니다. 빌링플러스 화면의 결제사 계약 상태를 확인하세요.

결제 거절은 에러가 아닙니다

카드 한도 초과·정지 카드 같은 거절은 정상적인 처리 결과입니다. HTTP 200 으로 오고, 결제 객체의 status 가 FAILED, failure_reason 에 빌링플러스 표준 사유가 들어 있습니다.

200 — 거절된 결제(일부)
{
  "id": 8812,
  "payment_no": "P-2026-1028-0007",
  "status": "FAILED",
  "amount": 29900,
  "failure_reason": "LIMIT_EXCEEDED",
  "failure_message": "한도초과",
  "approved_at": null
}
status뜻
PENDING요청중
APPROVED승인완료
PARTIAL부분취소
CANCELED취소완료
FAILED승인실패
UNKNOWN미확정 — 결제사 응답을 못 받았다. 조회로 확정될 때까지 성공도 실패도 아니다. 이 상태로는 웹훅이 나가지 않는다
failure_reason뜻
LIMIT_EXCEEDED한도초과
INSUFFICIENT잔액부족
INVALID_CARD카드오류
SUSPENDED정지·분실카드
EXPIRED유효기간 경과
TEMPORARY일시오류(재시도 가치 있음)
PG_ERROR결제사 오류
UNMAPPED미분류 — 결제사 코드를 아직 분류하지 못함

UNKNOWN 은 실패가 아닙니다. 결제사 응답을 받지 못한 상태라 실제로는 승인됐을 수 있습니다. 다시 승인하지 말고 조회나 웹훅으로 확정을 기다리세요 — 미확정 결제

사유 코드는 앞으로 늘어날 수 있습니다. 모르는 값이 오면 "사유 확인 필요" 처럼 다루고, 성공이나 특정 사유로 단정하지 마세요.