본문으로 건너뛰기

에러 코드

CROSS Pay 에러는 SDK/runtime error와 REST API error로 나뉩니다. 브라우저 SDK는 가능한 경우 다음 형태의 구조화된 에러를 전달합니다.

{
type: 'validation_error',
code: 'INVALID_REDIRECT_URL',
message: 'redirect URL is not allowed',
retryable: false,
requestId: 'req_...',
checkoutId: 'cs_...'
}

SDK error type

type설명기본 처리
network_errorCDN/runtime/API 네트워크 실패retryable이면 재시도 버튼 표시
validation_error요청 값, URL, currency/country 검증 실패입력 수정 안내
payment_error결제 거절, 만료, 취소, 온체인 실패결제수단 변경 또는 새 세션 유도
authentication_errorAPI key/session 인증 실패서버 설정 점검
rate_limit_error요청 한도 초과Retry-After 또는 백오프 적용
server_errorCROSS Pay 또는 provider 서버 오류잠시 후 재시도
sdk_errorSDK 로드/위젯 생명주기 오류연동 코드와 CSP 점검

Network / SDK load

coderetryable설명
NETWORK_TIMEOUT네트워크 요청이 제한 시간 안에 끝나지 않음
NETWORK_OFFLINE브라우저가 offline 상태
SDK_NOT_LOADEDruntime script가 아직 준비되지 않음
WIDGET_LOAD_FAILEDwidget iframe/runtime 로드 실패
SSR_UNSUPPORTED서버 환경에서 브라우저 전용 결제 메서드 호출
INVALID_SCRIPT_URL허용되지 않은 cross-pay.js URL
HTTP_NOT_ALLOWED운영 script/redirect URL에 HTTP 사용

SDK 클래스 기준으로는 ScriptLoadFailedError, ScriptLoadTimeoutError, ScriptLoadAbortedError, NamespaceNotAvailableError, CrossPaySDKError를 구분할 수 있습니다.

Validation

code설명
MISSING_PARAM필수 파라미터 누락
INVALID_FORMAT형식 검증 실패
INVALID_AMOUNT금액이 0 이하이거나 허용 범위를 벗어남
INVALID_CURRENCYcurrency 형식이 유효하지 않음
UNSUPPORTED_CURRENCYCROSS Pay가 처리하지 않는 currency
UNSUPPORTED_COUNTRY지원하지 않거나 비활성화된 country
INVALID_RESPONSEruntime/API 응답 shape이 예상과 다름
INVALID_REDIRECT_URL위험하거나 allowlist에 없는 redirect URL

Payment

coderetryable설명
CHECKOUT_EXPIREDcheckout session TTL 만료. 새 POST /v1/payments 필요
PAYMENT_DECLINEDprovider가 결제를 거절
PAYMENT_CANCELLED사용자가 결제를 취소하거나 창을 닫음
USER_REJECTED사용자 취소를 SDK가 정규화한 코드
PAYMENT_FAILED결제 실패 일반
INSUFFICIENT_FUNDS잔액 부족
POLLING_TIMEOUT상태 확인이 제한 시간 내 완료되지 않음
POPUP_BLOCKED브라우저가 popup을 차단
WALLET_INIT_FAILEDembedded wallet 초기화 실패
WRONG_CHAIN지갑 네트워크가 결제 chain과 다름
ONCHAIN_TX_FAILED온체인 트랜잭션 실패 또는 revert

Widget lifecycle

code설명
AMOUNT_NOT_SETwidgets.setAmount() 호출 전 submit 시도
WIDGET_NOT_MOUNTED결제수단 widget이 mount되지 않은 상태에서 submit/update 호출
WIDGET_LOAD_FAILEDwidget iframe 로드 또는 bridge 준비 실패

REST API 대표 코드

REST API 에러 응답은 { code, message } 형태이며, 원본은 internal/api/errors.go (cross-pay-api) 에서 정의됩니다.

4xx (요청 측 오류)

codeHTTP설명
BAD_REQUEST400요청 body/query/header 검증 실패
INVALID_AMOUNT400금액 형식 오류 또는 통화 소수점 초과
INVALID_CURRENCY400currency 코드가 유효하지 않거나 미지원
UNAUTHORIZED401merchant API key 누락 또는 유효하지 않음
FORBIDDEN403다른 머천트의 리소스 접근 시도
NOT_FOUND404대상 리소스를 찾을 수 없음
CHECKOUT_NOT_FOUND404checkout id를 찾을 수 없음
PAYMENT_METHOD_NOT_FOUND404선택한 결제수단이 존재하지 않거나 비활성
CONFLICT409일반 충돌
IDEMPOTENCY_CONFLICT409같은 idempotency key를 다른 request body로 재사용
INVALID_CHECKOUT_STATE409terminal 상태의 checkout에 SelectQuote 호출
INVALID_PAYMENT_STATE409현재 결제 상태에서 허용되지 않는 작업 (예: PAID cancel)
INVALID_TRANSITION409상태 전이 위반. 예: PROCESSING 결제 cancel — PG와 race 회피
CHECKOUT_EXPIRED410checkout TTL 만료 — 새 POST /v1/payments 필요
SESSION_GONE410on-chain session 종료 또는 payment terminal 상태
UNPROCESSABLE422요청은 형식상 valid 하나 의미상 처리 불가
UNSUPPORTED_CURRENCY422결제수단/국가 조합에서 지원하지 않는 통화
UNSUPPORTED_COUNTRY422미등록 또는 비활성 국가
PAYMENT_TOKEN_NOT_AVAILABLE422해당 체인의 토큰 매핑이 활성화되지 않음
PG_NOT_AVAILABLE422선택한 결제수단의 PG가 해당 checkout에 사용 불가
REFUND_EXCEEDS_REMAINING409환불 금액이 잔여 환불 가능액을 초과
REFUND_PROVIDER_UNAVAILABLE503PG의 환불 채널이 일시 사용 불가
RATE_LIMITED429요청 한도 초과

5xx (서버 측 오류)

codeHTTP설명
INTERNAL_ERROR500서버 내부 오류
SERVER_ERROR500(legacy alias) INTERNAL_ERROR
NOT_IMPLEMENTED501라우트는 노출되어 있으나 미구현
PG_UPSTREAM_ERROR502provider upstream 오류
SERVICE_UNAVAILABLE503일시적 서비스 가용성 부재
INVALID_TRANSITION vs INVALID_PAYMENT_STATE

두 코드 모두 409 이지만 의도는 다릅니다.

  • INVALID_TRANSITION — 상태 머신 위반 (예: PROCESSING → CANCELLED 시도). 자세한 라이프사이클은 Webhooks Overview.
  • INVALID_PAYMENT_STATE — 작업 자체가 결제 상태에 부합하지 않음 (예: PAID 에 대해 단순 lookup이 아닌 mutation 시도).

머천트는 두 코드를 별도 분기로 처리하기보다 "현 상태에서 불가" 로 한꺼번에 다루는 것이 일반적입니다.

FDS deny

/v1/checkout/**는 FDS 차단도 HTTP 200으로 응답합니다. 이때 body에는 Payment/Quote 객체가 없고 fds envelope만 포함됩니다.

{
"fds": {
"outcome": "DENY",
"code": "COUNTRY_BLOCKED",
"message": "Payment is blocked by risk policy",
"risk_level": "HIGH",
"risk_score": 92,
"rule": "country_allowlist"
}
}

SDK와 checkout UI는 HTTP status가 아니라 fds.outcome으로 분기해야 합니다. 알 수 없는 fds.code는 generic block으로 처리하세요.