에러 코드
HTTP 상태 코드와 본문 code로 에러를 분기해요.
응답 형식
{
"statusCode": 403,
"code": "API_KEY_SCOPE_MISSING",
"message": "이 요청에 필요한 권한이 없어요.",
"details": { "required": ["refunds:write"] }
}| 필드 | 타입 | 설명 |
|---|---|---|
statusCode | integer | HTTP 상태 코드예요. |
code | string | 에러 분기에 사용하는 코드예요. |
message | string | 상황을 설명하는 한국어 메시지예요. |
details | object, 선택 | 필드 검증 오류나 필요한 권한 등 추가 정보예요. 내용이 없으면 생략하거나 빈 객체일 수 있어요. |
전체 에러 코드
일반 오류 · HTTP 400
| 코드 | 의미 | 발생 엔드포인트 |
|---|---|---|
BAD_REQUEST | 요청 필드를 확인해 주세요. | POST /v1/portal-sessions |
VALIDATION_FAILED | 필드 누락, 형식 오류, 지원하지 않는 필드 또는 필수 멱등 키 오류예요. | 공통 |
일반 오류 · HTTP 401
| 코드 | 의미 | 발생 엔드포인트 |
|---|---|---|
API_KEY_INVALID | API 키가 없거나 형식이 올바르지 않아요. 등록되지 않았거나 회전 유예가 끝난 키도 사용할 수 없어요. | 공통 |
일반 오류 · HTTP 404
| 코드 | 의미 | 발생 엔드포인트 |
|---|---|---|
NOT_FOUND | 요청한 리소스를 찾을 수 없어요. | POST /v1/portal-sessions |
일반 오류 · HTTP 429
| 코드 | 의미 | 발생 엔드포인트 |
|---|---|---|
RATE_LIMITED | API 키 호출 한도를 초과했어요. 잠시 후 다시 시도해 주세요. | 공통 |
일반 오류 · HTTP 500
| 코드 | 의미 | 발생 엔드포인트 |
|---|---|---|
INTERNAL_ERROR | 요청을 처리하는 중 오류가 발생했어요. | 공통 |
리소스별 오류 · HTTP 400
| 코드 | 의미 | 발생 엔드포인트 |
|---|---|---|
CHECKOUT_URL_INVALID | Checkout 또는 포털 복귀 URL 형식이 올바르지 않아요. | POST /v1/checkout/sessions, POST /v1/portal-sessions |
METADATA_INVALID | 메타데이터가 평면 문자열 맵이 아니거나 허용된 크기를 벗어났어요. | POST /v1/checkout/sessions |
REFUND_AMOUNT_EXCEEDS | 요청한 환불 금액이 현재 환불 가능액보다 커요. | POST /v1/refund-requests/{id}/approve |
REFUND_AMOUNT_INVALID | 환불 금액은 0보다 커야 해요. | POST /v1/orders/{id}/refund, POST /v1/refund-requests/{id}/approve |
REFUND_EXCEEDS | 환불 금액이 남은 환불 가능액보다 커요. | POST /v1/orders/{id}/refund, POST /v1/refund-requests/{id}/approve |
REFUND_REASON_REQUIRED | 환불 요청을 보류하거나 거절하는 사유를 입력해 주세요. | POST /v1/refund-requests/{id}/hold, POST /v1/refund-requests/{id}/reject |
RETURN_URL_NOT_ALLOWED | 복귀 URL 도메인이 결제 모드별 허용 목록에 없어요. | POST /v1/checkout/sessions, POST /v1/portal-sessions |
SUBSCRIPTION_REFUND_AMOUNT_INVALID | 승인한 구독 환불 금액이 유효하지 않아요. | POST /v1/refund-requests/{id}/approve |
리소스별 오류 · HTTP 403
| 코드 | 의미 | 발생 엔드포인트 |
|---|---|---|
API_KEY_IP_NOT_ALLOWED | 허용된 IP 주소에서 요청해야 해요. | 여러 엔드포인트 공통(19개) |
API_KEY_SCOPE_MISSING | 요청에 필요한 권한이 없어요. | 여러 엔드포인트 공통(19개) |
리소스별 오류 · HTTP 404
| 코드 | 의미 | 발생 엔드포인트 |
|---|---|---|
CHECKOUT_SESSION_NOT_FOUND | Checkout 세션이 없거나 키의 범위 밖이에요. | GET /v1/checkout/sessions/{id} |
LICENSE_NOT_FOUND | 라이선스가 없거나 키의 상품 범위 밖이에요. | GET /v1/licenses/{id} |
ORDER_NOT_FOUND | 주문이 없거나 키의 상품 범위 밖이에요. | GET /v1/orders/{id}, POST /v1/orders/{id}/refund, POST /v1/refund-requests/{id}/approve, POST /v1/subscriptions/{id}/cancel |
PRODUCT_NOT_FOUND | 상품이 없거나 키의 상품 범위 밖이에요. | POST /v1/checkout/sessions, GET /v1/products/{id} |
REFUND_REQUEST_NOT_FOUND | 환불 요청이 없거나 키의 상품 범위 밖이에요. | GET /v1/refund-requests/{id}, POST /v1/refund-requests/{id}/approve, POST /v1/refund-requests/{id}/hold, POST /v1/refund-requests/{id}/reject |
SUBSCRIPTION_NOT_FOUND | 구독이 없거나 키의 상품 범위 밖이에요. | POST /v1/portal-sessions, GET /v1/subscriptions/{id}, POST /v1/subscriptions/{id}/cancel, GET /v1/subscriptions/{id}/cancel-preview |
리소스별 오류 · HTTP 409
| 코드 | 의미 | 발생 엔드포인트 |
|---|---|---|
ALREADY_CANCELED | 이미 기간말 해지가 예약돼 있어요. | POST /v1/subscriptions/{id}/cancel |
ALREADY_ENDED | 이미 종료된 구독이에요. | POST /v1/subscriptions/{id}/cancel |
ENDED | 판매가 종료된 상품이에요. | POST /v1/checkout/sessions |
IDEMPOTENCY_IN_PROGRESS | 같은 멱등 키의 요청이 처리 중이에요. 잠시 후 다시 시도해 주세요. | 여러 엔드포인트 공통(7개) |
IDEMPOTENCY_KEY_CONFLICT | 같은 멱등 키를 다른 요청에 사용했어요. | 여러 엔드포인트 공통(7개) |
NOT_STARTED | 아직 판매가 시작되지 않은 상품이에요. | POST /v1/checkout/sessions |
PRODUCT_ARCHIVED | 보관된 상품은 결제할 수 없어요. | POST /v1/checkout/sessions |
PUBLIC_CONTACT_VERIFICATION_REQUIRED | Checkout 세션을 만들기 전에 공개 연락처를 인증해 주세요. | POST /v1/checkout/sessions |
REFUND_AMOUNT_MISMATCH | 승인 금액이 요청 금액과 달라요. 금액을 확인하고 차이를 명시적으로 승인해 주세요. | POST /v1/refund-requests/{id}/approve |
REFUND_IN_PROGRESS | 이 주문과 관련한 환불이 처리 중이에요. | POST /v1/orders/{id}/refund, POST /v1/refund-requests/{id}/approve, POST /v1/subscriptions/{id}/cancel |
REFUND_NONE_LEFT | 남은 환불 가능 금액이 없어요. | POST /v1/orders/{id}/refund, POST /v1/refund-requests/{id}/approve |
REFUND_NOT_PAID | 주문 상태가 결제 완료가 아니에요. | POST /v1/orders/{id}/refund, POST /v1/refund-requests/{id}/approve |
REFUND_REQUEST_NOT_ACTIONABLE | 환불 요청의 현재 상태에서는 승인·거절·보류할 수 없어요. | POST /v1/refund-requests/{id}/approve, POST /v1/refund-requests/{id}/hold, POST /v1/refund-requests/{id}/reject |
REFUND_REQUEST_PENDING | 활성 환불 요청이 있어 주문을 환불할 수 없어요. | POST /v1/orders/{id}/refund, POST /v1/subscriptions/{id}/cancel |
REFUND_SETTLED | 정산 회차에 포함된 주문은 환불할 수 없어요. | POST /v1/orders/{id}/refund, POST /v1/refund-requests/{id}/approve |
REFUND_STATUTORY_LOCKED | 법정 청약철회 기간에는 현재 작업자의 처리가 제한돼요. | POST /v1/refund-requests/{id}/approve, POST /v1/refund-requests/{id}/hold, POST /v1/refund-requests/{id}/reject |
SOLD_OUT | 이 상품은 품절되어 결제할 수 없어요. | POST /v1/checkout/sessions |
SUBSCRIPTION_REFUND_NONE_LEFT | 구독 주문에 남은 환불 가능 금액이 없어요. | POST /v1/refund-requests/{id}/approve, POST /v1/subscriptions/{id}/cancel |
SUBSCRIPTION_REFUND_SETTLED | 즉시 해지 환불 대상 주문이 정산 회차에 포함됐어요. | POST /v1/refund-requests/{id}/approve, POST /v1/subscriptions/{id}/cancel |
리소스별 오류 · HTTP 429
| 코드 | 의미 | 발생 엔드포인트 |
|---|---|---|
LICENSE_LOOKUP_BLOCKED | 라이선스 조회 제한에 걸려 요청할 수 없어요. Retry-After 이후 다시 시도해 주세요. | POST /v1/licenses/activate, POST /v1/licenses/deactivate, POST /v1/licenses/verify |
LICENSE_RATE_LIMITED | 라이선스 API 호출 한도를 넘었어요. Retry-After 이후 다시 시도해 주세요. | POST /v1/licenses/activate, POST /v1/licenses/deactivate, POST /v1/licenses/verify |
리소스별 오류 · HTTP 500
| 코드 | 의미 | 발생 엔드포인트 |
|---|---|---|
CHECKOUT_NOT_CONFIGURED | 스토어의 결제 설정이 완료되지 않아 Checkout 세션을 만들 수 없어요. | POST /v1/checkout/sessions |
리소스별 오류 · HTTP 502
| 코드 | 의미 | 발생 엔드포인트 |
|---|---|---|
PG_REFUND_AMBIGUOUS | 결제 대행사의 환불 결과를 확인하지 못했어요. 실제 환불됐을 수 있으니 상태를 확인한 뒤 다시 처리해 주세요. | POST /v1/orders/{id}/refund, POST /v1/refund-requests/{id}/approve, POST /v1/subscriptions/{id}/cancel |
PG_REFUND_FAILED | 결제 대행사가 환불 요청을 처리하지 못했어요. | POST /v1/orders/{id}/refund, POST /v1/refund-requests/{id}/approve, POST /v1/subscriptions/{id}/cancel |
입력 검증 실패
필드 누락·형식 오류·미지원 필드는 400 VALIDATION_FAILED이며, details.fields에 field와 message가 담겨요.
{
"statusCode": 400,
"code": "VALIDATION_FAILED",
"message": "요청 값을 확인해주세요.",
"details": {
"fields": [
{ "field": "successUrl", "message": "URL 형식이 올바르지 않아요." }
]
}
}{
"statusCode": 400,
"code": "VALIDATION_FAILED",
"message": "요청 값을 확인해주세요.",
"details": {
"fields": [
{ "field": "Idempotency-Key", "message": "필수 값이에요." }
]
}
}멱등성 충돌
멱등 키의 응답 재생과 충돌 처리는 REST API 개요의 멱등성에서 확인해요.
라이선스 앱 연동 API
| 상황 | 응답 | 응답 서명 |
|---|---|---|
| 정상 처리 | HTTP 200과 status (없는 라이선스 키는 status: "not_found") | Payri-Signature 있음 |
| 요청 형식 오류 | 400 VALIDATION_FAILED | 없음 |
| 호출 제한 | 429 LICENSE_RATE_LIMITED 또는 429 LICENSE_LOOKUP_BLOCKED | 없음 |
라이선스 앱 API는 API 키 대신 라이선스 키로 인증하고, 응답 서명은 라이선스 앱 연동 API에서 확인해요.
호출 제한
API 키 호출 제한은 REST API 개요의 호출 제한에서 확인해요.
다시 보내기
POST 재시도는 REST API 개요의 멱등성 규칙을 따라요.
관련 코드
Last updated on