Google Play Refund Management

Google Play RTDN vs Voided Purchases API: 환불 방어에는 어느 것을 사용해야 할까?

Google Play RTDN과 Voided Purchases API를 비교하여 앱을 위한 더 강력하고 스마트한 환불 방어 체계를 구축하세요.

5 min read
Google Play RTDN vs Voided Purchases API: 환불 방어에는 어느 것을 사용해야 할까?

빠른 이벤트 처리에는 Google Play RTDN을 사용하세요. 무효화된 주문을 점검하고 기록을 대조할 때는 Voided Purchases API를 사용하세요. 대부분의 유료 앱에는 두 가지를 모두 사용하는 것이 더 안전한 선택입니다.

만약 당신이 앱을 위한 Google Play 환불 방어를 계획하고 있다면, 이 구분에서부터 시작하세요. 하나의 경로는 무언가가 변경되었다는 사실을 알려줍니다. 다른 경로는 서버가 무효화된 구매 목록을 가져와 놓친 것이 없는지 확인할 수 있게 해줍니다.

이 선택은 사실상 두 가지 알림 시스템 사이의 선택이 아닙니다. Google Play RTDN은 Cloud Pub/Sub를 통해 메시지를 푸시합니다. Voided Purchases API는 풀(pull) 방식 API로, 당신의 백엔드가 직접 호출하는 구조입니다.

둘 중 어느 것도 그 자체로는 누군가의 환불 요청을 막지 못합니다. 이들의 가치는 변경 사항을 감지하고, 주문을 점검하고, 유료 액세스가 구매 상태와 일치하도록 보장하는 데 있습니다.

핵심 요약

  • 구매 및 구독 이벤트에 신속히 대응하려면 RTDN을 사용하세요.

  • 영향을 받은 주문을 점검하는 2차 경로로 무효화된 구매 목록을 사용하세요.

  • 구독 취소를 환불의 증거로 간주하지 마세요.

  • 두 경로 모두 동일한 안전한 액세스 업데이트 로직을 사용하도록 하세요.

  • 보류 중인 지불 거부(chargeback) 검토와 완료된 무효화 처리는 별도로 관리하세요.

Google Play RTDN이란?

Google Play 실시간 개발자 알림(Real-Time Developer Notifications), 흔히 RTDN이라 불리는 이 기능은 구매 관련 이벤트를 Cloud Pub/Sub 토픽으로 전송합니다.

백엔드는 메시지를 받아 적절한 워커로 전달합니다. 이때 메시지 유형이 중요합니다. 갱신, 취소, 무효화된 구매는 서로 다른 이벤트입니다.

환불 추적을 위해서는 voidedPurchaseNotification에 특히 주의를 기울여야 합니다. 여기에는 다음이 포함됩니다.

  • purchaseToken: 이벤트를 특정 구매와 연결합니다.

  • orderId: 영향을 받은 주문을 식별합니다.

  • productType: 구독인지 단건 구매인지를 식별합니다.

  • refundType: 전체 무효화인지 수량 기반 부분 환불인지를 구분합니다.

Google의 RTDN 참조 문서 및 이벤트 정의에서 이러한 필드와 다른 알림 유형에 대해 설명하고 있습니다.

RTDN은 변경이 발생한 직후 조치를 취하고자 할 때 유용합니다. 하지만 메시지 하나가 전체 구매 데이터베이스를 대체하지는 못합니다. 액세스를 변경하기 전, 저장된 기록과 대조하고 필요한 경우 관련 구매 상태를 조회하세요.

구독 취소는 환불을 의미하나요?

아닙니다. 고객은 향후 갱신을 중단하면서도 현재 결제 기간이 끝날 때까지는 여전히 유료 액세스를 유지할 수 있습니다.

SUBSCRIPTION_CANCELED가 수신될 때마다 액세스를 제거하는 규칙을 만들지 마세요. 대신 구독 상태와 만료일을 확인하세요. 권한 박탈(revocation)과 만료는 각각 별도로 처리해야 합니다.

Voided Purchases API란?

Google Play Voided Purchases API는 지원 범위 내에서 취소, 환불, 또는 지불 거부(chargeback) 처리된 구매 목록을 반환합니다.

이는 단건 인앱 주문과 구독 모두에 적용됩니다. 서버는 이 결과를 활용해 더 이상 액세스를 부여해서는 안 되는 구매를 확인할 수 있습니다.

목록에는 주문 ID, 구매 토큰, 무효화 시각, 무효화 소스, 무효화 이유가 포함될 수 있습니다. 지원되는 수량 기반 부분 환불의 경우, 환불된 수량도 포함될 수 있습니다.

Google의 Voided Purchases API 가이드에는 30일의 조회 기간이 명시되어 있습니다. 이는 영구적인 환불 보관소가 아닙니다. 처리된 기록은 자체 시스템에 저장해 두세요.

이 API는 워커 장애, 라우팅 버그, 또는 로컬 기록의 누락이 발생한 뒤 특히 유용합니다. 또한 이미 처리한 이벤트에 대한 정기적인 점검 수단이 되기도 합니다.

RTDN vs Voided Purchases API: 실무적 차이

질문

Google Play RTDN

Voided Purchases API

작동 방식은?

Google이 Pub/Sub에 이벤트를 게시합니다.

서버가 목록을 요청합니다.

주요 역할은?

구매 상태 변경에 대한 신속한 처리.

무효화된 주문의 점검 및 대조.

환불 외의 이벤트도 다루나요?

네, 갱신 및 기타 라이프사이클 이벤트를 포함합니다.

무효화된 구매에 초점을 둡니다.

처리 공백 이후에도 도움이 되나요?

Pub/Sub 복구는 설정 및 보존 기간에 따라 달라집니다.

30일 기간 내 사용 가능한 기록을 목록화할 수 있습니다.

중복 방지가 필요한가요?

네.

네, 특히 스캔이 중복되거나 RTDN과 이벤트를 공유할 때는 더욱 그렇습니다.

핵심 질문은 두 도구 중 어느 것이 단독으로 더 나은가가 아닙니다. 각 도구가 어떤 장애 상황을 처리하는 데 도움이 되는가 하는 것입니다.

RTDN은 빠른 경로를 제공합니다. API는 점검 경로를 제공합니다. 이 둘을 종합하는 것은 당신의 데이터베이스가 해야 할 일입니다.

당신의 앱은 어느 것을 사용해야 할까요?

속도가 중요할 때는 RTDN을 사용하세요

유료 앱이라면 구매 상태 변경을 알아차리기 위해 예약된 스캔을 기다릴 필요가 없어야 합니다.

구독, 단건 구매, 무효화된 주문에 대해 신속한 업데이트가 필요할 때 RTDN을 사용하세요. 모든 메시지에 하나의 환불 규칙을 적용하기보다, 각 이벤트를 유형별로 라우팅하세요.

완전성이 중요할 때는 API를 사용하세요

워커가 기록에 반영하지 못한 무효화된 주문을 찾아내려면 예약된 API 점검을 사용하세요.

예를 들어, 수신기는 메시지를 정상적으로 수신했지만 버그로 인해 이후 액세스 업데이트가 중단될 수 있습니다. 전송 문제만 해결한다고 해서 그 로컬 공백이 해결되지는 않습니다.

프로덕션 환불 워크플로우에는 두 가지를 모두 사용하세요

대부분의 유료 앱이라면 두 가지를 결합하세요. 두 경로 모두 주문을 점검하고 안전하게 변경을 적용하는 하나의 공유 핸들러로 연결하세요.

이렇게 하면 하나의 이벤트를 놓쳐 액세스가 계속 활성화되는 위험이 줄어듭니다. 또한 동일한 환불에 대해 액세스를 두 번 제거하는 반대 위험도 줄어듭니다.

Google Play 환불을 단계별로 감지하는 방법

1. 구매 원장(ledger)을 관리하세요

앱 패키지, 구매 토큰, 주문 ID, 제품, 사용자 매핑, 부여된 수량을 저장하세요. 원장이란 간단히 말해 무엇이 구매되었고 그로 인해 어떤 액세스가 부여되었는지에 대한 명확한 기록입니다.

구독의 경우, 갱신 주문 ID도 함께 저장하세요. RTDN 참조 문서에서는 자동 갱신마다 새로운 주문 ID가 생성된다고 설명합니다. 구매 토큰 하나만으로는 영향을 받은 모든 갱신을 식별하기에 충분하지 않습니다.

2. RTDN 메시지를 안전하게 보호하고 라우팅하세요

Pub/Sub 액세스를 올바르게 구성하세요. 푸시 전달 방식이라면 인증된 요청인지 확인하세요. 풀 전달 방식이라면 구독을 읽을 수 있는 대상을 제한하세요.

느린 작업을 실행하기 전에 메시지를 디코딩하고, 패키지 이름을 확인하고, 저장하세요. 테스트 이벤트는 수신 엔드포인트만이 아니라 전체 경로를 통해 전송하세요.

3. 예약된 무효화 구매 스캔을 실행하세요

적절한 자격 증명과 Play Console 권한으로 목록 메서드를 호출하세요. 모든 결과 페이지를 따라가야 합니다.

놓치기 쉬운 두 가지 쿼리 설정이 있습니다.

  • type=1은 단건 구매와 구독을 모두 포함합니다. 기본값인 0은 단건 구매만 포함합니다.

  • includeQuantityBasedPartialRefund=true는 지원되는 수량 기반 부분 환불을 포함합니다. 기본값은 false입니다.

Google의 voidedpurchases.list 메서드 참조 문서에서 요청 및 페이지네이션 필드를 다루고 있습니다.

스캔 간에는 적절한 중복 구간을 두고 결과의 중복을 제거하세요. 스캔 빈도는 처리량, 할당량, 앱이 허용할 수 있는 지연 시간에 따라 선택하세요. 조회 기간이 거의 끝날 때까지 기다리지 마세요.

4. 각 변경 사항은 한 번만 적용하세요

두 경로 모두 동일한 무효화를 보고할 수 있습니다. 멱등적(idempotent) 처리를 구축하세요. 즉, 같은 변경을 다시 실행해도 결과가 달라지지 않아야 합니다.

주문 ID만을 기준으로 이후의 모든 이벤트를 폐기하지 마세요. 다중 수량 구매에는 여러 번의 부분 환불이 발생할 수 있습니다. 처리된 조정 내역과 환불된 수량을 추적하여, 실제로 이후에 발생한 환불이 누락되지 않도록 하세요.

5. 메시지 수뿐만 아니라 공백도 모니터링하세요

마지막 성공한 스캔, 미완료 페이지, 워커 오류, 매칭되지 않은 주문을 추적하세요. 확인된 이벤트 이후 액세스를 업데이트하는 데 걸리는 시간도 측정하세요.

더 넓은 범위의 리포팅에 대해서는 모바일 앱 환불 및 지불 거부 추적 도구 가이드를 참고하세요.

예시: 하나의 환불, 두 가지 감지 경로

이는 가정된 워크플로우이며, 실제 고객 사례가 아닙니다.

한 플레이어가 500코인을 부여하는 단건 패키지를 구매합니다. 이후 해당 구매는 전액 무효화됩니다.

RTDN이 voided-purchase 메시지를 전송합니다. 워커는 해당 주문을 찾아 기록된 부여 내역을 확인하고, 해당 구매와 연결된 코인에 대해 당신이 공표한 정책을 적용합니다.

나중에 예약된 API 스캔이 동일한 주문을 반환합니다. 공유 핸들러는 전체 무효화 조정이 이미 적용되었음을 확인합니다. 이를 매칭 처리로 기록하고, 두 번째 차감은 발생시키지 않습니다.

이번에는 첫 번째 변경을 적용하기 전에 워커가 실패했다고 가정해봅시다. 스캔은 해당 주문을 찾아내어, 시스템이 이를 처리할 수 있는 또 다른 경로를 제공합니다.

바로 이것이 두 가지를 모두 사용하는 목적입니다. 두 번의 별도 제재가 아니라, 하나의 올바른 결과에 도달하는 두 가지 방법입니다.

이미 사용된 코인이 있다면, 관련 없는 다른 유료 패키지에서 무작정 코인을 차감하지 마세요. 명확한 정책을 적용하고, 조치 내용을 설명하며, 지원 경로를 제공하세요.

보류 중인 환불 검토는 별도의 워크플로우입니다

현재 Google 문서에는 개발자의 검토가 필요한 지불 거부(chargeback) 요청에 대해 pendingRefundReviewNotification도 명시되어 있습니다.

이 이벤트에 대해 Google은 24시간 이내에 orders.reviewrefund를 통해 환불 제안과 구매 사용 증거를 제공하라고 안내합니다.

이를 voidedPurchaseNotification과 혼동하지 마세요. 하나는 보류 중인 검토에 관한 것이고, 다른 하나는 이미 무효화된 구매를 보고하는 것입니다.

Voided Purchases API는 보류 중인 검토 이벤트를 처리하는 수단을 대체하지 않습니다. 이 분기는 별도로 유지하고, 모든 환불 요청이 이 이벤트를 생성한다고 가정하지 마세요.

App Store 환불과 수익 누수: 개발자가 알아야 할 사항

수익 누수는 스토어가 돈을 환불했는지 여부에만 국한되지 않습니다. 관련 구매가 더 이상 유효하지 않음에도 백엔드가 계속 유료 액세스를 부여하는 경우도 이에 해당합니다.

두 플랫폼 모두를 운영하는 팀의 목표는 비슷합니다. 즉, 결제, 구매 상태, 액세스 기록을 일관되게 유지하는 것입니다. 다만 스토어별 도구와 이벤트 규칙은 서로 다릅니다. Apple의 워크플로우를 그대로 Google Play에 적용하지 마세요.

저희의 App Store 환불 수익 관리 가이드에서는 더 넓은 범위의 수익 관리 문제를 다룹니다. 이번 Google Play 연동에서는 먼저 놓친 무효화 처리, 중복 차감, 잘못된 구독 액세스 변경에 집중하세요.

Google Play 환불 부정 방지가 할 수 있는 것과 할 수 없는 것

Google Play 환불 부정 방지는 견고한 기록과 공정한 규칙에서 시작됩니다. 무효화된 주문이 고객의 부정 행위를 입증하는 증거는 아닙니다.

고객에게 정당한 불만이 있을 수도 있습니다. 결제가 실패했을 수도 있습니다. 앱이 잘못된 상품을 제공했을 수도 있습니다.

이러한 도구는 사실을 확인하고 액세스 변경을 적용하는 데 사용하세요. 반복되는 패턴은 맥락을 고려하여 검토하세요. 단 한 번의 환불만으로 계정을 자동으로 차단하지 말고, 고객이 오류를 제기할 수 있는 창구를 마련하세요.

RTDN도 목록 API도 환불을 예방, 거부, 또는 취소할 수 있다고 보장하지는 않습니다.

결론

대부분의 유료 앱에게 RTDN과 Voided Purchases API 중 어느 것을 선택할지는 이것 아니면 저것의 문제가 아닙니다.

빠르게 대응하려면 RTDN을 사용하세요. 기록을 대조하려면 예약된 무효화 구매 점검을 사용하세요. 둘 다 하나의 안전한 핸들러를 통해 처리하고, 보류 중인 검토는 완료된 무효화 처리와 분리해서 관리하세요.

작은 테스트부터 시작하세요. 하나의 무효화 처리를 두 경로 모두를 통해 전송하고, 액세스 변경이 단 한 번만 발생하는지 확인하세요. 그런 다음 워커를 중단시키고, 복구 경로가 그 공백을 제대로 포착하는지 확인하세요.

자주 묻는 질문

RTDN은 이벤트를 신속하게 처리하는 데 더 적합합니다. API는 무효화된 주문을 정기적으로 점검하는 데 더 적합합니다. 대부분의 유료 앱은 두 가지를 모두 활용할 때 가장 큰 효과를 봅니다.

네. RTDN에는 주문 및 환불 유형 정보를 담은 voided-purchase 알림이 포함되어 있습니다. 이 이벤트는 구독 취소와는 별도로 처리해야 합니다.

폴링을 통해 사용 가능한 무효화 기록을 감지할 수는 있지만, 감지 시점은 다음 성공적인 스캔까지 기다려야 합니다. 또한 RTDN이 제공하는 더 광범위한 라이프사이클 이벤트 스트림은 놓치게 됩니다.

Google 문서에는 30일의 조회 기간이 명시되어 있습니다. 장기적인 점검과 고객 지원을 위해서는 자체적으로 기록을 보관해 두어야 합니다.

네. 목록 요청에서 지원되는 부분 환불 결과를 활성화하세요. 환불된 수량을 추적하고, 하나의 주문에 여러 번의 부분 환불이 발생할 수 있다는 점을 고려해야 합니다.

#Google Play RTDN#Voided Purchases API#Google Play Refunds#Refund Fraud Prevention#Google Play Billing#In-App Purchase Security
Refund SensorRefund Sensor TeamRefund defense for App Store and Google Play developers