인앱결제 ② 결제 성공(서버 실패) 테스트 중 문의사항

이 글의 성격은 무엇인가요?

질문 / 문제 해결

내용을 설명해주세요

Apps in Toss 인앱결제 복구 테스트 중 확인한 내용 공유드립니다.

개발환경: WebView
사용중인 SDK 버전: @apps-in-toss/web-framework 2.4.7
테스트 환경: 샌드박스
토스앱 버전: 5.258.1
샌드박스 앱: 최신 버전 재설치 후 테스트
상품 SKU: ait.0000019167.986a4d44.dc62a60424.781268xxxx

현재 createOneTimePurchaseOrder로 결제하고,
processProductGrant({ orderId })에서 파트너 서버 지급 API를 호출한 뒤
성공 여부를 boolean으로 반환하는 구조입니다.

문서/가이드상 반드시 테스트해야 하는 케이스 중
“결제 성공 + 파트너 서버 지급 실패” 케이스를 확인하고 있습니다.

기대 흐름은 아래와 같이 이해했습니다.

  1. 결제는 성공
  2. 파트너 서버 지급 로직 실패
  3. PRODUCT_NOT_GRANTED_BY_PARTNER 발생
  4. 앱 재실행 또는 즉시 getPendingOrders()로 미결 주문 조회
  5. 해당 주문 orderId + sku 확인
  6. 파트너 서버 지급 재시도
  7. 지급 성공 후 completeProductGrant({ params: { orderId } }) 호출

그런데 실제 테스트에서는 기대와 다른 현상이 있습니다.


케이스 1. 결제 성공 후 파트너 서버 지급 실패를 의도한 테스트

실제 로그상 processProductGrant가 호출되고,
파트너 서버 지급 API도 200 ok=true로 성공했습니다.
processProductGrant도 true를 반환했습니다.

하지만 onEvent success가 아니라 onError로 TOSS_SERVER_VERIFICATION_FAILED가 내려옵니다.

예시 로그:

processProductGrant 진입: orderId=0C46C0AB-D197…
grantToServer 응답: status=200 ok=true
processProductGrant 반환: true
TOSS processProductGrant return=true
onError: code=TOSS_SERVER_VERIFICATION_FAILED
userInfo.orderId=0C46C0AB-D197-4C9B-8B68-9B2295201C6A

이후 getPendingOrders()를 호출하면,
onError에 있던 실제 orderId가 내려오지 않고 아래 값만 반환됩니다.

orderId=550e8400-e29b-41d4-a716-446655440000
sku=sku_106…

실제 결제 SKU는 아래 값입니다.

ait.0000019167.986a4d44.dc62a60424.781268xxxx

즉, TOSS_SERVER_VERIFICATION_FAILED에서는 orderId가 error.userInfo에 있긴 하지만,
getPendingOrders()에 해당 주문이 없어 completeProductGrant까지 갈 수 없습니다.


케이스 2. PRODUCT_NOT_GRANTED_BY_PARTNER를 의도적으로 발생시킨 테스트

에러 테스트 항목 중 "파트너사 상품 지급 실패"를 검증하기 위해
PRODUCT_NOT_GRANTED_BY_PARTNER를 발생시켰습니다.

실제 onError raw는 아래와 같습니다.

{
“name”: “PRODUCT_NOT_GRANTED_BY_PARTNER”,
“code”: “PRODUCT_NOT_GRANTED_BY_PARTNER”,
“userInfo”: {
“orderId”: “”
},
“moduleName”: “MiniAppModule”,
“__isError”: true
}

이 경우 processProductGrant 진입 로그가 없었고,
error.userInfo.orderId도 빈 문자열이었습니다.

이후 getPendingOrders()를 호출했지만 마찬가지로 실제 주문이 내려오지 않고,
아래 값만 반환됩니다.

orderId=550e8400-e29b-41d4-a716-446655440000
sku=sku_106…

그래서 PRODUCT_NOT_GRANTED_BY_PARTNER가 내려왔지만,
앱에서 복구할 실제 orderId를 특정할 방법이 없었습니다.


궁금한 점입니다.

  1. “결제 성공 + 파트너 서버 지급 실패” 테스트의 기대 에러는 PRODUCT_NOT_GRANTED_BY_PARTNER로 이해했는데,
    실제로는 TOSS_SERVER_VERIFICATION_FAILED가 내려오는 것이 정상인가요?

  2. processProductGrant가 호출되고 true를 반환했으며,
    파트너 서버 지급 API도 200 ok=true였는데 TOSS_SERVER_VERIFICATION_FAILED가 발생한 경우,
    파트너사는 자체 DB 지급 성공을 기준으로 콘텐츠를 제공해도 되나요?

  3. TOSS_SERVER_VERIFICATION_FAILED 발생 시 getPendingOrders()에 해당 orderId가 포함되지 않는 것이 정상인가요?

  4. PRODUCT_NOT_GRANTED_BY_PARTNER 발생 시 error.userInfo.orderId가 빈 문자열로 내려오는 것이 정상인가요?

  5. PRODUCT_NOT_GRANTED_BY_PARTNER 발생 후 getPendingOrders()에서 실제 pending order가 내려와야 하는 것으로 이해했는데,
    현재는 550e8400-e29b-41d4-a716-446655440000 / sku_106… 값만 반환됩니다.
    이 값은 샌드박스 mock 데이터인가요?

  6. 샌드박스 WebView 환경에서 PRODUCT_NOT_GRANTED_BY_PARTNER 복구 플로우를 정상적으로 테스트하려면
    별도 조건이나 설정이 필요한가요?

현재 가장 큰 문제는 복구 대상 에러가 발생해도
앱에서 복구할 실제 orderId + sku를 얻지 못해
getPendingOrders → 서버 지급 재시도 → completeProductGrant 흐름을 검증할 수 없다는 점입니다.

appName (선택)

toss

안녕하세요 :slight_smile:
현재 샌드박스 환경에서는 mock 값만 내려가고 있어, orderId가 실제로 생성되거나 getPendingOrders() 생성된 주문이 내려가는 구조는 아니에요. :cry:

결제 성공 + 파트너사 지급 실패는 PRODUCT_NOT_GRANTED_BY_PARTNER 가 맞습니다.
TOSS_SERVER_VERIFICATION_FAILED 는 언제 발생하는지 한번 확인해볼게요.

답변 감사합니다.
그럼 getPendingOrders() 에서 복구 코드만 넣어놓고 실서버에서 된다고(?) 생각하면 되겠네요.

TOSS_SERVER_VERIFICATION_FAILED 도 PRODUCT_NOT_GRANTED_BY_PARTNER 와 동일하게
결제 성공 + 파트너사 지급 실패 라고 범위를 정해놓고 getPendingOrders() 를 호출하게 개발을 해놓긴 헀는데

맞는걸까요? ^^;