App Store Refund Management

Apple CONSUMPTION_REQUEST 내부 분석: 환불을 결정짓는 반나절

모든 App Store 환불은 Apple의 결정이지만, CONSUMPTION_REQUEST는 구매에 대한 사실을 제시할 수 있는 정해진 시간을 제공합니다. 제대로 답변하면 부당한 주장은 거부됩니다. 침묵하면 Apple은 고객의 주장만을 듣게 됩니다.

5 min read
Apple CONSUMPTION_REQUEST 내부 분석: 환불을 결정짓는 반나절

모든 App Store 환불은 Apple의 결정이지만, Apple도 아무 정보 없이 결정을 내리고 싶어하지는 않습니다. 환불 요청이 들어오면 처리 과정이 일시 중단되고, 여러분의 서버에 질문이 전달되며, 구매에 대한 사실로 답변할 수 있는 정해진 기간이 열립니다. 실질적으로 답변하면 부당한 주장은 거부됩니다. 침묵하면 Apple은 고객의 주장만을 듣게 됩니다.

핵심 요약

  • App Store에서 환불이 요청되면 Apple은 여러분의 서버로 CONSUMPTION_REQUEST 알림을 전송한 뒤, 최대 12시간 동안 증거를 기다렸다가 판정을 내립니다.

  • 응답한다는 것은 동의 여부, 전달 상태, 샘플 제공 여부, 소비량, 원하는 결과를 담은 간결한 페이로드로 Send Consumption Information 엔드포인트를 호출하는 것을 의미합니다.

  • 아무것도 보내지 않는 것 자체도 하나의 응답입니다. Apple은 고객의 주장과 계정 이력만을 근거로 진행합니다.

  • 동의는 절대적인 전제 조건으로 작동합니다. Apple의 문서에는 고객이 자신의 소비 데이터 공유에 동의하지 않은 경우 아예 응답하지 말아야 한다고 명확히 명시되어 있습니다.

  • 자동 갱신 구독의 경우 소비율은 Apple이 경과 시간을 기준으로 산출하며, 직접 값을 제공하면 오류가 발생합니다.

  • 수동 처리로는 그 시간 안에 맞출 수 없습니다. 이 과정에서 이득을 보는 개발자는 응답이 자동으로 작성되고 제출되는 쪽입니다.

App Store의 모든 환불은 동일하게 시작됩니다. 누군가 reportaproblem.apple.com에 접속해 구매 항목을 선택하고 사유를 고릅니다.

대부분 응답되지 않는 알림

App Store Server Notifications V2가 설정된 앱은 환불이 요청되는 즉시 CONSUMPTION_REQUEST 알림을 받습니다. 이 페이로드에는 거래 정보, 제품 정보, 그리고 2024년부터는 고객이 선택한 사유(UNINTENDED_PURCHASE, FULFILLMENT_ISSUE, UNSATISFIED_WITH_PURCHASE, LEGAL, OTHER 중 하나)가 포함됩니다.

이 시점부터 12시간이 시작되며, 그 사이 Send Consumption Information 엔드포인트를 호출해 여러분의 입장을 공식적으로 기록할 수 있습니다. 이 엔드포인트가 요구하는 정보는 의도적으로 최소화되어 있으며, 플래그와 숫자로만 구성된 다섯 개의 필드뿐입니다.

  • customerConsented는 고객이 자신의 사용 데이터 공유에 동의했는지를 Apple에 알립니다. 일반적인 값은 true입니다.

  • deliveryStatus는 구매 항목이 정상적으로 전달되고 작동했는지를 Apple에 알립니다. 일반적인 값은 DELIVERED입니다.

  • sampleContentProvided는 사전에 무료 샘플이나 체험판이 제공되었는지를 Apple에 알립니다. 일반적인 값은 true입니다.

  • consumptionPercentage는 소비된 비율을 Apple에 알리며, 밀리단위(milliunit)로 표현되어 100000이 100퍼센트를 의미합니다. 일반적인 값은 67500입니다.

  • refundPreference는 여러분이 선호하는 결과, 즉 승인, 거부, 또는 선호 없음 중 어느 것인지를 Apple에 알립니다. 일반적인 값은 DECLINE입니다.

consumptionPercentage는 소비성 상품, 일회성 구매, 갱신되지 않는 구독에 한해 적용됩니다. 자동 갱신 구독의 경우 Apple이 결제 주기 내 경과 시간을 기준으로 이 값을 직접 산출하며, 여러분이 제공하는 값은 어떤 것이든 거부됩니다.

Apple이 여러분이 보낸 정보를 처리하는 방식

소비 정보는 Apple이 환불 결과를 결정하는 데 명시적으로 활용하는 입력값입니다. 아무것도 보내지 않으면 판정은 순전히 고객의 주장과 계정 이력에만 근거해 내려집니다. 증거를 보내면 이의가 제기된 환불이 실제로 상당한 빈도로 거부됩니다.

응답 경로를 처음부터 끝까지 직접 구축하기

이 과정에 비밀스러운 부분은 전혀 없습니다. 다만 이 모든 것이 새벽 3시에도 사람 없이 작동해야 합니다.

1. 알림이 도착하도록 설정하기

App Store Connect에서 해당 앱의 App Information 페이지를 열고, App Store Server Notifications 항목 아래에서 Version 2를 선택해 Production Server URL을 설정합니다. 소비 요청은 V1으로는 전달되지 않습니다. 이후 환불을 포함한 모든 알림이 서명된 JWS 페이로드 형태로 POST 방식으로 해당 URL에 도착합니다.

2. 올바른 키 생성하기

응답 인증에는 Users and Access의 Integrations 섹션에서 생성하는 인앱 구매 키(In-App Purchase key)를 사용합니다. 이는 별도의 키 유형으로, 바로 옆에 있는 App Store Connect API 키로는 이 호출을 인증할 수 없습니다. .p8 파일은 정확히 한 번만 다운로드되며, 이후에는 요청마다 단기 유효한 ES256 JWT를 직접 발급해야 합니다.

3. 검증하고, 매칭하고, 결정하기

도착한 CONSUMPTION_REQUEST 알림은 내용의 어떤 부분이든 신뢰하기 전에 Apple의 루트 인증서를 기준으로 JWS 서명 체인을 검증해야 합니다. 그다음에는 구매 시 첨부한 appAccountToken UUID 등을 활용해 거래를 사용자와 연결하고, 실제 사용 내역을 확인합니다. 마지막으로 선호를 결정합니다. 선의로 처리할 상황은 받아들이고, 제품이 명확히 소비된 경우는 이의를 제기합니다.

4. 시간이 끝나기 전에 제출하기

12시간 이내에 해당 거래 ID를 대상으로 Send Consumption Information 엔드포인트에 이 다섯 개 필드를 PUT으로 전송합니다. 거의 모든 사람이 두 가지 실수를 저지릅니다. 비율은 밀리단위로 표현되므로 100%는 100만이 아니라 100000을 의미합니다. 그리고 동의가 전체 과정의 전제 조건이 되는데, Apple의 공식 문서에서는 고객 동의가 없는 경우 아예 응답하지 말아야 한다고 명시하고 있기 때문입니다. 이 기능을 출시하기 전에 해당 동의 관련 문구를 이용약관에 반드시 포함시켜야 합니다.

그토록 많은 개발자가 기회를 놓치는 이유

반나절이라는 시간은 사람이 직접 처리하기에는 가혹한 수준입니다. 알림은 토요일 새벽 3시에도 도착합니다. 이를 처리하려면 Apple의 JWS 서명 체인을 검증하고, 거래를 사용자와 연결하고, 소비율을 밀리단위로 계산하고, JWT로 인증된 API를 호출할 수 있는 서버가 필요합니다. 모든 단일 요청마다, 끝없이 말입니다.

실질적으로 체크리스트는 다음과 같습니다.

  • App Store Server Notifications V2를 설정합니다. 이것이 없으면 요청 자체가 여러분에게 전달되지 않습니다.

  • 신뢰를 부여하기 전에 서명된 페이로드를 Apple의 인증서 체인에 대해 검증합니다.

  • 일반적으로 구매 시 첨부된 appAccountToken을 통해, 거래를 여러분 시스템 내 사용자와 연결합니다.

  • 추정이 아니라 실제로 기록된 사용 내역을 바탕으로 소비율을 산출합니다.

  • 시간이 남아 있는 동안 인앱 구매 키를 사용해 Send Consumption Information을 호출합니다.

Refund Sensor는 바로 이 부담을 대신 짊어지기 위해 존재하며, 누구도 깨우지 않고도 시간 안에 충분한 여유를 두고 증거를 갖춘 완전한 응답을 제출합니다.

이 규칙들이 문서화된 곳

자주 묻는 질문

환불은 여전히 결정되지만, 이번에는 고객의 주장과 계정 이력만을 근거로 이루어집니다. 구매가 정상적으로 전달되었고 충분히 사용되었다는 사실을 입증할 유일한 기회를 놓치게 됩니다. 실제로 응답하지 않은 요청은 훨씬 더 자주 승인됩니다.

네, 필요합니다. customerConsented 값은 true여야 하며, 이 플래그의 근거가 되는 동의는 실제로 존재해야 하고, 보통 데이터 공유를 다루는 법적 문서에 기록됩니다. Apple의 자체 가이드라인에서도 그러한 동의가 없는 경우에는 알림에 아예 응답하지 말라고 안내합니다.

갱신되지 않는 구독에만 가능합니다. 자동 갱신 구독의 경우 Apple이 현재 결제 주기 내 경과 시간을 기준으로 소비율을 자체적으로 산출하며, 직접 제공하는 비율 값은 API에서 거부됩니다. 다만 환불 선호도(refundPreference)는 여전히 영향을 미칩니다.

App Store Connect의 Users and Access 내 Integrations에서 생성하는 인앱 구매 키(In-App Purchase key)입니다. 이는 App Store Connect API 키와는 다르며, .p8 파일은 생성 시점에 단 한 번만 다운로드할 수 있습니다.

프로덕션 환경에서는 알림 발생 후 12시간이 주어집니다. 샌드박스 환경에서는 단 5분뿐인데, 이는 Apple이 기대하는 것이 사람이 아니라 자동화라는 점을 상당히 직접적으로 보여주는 신호라고 볼 수 있습니다.

#consumption request#send consumption information#app store server notifications#refunds#storekit#ios
Refund SensorRefund Sensor TeamRefund defense for App Store and Google Play developers