모든 글
Playbook8분 소요

환불 처리는 조용히 망가진다. 그러니 실제 고객이 먼저 겪기 전에 sandbox에서 인앱 구매 환불을 테스트하라

환불 처리는 고객이 이미 떠난 뒤에야 실행되므로, 그 안의 버그는 실제로 돈을 잃기 전까지 보이지 않은 채로 남습니다. 두 스토어 모두 먼저 테스트 환경에서 환불을 발생시킬 수 있게 해줍니다. 여기서는 환불이 진짜가 되기 전에 App Store와 Google Play에서 인앱 구매 환불을 테스트하는 방법을 설명합니다.

어두운 책상 위 돋보기 아래 놓인 iPhone과 Android 휴대폰. 환불이 진짜가 되기 전에 인앱 구매 환불을 테스트하는 것을 나타냅니다

핵심 요약

  • Xcode의 StoreKit 테스트에서는 Transaction Manager의 환불 화살표를 클릭하는 것만으로 로컬에서 구매를 환불할 수 있고, 이는 앱의 Transaction.updates 리스너를 발생시킵니다. 하지만 Apple에는 전혀 연결하지 않으므로 App Store Server Notification은 전송되지 않습니다.
  • Apple에서 서버 측을 테스트하려면 sandbox의 App Store Server Notifications V2 URL을 백엔드로 향하게 하세요. 그러면 sandbox 환불은 진짜 REFUND를, 환불 요청은 CONSUMPTION_REQUEST를 서버로 전달합니다.
  • Apple의 Request a Test Notification 엔드포인트는 설정한 URL로 TEST 유형의 알림을 보내고 testNotificationToken을 반환하므로, 진짜 이벤트가 발생하기 전에 webhook이 도달 가능한지 확인할 수 있습니다.
  • Apple의 sandbox는 실패한 알림을 결코 재시도하지 않으므로, sandbox가 발생할 때 webhook이 다운되어 있으면 이벤트는 두 번째 시도 없이 버려집니다. 이는 나중에 진짜 환불 기한을 잃게 만드는 것과 같은 종류의 누락입니다.
  • Google Play는 라이선스 테스터에게 Test card, approves then charges back이라는 결제 수단을 제공하며, 이는 구매 직후 PendingRefundReviewNotification을 발생시키므로 24 hours의 orders.reviewrefund 응답을 리허설할 수 있습니다.
  • Google Play의 라이선스 테스터의 경우, 확인되지 않은 구매는 프로덕션이 기다리는 3 days가 아니라 3 minutes 후에 자동 환불되므로, 망가진 확인 경로가 테스트 중에 빠르고 뚜렷하게 드러납니다.
  • 한 번도 테스트하지 않은 환불 핸들러가 바로 환불된 고객의 유료 접근을 살아 있게 두는 핸들러입니다. 그리고 2026년 8월 3일부터, 테스트하지 않은 Google Play 지불 거절 응답은 구매 가격에서 Play의 서비스 수수료를 뺀 금액에 은행 수수료를 더한 만큼을 잃게 할 수 있습니다.

환불 처리는 고객이 이미 떠난 뒤에야 실행되는 유일한 코드 경로입니다. 거기에 도달하려면 실제로 환불을 받아야 하므로, 평소의 QA로는 전혀 건드리지 못합니다. 그래서 테스트되지 않은 채 출시되고, 몇 달간 조용히 잠들어 있다가, 진짜 환불에서 실패합니다. 그 실패가 치르게 하는 것은 빨간 테스트가 아니라 돈입니다. 해법은 환불을 나에게 일어나는 일로 다루기를 멈추고, 일부러 한 건을 발생시키는 것입니다. Apple과 Google 모두 테스트 환경에서 환불을 발생시키고 서버가 어떻게 반응하는지 지켜보게 해줍니다. 여기서는 유료 고객이 당신의 핸들러가 망가져 있었음을 증명하기 전에, App Store와 Google Play에서 인앱 구매 환불을 테스트하는 방법을 설명합니다.

환불이 발생할 수 있는 세 가지 환경, 그리고 그중 프로덕션은 단 하나뿐

개발 중에 Apple이나 Google 환불이 발생할 수 있는 곳은 서로 독립된 세 군데이며, 이들은 서로 대체되지 않습니다. 그중 둘은 당신이 필요할 때 발생시킬 수 있습니다. 세 번째는 프로덕션이며, 거기서 환불 버그를 처음 만나고 싶지는 않을 것입니다. 함정은 쉬운 쪽, 즉 Xcode에서의 로컬 테스트가 파이프라인 전체를 증명한다고 여기는 것입니다. 그것은 당신의 앱을 증명합니다. 당신의 서버에 대해서는 아무것도 말해주지 않습니다.

Xcode StoreKit 테스트는 로컬이므로, 오직 앱만 단련합니다

Xcode 내장 StoreKit 테스트는 Mac 위의 구성 파일에 대해 동작하며, Apple과의 왕복이 없습니다. 디버그 바에서 StoreKit Transaction Manager를 열고, 구매된 트랜잭션을 선택한 뒤, 휘어진 환불 화살표를 클릭하세요. 트랜잭션은 환불됨으로 뒤집히고, 앱의 Transaction.updates 리스너가 실제 환경과 똑같이 발생합니다. beginRefundRequest를 호출해 진짜 환불 시트를 띄울 수도 있으며, Xcode 환경에서는 당신이 고른 문제가 하나의 RevocationReason에 일대일로 대응하고 환불이 즉시 적용됩니다. 이는 revocationDate가 nil이 아니게 되는 순간 클라이언트가 접근을 끊는지 증명하는 가장 빠른 방법입니다. 동시에 이것이 로컬 테스트가 알려줄 수 있는 전부이기도 합니다. 여기서는 아무것도 Apple의 서버에 닿지 않으므로 App Store Server Notification이 전송되지 않기 때문입니다. 당신의 백엔드는 아무것도 배우지 못합니다.

sandbox는 당신의 서버가 마침내 환불 소식을 듣는 곳입니다

돈을 결정하는 통합의 절반, 즉 당신의 서버를 테스트하려면 Apple의 sandbox가 필요합니다. App Store Connect에서 sandbox의 App Store Server Notifications V2 URL을 설정하고, 기기에서 sandbox 테스터로 로그인해 구매하세요. 이제 sandbox에서의 환불은 진짜 REFUND 알림을 백엔드로 전달하고, 소비형이나 자동 갱신형에 대한 환불 요청은 CONSUMPTION_REQUEST를 전달합니다. 이는 프로덕션 서버가 받게 될 것과 같은 서명된 페이로드입니다. 무엇이든 발생시키기 전에 먼저 Request a Test Notification 엔드포인트를 호출하세요. 이는 App Store 서버에 설정한 URL로 TEST 유형의 알림을 보내라고 지시하고 testNotificationToken을 건네줍니다. 그것을 Get Test Notification Status에 전달해 전달을 확인합니다. 이 왕복이 동작하지 않으면 진짜 알림도 동작하지 않습니다.

환경발생시킬 수 있는 것증명하는 것할 수 없는 것
Xcode StoreKit 테스트Transaction Manager 또는 beginRefundRequest 시트를 통한 환불앱이 로컬에서 몇 초 안에 환불에 반응함Apple에 전혀 연결하지 않으므로 서버 알림이 전송되지 않음
Sandbox서버로의 진짜 REFUND와 CONSUMPTION_REQUEST, 그리고 필요할 때의 TEST 알림백엔드가 서명된 페이로드를 수신, 검증하고 처리함엔드포인트가 받지 못한 알림을 재시도하지 않음
프로덕션모든 환불, 진짜 돈으로여기서 먼저 배우고 싶은 것은 아무것도 없음버그의 비용을 되돌릴 수 없음

App Store에서 인앱 구매 환불을 테스트하는 방법

이 순서로 실행하세요. 저렴한 클라이언트 점검에서 완전한 서버 왕복까지. 각 단계는 서로 다른 부품을 단련하며, 뒤쪽 단계가 바로 프로덕션이 실제로 당신에게 청구하는 부분입니다.

  • App Store Connect의 Users and Access, Integrations, In-App Purchase 아래에서 In-App Purchase key를 만들고, 그것으로 App Store Server API 호출에 서명하세요.
  • sandbox의 App Store Server Notifications V2 URL을 백엔드로 향하게 한 뒤, Request a Test Notification을 호출하고, TEST 페이로드가 도착해 Apple의 인증서 체인에 대해 검증되는지 확인하세요.
  • Xcode의 Transaction Manager에서 구매를 환불하고, revocationDate가 설정되는 순간 앱이 자격을 내려놓는지 확인하세요.
  • sandbox 테스터로 로그인하고, 소비형을 구매하고, 환불을 요청하고, 서버가 CONSUMPTION_REQUEST를 받고 12 hours 기한의 넉넉한 안쪽에서 Send Consumption Information 응답을 조립해 보낼 수 있는지 확인하세요.
  • sandbox 구매를 환불하고, REFUND 알림이 서버에 도달하는지, 접근을 취소하거나 소비형 잔액을 차감하는지, 그리고 같은 알림이 반복 전달되어도 이중 적용되지 않는지 확인하세요.
작업등 아래 작은 바이스에 물린 스마트폰과 그 옆의 핀셋. 테스트 대상 기기가 환불이 진짜가 되기 전에 리허설하는 것을 나타냅니다

Google Play에서 환불과 지불 거절을 리허설하는 방법

Google Play에는 Xcode 같은 로컬 모드가 없습니다. 모든 것이 Google의 서버에 대해 동작하지만, 라이선스 테스터가 그것을 무료이면서 안전하게 유지해줍니다. Play Console에서 테스트용 Google 계정을 라이선스 테스터로 추가하면, 진짜 돈을 결코 청구하지 않는 일련의 테스트 결제 수단을 받습니다. Google은 모든 테스트 구매에 구매 대화상자 가운데를 가로지르는 안내를 붙이고, 세금은 계산하지 않습니다. 환불 테스트에서 중요한 것은 어떤 테스트 수단을 고르느냐입니다. 각각이 다른 결과를 이끌기 때문입니다.

테스트 결제 수단무엇을 시뮬레이션하는가왜 사용하는가
Test instrument, always approves깔끔하게 성공한 구매나중에 환불하거나 취소할 수 있는 주문을 준비
Test instrument, always declines실패한 결제거절 시 아무것도 부여하지 않음을 확인
Slow test card, approves after a few minutes나중에 성공하는 대기 중 구매접근을 부여하기 전에 PENDING 처리를 단련
Slow test card, declines after a few minutes나중에 실패하는 대기 중 구매대기 중 거절이 자격을 새지 않음을 확인
Test card, approves then charges back사용자 발생 지불 거절PendingRefundReviewNotification을 발생시키고 24 hours 응답을 리허설

환불, 지불 거절, 그리고 확인 자동 환불을 발생시키기

  • 승인 후 지불 거절하는 테스트 카드로 구매하면, 잠시 후 PendingRefundReviewNotification이 당신의 Real-time Developer Notifications 주제에 도착합니다. 단일 orders.reviewrefund 호출로 응답하세요. Google은 당신의 첫 응답만 보관하기 때문입니다.
  • Play Console의 Orders 탭에서 테스트 주문을 환불하고 취소해 VoidedPurchaseNotification을 발생시키고, 서버가 자격을 회수하는지 확인하세요.
  • 라이선스 테스터의 구매를 일부러 확인되지 않은 채로 두세요. Google은 프로덕션이 허용하는 3 days가 아니라 3 minutes 후에 자동 환불하고 취소를 이메일로 알려줍니다. 그래서 망가진 확인 경로가 프로덕션의 나흘째가 아니라 몇 분 만에 드러납니다.

테스트하지 않은 환불 경로가 실제로 치르게 하는 비용

환불 핸들러는 장식이 아닙니다. 더 이상 당신에게 돈을 내지 않는 사람을 위해 계속 비용을 치르는 것을 멈추게 하는 코드입니다. 그것이 조용히 실패하면 환불 자체는 계속 처리되지만, 그 뒤의 접근과 잔액과 지출은 멈추지 않습니다.

돈을 따라가 보세요. Apple이나 Google이 구매를 환불하면, 당신은 판매 가격을 돌려주고 스토어는 수수료를 돌려주므로 여기까지는 장부가 균형을 이룹니다. 돌아오지 않는 것은 제품을 전달하기 위해 이미 쓴 모든 것입니다. 생성 결과 뒤의 연산, 모델 API 호출, 사용자가 저장한 것의 저장 공간, 이미 창작자에게 보낸 정산금. 접근을 결코 취소하지 않는 환불 핸들러는, 환불된 사용자가 그것들을 당신의 예산으로 계속 쓰게 두고, 그들을 끊어낼 것이 시스템에 아무것도 남지 않습니다.

두 증거 기한이 이를 더 날카롭게 합니다. sandbox에서 한 번도 단련하지 않은 CONSUMPTION_REQUEST는 형식이 잘못되었거나 늦게 보내는 응답이며, 당신의 답이 12 hours 안쪽에 도착하지 않으면 Apple은 흔히 기본값으로 환불을 승인합니다. 테스트 카드로 한 번도 발생시키지 않은 Google Play 지불 거절 응답은 실환경에서 놓치는 24 hours 기한이며, 2026년 8월 3일부터 잃어버린 Play 지불 거절은 구매 가격에서 Play의 서비스 수수료를 뺀 금액에 은행의 지불 거절 수수료를 더한 만큼을 치르게 합니다. 이 실패들 각각은 먼저 테스트 환경에서 무료로 재현할 수 있습니다. 그중 어느 것도 프로덕션에서는 싸지 않습니다.

테스트하지 않은 경로프로덕션에서 어떻게 실패하는가무엇을 치르게 하는가
REFUND 핸들러환불된 사용자가 접근을 유지당신이 그들에게 계속 쓰는 연산, API 호출, 저장 공간, 정산금
CONSUMPTION_REQUEST 응답형식이 잘못됨, 또는 12 hours 후에 전송Apple이 기본값으로 환불을 승인하므로 판매와 지출을 모두 잃음
orders.reviewrefund 응답24 hours 안쪽에서 놓치거나 잘못됨2026년 8월 3일부터, 구매 가격에서 Play의 서비스 수수료를 뺀 금액에 은행의 지불 거절 수수료를 더한 만큼

환불 처리를 출시하기 전 짧은 체크리스트

실험실은 필요 없습니다. 각 이벤트가 당신의 코드에 닿는 것을 한 번 지켜보았어야 합니다.

  • StoreKit 트랜잭션이 revocationDate를 보이는 순간 앱이 접근을 내려놓음. Xcode의 Transaction Manager에서 확인됨.
  • 당신의 sandbox 서버 URL이 TEST 알림을 받고 Apple의 인증서에 대해 검증함.
  • sandbox REFUND이 접근을 취소하거나 잔액을 차감하고, 재전달이 이중 계산되지 않음.
  • sandbox CONSUMPTION_REQUEST이 12 hours의 넉넉한 안쪽에서 유효한 Send Consumption Information 응답을 생성함.
  • 지불 거절 테스트 카드에서 온 Google PendingRefundReviewNotification이 정확히 한 번의 orders.reviewrefund 호출을 생성함.
  • 확인되지 않은 Google Play 테스트 구매가 3 minutes 안에 자동 환불되고, 당신의 대사가 그것을 알아챔.

그 목록을 한 번 돌리면, 환불 처리는 당신이 동작하기를 바라는 코드가 아니게 됩니다. 그것은 당신이 동작하는 것을 지켜본 코드가 됩니다.

자주 묻는 질문

진짜 구매 없이 App Store 환불을 테스트할 수 있나요?
네. Xcode의 StoreKit 테스트는 Transaction Manager를 통해 로컬에서 구매를 환불할 수 있으며, 진짜 돈도 App Store 계정도 필요 없고, 앱의 Transaction.updates 리스너를 발생시킵니다. 서버 알림은 보내지 않으므로 앱만 테스트하고 백엔드는 테스트하지 않습니다.
로컬 StoreKit 테스트는 App Store Server Notifications를 보내나요?
아니요. Xcode의 StoreKit 테스트는 Mac 위의 로컬 구성에 대해 전적으로 동작하며 Apple의 서버에 전혀 연결하지 않으므로, REFUND나 CONSUMPTION_REQUEST를 포함해 App Store Server Notification이 전혀 전송되지 않습니다. 서버를 테스트하려면 sandbox를 사용하세요.
Google Play 지불 거절 응답은 어떻게 테스트하나요?
Test card, approves then charges back이라는 이름의 라이선스 테스터 결제 수단을 사용하세요. 그것은 구매 직후 PendingRefundReviewNotification을 발생시키며, 진짜 은행 지불 거절이 보내는 것과 같은 알림이므로 24 hours의 orders.reviewrefund 응답을 리허설할 수 있습니다.
왜 제 Google Play 테스트 구매가 몇 분 뒤에 환불되나요?
라이선스 테스터의 경우, 앱이 확인하지 않으면 Google은 3 minutes 후에 구매를 자동 환불하고 취소를 이메일로 알려줍니다. 프로덕션은 3 days를 기다리지만, 테스터는 가속된 버전을 받아 망가진 확인 경로가 빠르게 드러납니다.
Apple의 sandbox는 실패한 환불 알림을 재시도하나요?
아니요. sandbox는 App Store Server Notifications를 재시도하지 않으므로, sandbox 환불이 발생할 때 엔드포인트가 다운되어 있으면 알림은 두 번째 시도 없이 버려집니다. 먼저 Request a Test Notification으로 URL이 도달 가능한지 확인하세요.

출처 및 추가 자료

RefundHalt

App Store와 Google Play 환불 자동 처리

계속 읽기

다음 환불 요청은 이미 오고 있습니다.

이의를 제기하지 못한 환불에 관한 지원 이메일을 하나 더 읽는 시간이면 RefundHalt 설정을 마칠 수 있습니다.