Apple's CONSUMPTION_REQUEST, explained: the 12 hours that decide your refund
When a customer asks Apple for a refund, Apple asks you first. Here's exactly what the CONSUMPTION_REQUEST notification contains, what Apple expects back, how to answer one end to end, and why most developers silently forfeit.
핵심 요약
- When a customer requests an App Store refund, Apple sends your server a CONSUMPTION_REQUEST notification and waits up to 12 hours for evidence before deciding.
- You respond by calling the Send Consumption Information endpoint with a small payload: consent, delivery status, sample content, consumption percentage, and your refund preference.
- Silence is an answer: if you send nothing, Apple decides from the customer's claim and account history alone.
- Consent is a hard gate. Apple's documentation says that without the customer's consent to share consumption data, you should not respond at all.
- For auto-renewable subscriptions Apple calculates the consumption percentage itself from elapsed time; sending your own value returns an error.
- The window is too short for a manual process. The developers who benefit are the ones whose response is generated and submitted automatically.
Here is what this whole mechanism is about: Apple decides every App Store refund itself, but it does not want to decide blind. So it built a formal channel for your side of the story. When a customer requests a refund, Apple pauses, sends your server a question, and gives you a fixed window to answer with facts about the purchase. Answer well and unreasonable requests get declined. Ignore it and Apple rules on the customer's word alone.
Every App Store refund starts the same way: a customer opens reportaproblem.apple.com, picks a purchase, and taps a reason. What most developers don't know is what happens next — Apple turns to you and asks for evidence before it decides.
The notification nobody answers
If your app has App Store Server Notifications V2 configured, Apple sends a CONSUMPTION_REQUEST notification the moment the refund is requested. The payload names the transaction, the product, and — since 2024 — the customer's stated reason: UNINTENDED_PURCHASE, FULFILLMENT_ISSUE, UNSATISFIED_WITH_PURCHASE, LEGAL, or OTHER.
From that moment you have 12 hours to call the Send Consumption Information endpoint with your side of the story. The current payload is deliberately small: five fields, numbers and flags only.
| Field | What it tells Apple | Example |
|---|---|---|
| customerConsented | The customer agreed that usage data may be shared | true |
| deliveryStatus | Whether the purchase was delivered and works | DELIVERED |
| sampleContentProvided | A free sample or trial existed before purchase | true |
| consumptionPercentage | How much of the purchase was used, 100% = 100000 | 67500 |
| refundPreference | Your preference: decline, grant, or no preference | DECLINE |
What Apple does with your answer
Apple explicitly uses consumption information as an input to its refund decision. Send nothing and the decision is made entirely from the customer's claim and account history. Send evidence — '87 scans in six days' reads very differently from silence — and contested refunds are frequently declined.
How to answer one yourself, end to end
If you want to build the response path in-house, this is the full sequence. None of it is secret; all of it has to work at 3 a.m.
1. Get the notification flowing
In App Store Connect, open your app's App Information page and set a Production Server URL under App Store Server Notifications, on Version 2. V1 does not carry consumption requests. Apple will now POST every notification, refunds included, to that URL as a signed JWS payload.
2. Create the right key
Responses are authenticated with an In-App Purchase key from Users and Access, under Integrations. This is its own key type: the App Store Connect API key next to it will not work. You download the .p8 once, then mint a short-lived ES256 JWT for every call.
3. Verify, match, decide
When the CONSUMPTION_REQUEST arrives, verify the JWS signature chain against Apple's root certificates before trusting a byte of it. Then match the transaction to your user, ideally through the appAccountToken UUID you attached at purchase, and pull their real usage. Decide your preference: grant the goodwill cases, contest the consumed ones.
4. Send it back in time
PUT your five fields to the Send Consumption Information endpoint for that transaction id, within the 12-hour window. Two traps catch almost everyone: the percentage is in milliunits, so 100% is 100000, not one million; and consent is a gate, because Apple's own documentation says that without customer consent you should not respond at all. Add the consent language to your terms of service before you ship any of this.
Why developers forfeit
Twelve hours is a brutal window for a human process. The notification can land at 3 a.m. on a Saturday. It requires a server that verifies Apple's JWS signature chain, matches the transaction to a user, computes a consumption percentage in milliunits, and calls a JWT-authenticated API — per request, every time, forever.
The practical checklist looks like this:
- Configure App Store Server Notifications V2 so the request reaches you at all.
- Verify the signed payload against Apple's certificate chain before trusting it.
- Match the transaction to your own user, usually through the appAccountToken you attached at purchase.
- Compute a consumption percentage from real usage, not guesswork.
- Call Send Consumption Information with an In-App Purchase key before the window closes.
That's the entire reason RefundHalt exists: the response is generated and submitted in seconds, from real usage data when you connect it, with your policy applied — grant the goodwill cases, contest the rest. The 12-hour window stops being a threat and becomes your home-field advantage.
자주 묻는 질문
- What happens if I never respond to a CONSUMPTION_REQUEST?
- Apple still decides the refund, but only from the customer's claim and account history. You lose the only opportunity to show that the purchase was delivered and heavily used. In practice unanswered requests are approved far more often.
- Do I need the customer's consent to send consumption data?
- Yes. Apple requires that customerConsented is true, and that you actually obtained that consent, typically through your terms of service or privacy policy. Apple's documentation says that without consent you should not respond to the notification at all.
- Can I send a consumption percentage for subscriptions?
- Only for non-renewing subscriptions. For auto-renewable subscriptions Apple calculates consumption from elapsed time in the current billing period and the API rejects a supplied percentage. Your evidence still drives the refund preference.
- Which key do I use to call the API?
- An In-App Purchase key, created in App Store Connect under Users and Access, Integrations. It is a different key type from the App Store Connect API key, and the .p8 file can only be downloaded once, at creation.
- How fast do I really need to answer?
- Apple's production window is 12 hours from the notification. In the sandbox environment it is only 5 minutes, which is a hint about the direction Apple expects: an automated response, not a human one.
출처 및 추가 자료
RefundHalt
App Store와 Google Play 환불 자동 처리
계속 읽기
아이가 저지른 무단 인앱 결제는 거의 매번 부모에게 환불되고, 그 비용은 개발자가 떠안습니다
아이가 부모의 휴대폰에서 코인 팩을 구매하면 Apple과 Google 모두 그것을 환불하며, 어느 쪽도 먼저 개발자에게 묻지 않습니다. 규제 당국이 그렇게 만들도록 했기 때문입니다. 이러한 무단 인앱 결제 환불이 각 스토어에서 어떻게 처리되는지, 돈이 오가는 15분의 창, 그리고 실제로 얼마의 손실이 되는지 설명합니다.
앱 환불 세금은 애초에 당신의 것이 아니었으므로, 환불로 잃는 것은 영수증의 총액이 아니라 당신의 몫입니다
앱 내 구매를 환불하면 영수증에는 가격과 세금이 함께 돌아가는 것으로 표시됩니다. 그 세금은 애초에 당신의 돈이 아니었습니다. Apple 과 Google 이 merchant of record 로서 이를 징수하고 납부하며, 환불 시 당신의 몫에는 손대지 않고 되돌립니다. 환불이 실제로 얼마의 비용인지, 그리고 세금이 당신의 것이 되는 유일한 설정을 설명합니다.