Apple can reverse a refund it already granted, and a reversed refund your server ignores locks out a customer who paid
When the App Store reverses a refund it already granted, it expects your server to reinstate the access you revoked. Here is how the refund, refund declined, and reversed refund notifications work on the App Store and Google Play, and what each one costs when you ignore it.

Key takeaways
- The App Store sends a REFUND_REVERSED notification when it reverses a refund it previously granted because the customer disputed it, and Apple's instruction is explicit: if your app revoked content or services, it needs to reinstate them.
- A REFUND notification means the App Store already refunded the transaction, so your server should revoke the entitlement. A REFUND_DECLINED notification means Apple turned the request down, and the customer keeps both their access and their charge.
- If you revoke on a refund but never handle the reversal, a customer whose charge is reinstated stays locked out. That is a support ticket, a one-star review, and on Google Play a frustration that can turn into a chargeback that now costs you money.
- Apple's revocationReason tells you why the refund happened: value 1 means Apple refunded because of an actual or perceived issue within your app, value 0 means another reason such as an accidental purchase.
- Google Play has no reversal notification. It sends a VoidedPurchaseNotification when a purchase is voided and a separate PendingRefundReviewNotification for chargebacks, and you reconcile the rest with the Voided Purchases API pull model.
- Google Play gives you 24 hours to answer a PendingRefundReviewNotification by calling orders.reviewrefund, and it records only your first call. From August 3, 2026, a lost chargeback costs the developer the price minus Google's service fee plus the bank's fee.
- Handle the App Store refund notifications idempotently. Duplicate deliveries are normal, so key every revoke and reinstate to the transaction id and make a repeat notification a no-op.
A refund is not always the last word. The App Store can reverse a refund it already granted, after the customer disputes it, and when that reversed refund lands on your server it carries one instruction: give the access back. Most teams wire up the plain REFUND notification, cut the customer off, and stop there. They never build the other half. So when the reversal arrives, nothing runs, and a customer who is paying again sits locked out of what they bought. Here is how the full set of refund notifications works on the App Store and Google Play, and what each one costs you when you ignore it.
The App Store sends three refund notifications, not one
Most refund handling is built for a single event: the money went back, cut the customer off. The App Store Server Notifications V2 feed actually carries three separate refund outcomes, and they ask for three different things. Two of them change what a customer can access. One of them undoes the first. Here is the full set, in Apple's own words.
| Notification | What it means | What your server does |
|---|---|---|
| CONSUMPTION_REQUEST | The customer asked for a refund and Apple wants consumption data | Send the consumption payload within 12 hours |
| REFUND | The App Store refunded the transaction | Revoke the entitlement for that transaction |
| REFUND_DECLINED | The App Store declined the refund request | Nothing; the customer keeps access and the charge |
| REFUND_REVERSED | The App Store reversed a refund it had granted | Reinstate the content or service you revoked |
REFUND, the one every team handles
When the App Store processes a refund, it sends a REFUND notification to the URL you configure, and Apple's definition is plain: it 'indicates that the App Store successfully refunded a transaction for a consumable In-App Purchase, a non-consumable In-App Purchase, an auto-renewable subscription, or a non-renewing subscription.' You store the refunded transaction, revoke whatever it bought, and Apple asks you to tell the customer what changed with contextual messaging in the app. This is the notification everyone wires up first, and often the only one.
REFUND_DECLINED, the one that needs nothing from you
REFUND_DECLINED means exactly what it says: 'the App Store declined a refund request.' The customer asked, Apple said no, and the transaction stands. Nothing about the customer's access changes, so your entitlement logic does nothing here. The value of this notification is bookkeeping. It closes the loop on a refund request you may have answered with a CONSUMPTION_REQUEST, and it confirms the customer still has what they paid for. Treat it as a record, not an action.
REFUND_REVERSED, the one that catches teams off guard
This is the notification most refund pipelines never handle. Apple's definition is unambiguous: REFUND_REVERSED 'indicates the App Store reversed a previously granted refund due to a dispute that the customer raised. If your app revoked content or services as a result of the related refund, it needs to reinstate them.' Read that twice. Apple gave the customer a refund, you revoked access, then Apple decided the refund should not stand and pulled it back. The charge is live again. The customer paid, and if your server only knows how to revoke, they are still locked out. A reversed refund is the one refund event that adds access back, and it is the one almost nobody builds for.
What a reversed refund actually costs you
A missed reversal is not a rounding error. Walk the money in both directions, because getting either half wrong has a price.
Miss the reversal and you keep a paying customer locked out. Apple has reinstated the charge, so the customer is out of pocket again, and your app is denying them the thing they bought. The immediate cost is support time and a goodwill refund you may now issue yourself, this time with no store commission coming back to soften it. The slower cost is the review and the churn, and on Google Play that same locked-out frustration is exactly what turns into a chargeback.
Miss the original refund and you keep serving a customer who paid nothing. The mirror mistake is never revoking at all. A refunded customer who still generates images, calls your APIs, and fills your storage runs up real cost against a sale that reversed. The compute, the third-party calls, and the storage are money you already spent, and none of it comes back with the refund.
- Support cost: a human answering a ticket for access that your own code removed and never restored.
- Goodwill refunds: reissuing money to a customer you wrongly locked out, with no store commission returned on a manual gesture.
- Wasted spend: compute, API calls, and storage consumed by a refunded account you never cut off.
- Chargeback risk: on Google Play, a customer who feels double-charged can dispute, and a lost dispute now lands on you.
The reversed refund and the plain refund are the same webhook feed pointing in opposite directions. Handle one and skip the other and you pay on both ends.

Why Apple reverses a refund, and how to read revocationReason
A reversal is not random. Apple ties it to 'a dispute that the customer raised,' which is the customer challenging the refund decision after the fact. When the refund was first granted, the transaction carried a revocationDate and a revocationReason, and that reason is worth reading before anything downstream acts on it.
- revocationReason 1: the App Store refunded 'due to an actual or perceived issue within your app.' That is a signal about your product, not just this customer.
- revocationReason 0: the App Store refunded 'for other reasons, for example, an accidental purchase.' No app-quality signal attached.
When a REFUND_REVERSED arrives for that transaction, the revocation is being undone. Your reinstate logic should look up the original transaction id, confirm you revoked it, and put the entitlement back exactly as it was.
Google Play does not send a reversal, so you reconcile instead
Google Play's model is different, and the difference matters if you run both stores through one webhook handler. There is no Google equivalent of REFUND_REVERSED. Google's Real-time developer notifications split refund events into two messages, and reversals are handled by reconciliation, not a push.
The voided purchase notification
When a Google Play purchase is voided, your server receives a VoidedPurchaseNotification. It names the purchaseToken and orderId, a productType of subscription or one-time, and a refundType that is either a full void or a quantity-based partial refund on multi-quantity purchases. Google says that data is enough to find the right purchase and adjust the entitlement. For anything more, it points you at the Voided Purchases API, a pull model that lists voided orders inside a timestamp range you query.
The chargeback review, and its 24-hour clock
Chargebacks come through a different message, the PendingRefundReviewNotification. When a customer disputes a charge with their bank, Google Play sends this notification and starts a clock. You have 24 hours to call orders.reviewrefund with a refund preference and any usage evidence, so Google can contest an illegitimate chargeback on your behalf. Google records your first call and ignores the rest. This is Google's parallel to Apple's CONSUMPTION_REQUEST, the one window where your side of a dispute counts.
Because there is no reversal push, a chargeback that Google contests and wins does not arrive as a tidy reinstate event. You reconcile it against the Voided Purchases API and your own records. The lesson is the same as on the App Store: a voided order is not always permanent, and your entitlement state has to be able to move back, not just forward.
| Refund event | App Store | Google Play |
|---|---|---|
| Refund granted | REFUND notification | VoidedPurchaseNotification |
| Refund declined | REFUND_DECLINED notification | No separate message |
| Refund reversed | REFUND_REVERSED notification | No push; reconcile via Voided Purchases API |
| Dispute evidence window | CONSUMPTION_REQUEST, 12 hours | PendingRefundReviewNotification, 24 hours |
| Who can issue the refund | Apple only | Google, or you from the Orders tab |
How to handle every refund notification without locking anyone out
You do not need separate pipelines per store. You need a handler that can move an entitlement in both directions and treats every message as possibly duplicated.
- Build reinstate, not just revoke. For every path that removes access on a REFUND, write the inverse that restores it on a REFUND_REVERSED, keyed to the same transaction id.
- Make it idempotent. Both stores can deliver the same notification more than once, so key each revoke and reinstate to the transaction or order id and make a repeat a no-op.
- Read the reason before you act. Use revocationReason to tell an app-quality refund from an accidental one, and route the app-quality ones to whoever owns product quality.
- Answer the evidence windows on time. Send Apple's consumption data within 12 hours of a CONSUMPTION_REQUEST, and call orders.reviewrefund within 24 hours of a PendingRefundReviewNotification.
- Store every event. Keep REFUND_DECLINED and the raw notifications, so a reversal that arrives later can be matched to the refund it undoes.
None of this changes whether a refund happens. It changes whether the customer on the other side of a reversed refund ever notices your server got it wrong.
Frequently asked questions
- What is a REFUND_REVERSED notification on the App Store?
- It is the App Store telling your server that it reversed a refund it had previously granted, because the customer disputed it. Apple's instruction is explicit: if your app revoked content or services as a result of that refund, it needs to reinstate them. The charge is live again, so the customer should get their access back.
- What should I do when I get a REFUND_DECLINED notification?
- Nothing to the customer's access. REFUND_DECLINED means the App Store turned down the refund request, so the transaction stands and the customer keeps what they paid for. Treat it as a record that closes out the refund request, often one you answered with a CONSUMPTION_REQUEST.
- Does Google Play send a notification when a refund or chargeback is reversed?
- No. Google Play has no equivalent of Apple's REFUND_REVERSED. It sends a VoidedPurchaseNotification when a purchase is voided and a PendingRefundReviewNotification for chargebacks, but a contested chargeback that Google wins is not pushed back to you. You reconcile it using the Voided Purchases API and your own records.
- How long do I have to respond to a Google Play chargeback?
- 24 hours. When Google Play sends a PendingRefundReviewNotification, you have 24 hours to call orders.reviewrefund with a refund preference and usage evidence. Google records only your first call. From August 3, 2026, a lost chargeback costs the developer the price minus Google's service fee plus the bank's fee.
- What does revocationReason tell me on a refunded App Store transaction?
- It tells you why Apple refunded. Value 1 means Apple refunded due to an actual or perceived issue within your app, which is a product signal. Value 0 means another reason, such as an accidental purchase. Reading it lets you separate refunds that point at a bug from routine ones.
Sources and further reading
- Apple Developer: App Store Server Notifications V2 notificationType
- Apple Developer: Handling refund notifications
- Apple Developer: revocationReason (App Store Server API)
- Android Developers: Real-time developer notifications reference
- Google Play Developer API: Method orders.reviewrefund
- Play Console Help: Updates to refund protection and chargeback cost responsibility
- Google Play Developer: Voided Purchases API
RefundHalt
The refund autopilot for the App Store and Google Play
Keep reading
Who pays for a refund on your app is mostly you, but not for the commission you think you're losing
When a customer is refunded, both Apple and Google hand their commission back, so the store's cut is not what you lose. Here is who pays for a refund on your app, what actually leaves your payout, and why a chargeback costs more than a plain refund.
Cancelling a subscription and getting a refund are two different things, and only one gives your customer money back
Cancel a subscription and the store just stops the next charge, the customer keeps access to the end of the period, and no money moves. A refund reverses a payment that already cleared and pulls the access with it. Here is where the two split, what each costs you, and why only a refund ever reaches your server.