# 에러 코드

point3가 반환하는 코드를 출처별로 정리했습니다. 처리 기준은 HTTP 상태 코드와 응답 본문의 코드를 함께 보고 판단하세요. 사용자 안내 문구는 `message` 원문 대신 코드별로 가맹점이 정한 문구를 사용하는 것을 권장합니다.

<Callout type="caution" title="결과가 불확실하면 성공·실패로 추정하지 마세요">
  `5xx`, 타임아웃, 네트워크 오류, 응답 유실은 결과가 확정되지 않은 상태입니다. 같은 요청을 무조건 반복하거나 실패로 처리하지 말고 상태 조회 API로 확인하세요.
</Callout>

## HTTP 상태 코드 공통 기준

| 상태 코드 | 의미 | 재시도 | 처리 |
| --- | --- | --- | --- |
| `200` | 정상 응답 | - | 응답 본문의 `status`로 결과 판단 |
| `202` | 처리 중 | 조회 | 잠시 기다렸다가 상태 조회 |
| `400` | 요청 형식 오류 | 안 함 | 요청값 수정 |
| `401` | 인증 실패 | 안 함 | API 키 확인 |
| `404` | 리소스 없음 | 안 함 | `sessionId` 확인 |
| `409` | 현재 상태에서 처리 불가 (결제 취소 API) | 코드별 | 본문의 `result.code` 확인 |
| `422` | 요청 거절 | 안 함 | 결제 승인: 승인 기한 만료. 결제 취소: 거절로 처리하고 코드 기록 |
| `500` | 서버 오류 | 조회 | 결과 미확정. 상태 조회로 확인 |
| `503` | 일시 사용 불가 | 조회 | 결제 세션 API: `error.eob`가 있으면 EOB 점검. 결제 취소 API: 결과 미확정이므로 상태 조회 |

## 결제 세션·결제 승인 API

결제 세션 API와 결제 승인 API의 오류 응답은 `error.type`과 `error.code`를 포함합니다.

```json title="오류 응답 형식"
{
  "error": {
    "type": "authenticationError",
    "code": "authenticationRequired",
    "message": "인증에 실패했습니다."
  }
}
```

| HTTP | `error.type` | `error.code` | 처리 |
| --- | --- | --- | --- |
| `400` | `invalidRequestError` | `invalidRequest` | 요청 형식과 필수 필드 확인 |
| `401` | `authenticationError` | `authenticationRequired` | `Authorization` 헤더와 API 키 확인 |
| `404` | `notFoundError` | `resourceMissing` | `sessionId` 확인 |
| `422` | `invalidRequestError` | `paymentCaptureExpired` | 결제 승인 기한 만료. 새 결제 세션으로 다시 시작 |
| `500` | `apiError` | `internalError` | 결과 미확정. 결제 세션 조회 |
| `503` | `serviceUnavailableError` | `temporarilyUnavailable` | `error.eob`가 있으면 `endsAt` 이후 재요청, 없으면 잠시 후 결제 세션 조회 |

`error.eob`는 결제 세션 API에서만 반환되며 `startsAt`, `endsAt`, `timeZone`을 포함합니다. EOB 점검 중 응답 예시는 [EOB 점검 시간](/operations#eob-점검-시간)을 참고하세요.

### 결제 승인 결과 코드

결제 승인 API가 `200`으로 응답하면 `outcome.code`로 결과를 구분합니다.

| `status` | `outcome.type` | `outcome.code` | 의미 | 처리 |
| --- | --- | --- | --- | --- |
| `captured` | `succeeded` | `PAYMENT_CAPTURED` | 결제 성공 | 주문 완료 |
| `failed` | `declined` | `PAYMENT_METHOD_DECLINED` | 결제 수단 승인 거절 | 다른 결제 수단 안내 |
| `failed` | `paymentMethodUnavailable` | `PAYMENT_METHOD_UNAVAILABLE` | 결제 수단 사용 불가 | 다른 결제 수단 안내 |
| `failed` | `serviceUnavailable` | `PAYMENT_SERVICE_UNAVAILABLE_HOURS` | 은행·기관 점검 또는 운영시간 외 | 다른 계좌 선택 또는 점검 종료 후 새 결제 |
| `failed` | `rejected` | `PAYMENT_CAPTURE_REJECTED` | 승인 요청 거절 | 실패 안내 |
| `failed` | `failed` | `PAYMENT_METHOD_LIMIT_EXCEEDED` | 결제 수단의 이체 한도 초과 | 다른 결제 수단 또는 금액 안내 |
| `failed` | `failed` | `PAYMENT_CAPTURE_ALREADY_FAILED` | 이미 실패한 결제 | 실패로 처리하고 새 결제 |

`failed`의 `outcome.message`에는 은행이 반환한 사유가 담길 수 있습니다. 화면 분기는 `outcome.code`로 하세요.

`202` 응답은 `PAYMENT_CAPTURE_PROCESSING`이며, 잠시 기다렸다가 결제 세션을 조회합니다.

## 결제 취소 API

결제 취소 API의 오류 응답은 `result.code`를 포함합니다.

```json title="오류 응답 형식"
{
  "status": 409,
  "timestamp": "2026-08-21T00:00:00.000Z",
  "result": {
    "code": "REFUND_DUPLICATE_REQUEST",
    "message": "동일한 Idempotency-Key로 요청이 이미 접수되었습니다"
  }
}
```

### 409 응답

| `result.code` | 의미 | 처리 |
| --- | --- | --- |
| `REFUND_TEMPORARY_UNAVAILABLE` | 외부 처리 결과 미확정. 일시 장애 시에는 `503`으로 반환 | 원래 키와 응답 식별값을 보존하고 상태 조회 후 처리 중인 항목만 재개 |
| `REFUND_DUPLICATE_REQUEST` | 동일 `Idempotency-Key`를 24시간 안에 재사용 | 상태 조회로 기존 요청 결과를 확인하고 새 취소를 만들지 않음 |
| `REFUND_ACTIVE_REQUEST_EXISTS` | 현재 처리 중인 취소 존재 | 새 취소를 만들지 않고 상태 조회 후 기존 처리를 재개 |
| `REFUND_NOT_IN_REFUNDABLE_STATE` | 취소 가능한 상태가 아님 | 결제·취소 상태를 확인하고 요청 종료 |
| `EOB_WINDOW_BLOCKED` | 23:30 이상 00:30 미만(KST) 요청 | 00:30 이후 새 취소 요청 |

### 그 외 오류 코드

| HTTP | `result.code` | 의미 |
| --- | --- | --- |
| `400` | `REFUND_VALIDATION_FAILED` | 요청 형식 오류 |
| `400` | `NON_POSITIVE_REFUND_AMOUNT` | 취소 금액이 0 이하 |
| `400` | `REFUND_TAX_BREAKDOWN_INVALID` | 면세 금액·부가세 구성이 올바르지 않음 |
| `404` | `REFUND_NOT_FOUND` | 취소할 결제를 찾을 수 없음 |
| `422` | `AMOUNT_EXCEEDS_REFUNDABLE` | 취소 금액이 취소 가능 금액을 초과 |
| `422` | `TAX_FREE_AMOUNT_EXCEEDS_REFUNDABLE` | 면세 금액이 취소 가능 면세 금액을 초과 |
| `422` | `VAT_EXCEEDS_REFUNDABLE` | 부가세가 취소 가능 부가세를 초과 |

### 취소 실패 코드

취소 상태 조회 결과에서 `failed`인 취소 항목은 실패 사유 코드를 포함합니다.

| 코드 | 의미 |
| --- | --- |
| `refundMethodDeclined` | 환불 수단 승인 거절 |
| `refundMethodUnavailable` | 환불 수단 사용 불가 |
| `refundServiceUnavailable` | 은행 서비스 운영시간 외 |
| `refundRejected` | 환불 요청 거절 |
| `refundFailed` | 환불을 완료할 수 없음 |

취소 처리 흐름은 [결제 취소](/payment-cancellation)를 참고하세요.

## 위임 인증 API

위임 인증 생성 API의 오류 응답은 `result.code`를 포함합니다. 어떤 오류든 위임 인증 없이 결제창을 열면 결제를 계속할 수 있습니다.

| HTTP | `result.code` | 처리 |
| --- | --- | --- |
| `400` | `HTTP_ERROR` | `payer_id` 형식과 추가 필드 확인 |
| `401` | `HTTP_ERROR` | `Authorization` 헤더와 API 키 확인 |
| `404` | `PAYER_NOT_FOUND` | 저장된 `payerId`를 사용할 수 없음. 위임 인증 없이 결제창을 열고, 결제 후 새로 받은 `payerId` 저장 |
| `503` | | 일시적 장애. 위임 인증 없이 결제창 열기 |

자세한 내용은 [위임 인증 생성](/delegated-creation#오류-처리)을 참고하세요.

## 결제창 코드

### JavaScript SDK 결제

`failUrl`의 `code` 쿼리 파라미터로 전달됩니다. 결제 승인 API를 호출하지 않습니다.

| 코드 | 의미 | 안내 문구 예시 |
| --- | --- | --- |
| `PAYMENT_WINDOW_CLOSED` | 사용자가 결제창을 닫음 | 결제창이 닫혔습니다. |
| `PAYER_DEACTIVATED` | 구매자 탈퇴 완료 | 탈퇴가 완료되어 결제가 종료되었습니다. |
| `SESSION_EXPIRED` | 결제 세션 만료 | 결제 세션이 만료되었습니다. 결제를 다시 시도해 주세요. |
| `INVALID_SESSION` | 결제 세션 확인 불가 | 결제 세션 정보를 확인할 수 없습니다. 결제를 다시 시작하세요. |
| `PAYMENT_FAILED` | 결제 요청 거절 (예: 금액이 수수료 이하) | 결제 요청이 거절되었습니다. |

### JavaScript SDK 등록

`failUrl`의 `code` 쿼리 파라미터로 전달됩니다.

| 코드 | 의미 |
| --- | --- |
| `REGISTRATION_CANCELLED` | 사용자가 등록을 취소함 |
| `AUTHENTICATION_EXPIRED` | 인증 만료. 본인인증부터 다시 시작 |
| `REGISTRATION_FAILED` | 등록 실패 |
| `REGISTRATION_RESULT_UNAVAILABLE` | 등록 결과 확인 불가 |

### SDK 초기화·호출 오류

`failUrl`로 전달되지 않고 SDK 호출에서 발생하는 오류 객체의 `code`로 확인합니다. `try/catch`로 처리하세요.

| 코드 | 원인 |
| --- | --- |
| `INVALID_CLIENT_KEY` | `client_id`가 `client-...` 형식이 아님 |
| `INVALID_PAYMENT_REQUEST` | 요청값 누락 또는 SDK 호출 순서 오류. 위임 인증의 `authorization_url`을 가공했거나 등록 전용 위젯에 전달한 경우 포함 |
| `PAYMENT_REQUEST_IN_PROGRESS` | 결제나 등록이 진행 중인 상태에서 다시 요청 |
| `BROWSER_NOT_READY` | 문서 준비 상태, 보안 컨텍스트 또는 `crypto.randomUUID()` 미지원 (등록) |
