Who actually decides when your user gets a refund?
Sooner or later a support email arrives that says “I want my money back.” What you can do about it depends entirely on which store took the payment. On the App Store, the answer is almost nothing directly: Apple decides, and you get one structured chance to weigh in. On Google Play, the first 48 hours belong to Google and every day after that belongs to you. Those are two different jobs, and most apps are set up for neither.
On the App Store, Apple is the only one with the button
App Store Connect has no refund button. Every In-App Purchase and paid download is refunded,
or not, by Apple. The customer asks through Apple’s own channels: the Report a Problem
site, Apple support, or a refund sheet you can open inside your app with StoreKit’s
beginRefundRequest. That sheet doesn’t give you any say. It just saves the
customer from hunting for the right Apple page.
So the honest reply to an App Store refund email is a link and a sentence: we can’t issue App Store refunds ourselves, here’s where to request one. Don’t promise an outcome you don’t control. A customer told “sure, you’ll get it back” who then gets declined is angrier than one who was pointed to the right door.
Your one lever: the consumption request
If you’ve set up App Store Server Notifications (version 2), Apple tells your server when
a refund request comes in with a CONSUMPTION_REQUEST notification. Apple sends it
for every product type: consumables, non-consumables, non-renewing subscriptions and
auto-renewing subscriptions. You then have 12 hours to answer by calling the Send
Consumption Information endpoint. Apple’s documentation says plainly that it
“uses a variety of factors” to decide, and that your data informs the decision.
It’s evidence, not a veto.
The current request body is short. It has five fields:
customerConsentedmust betrue. Apple rejects anything else with an HTTP 400.deliveryStatussays whether the purchase was delivered and works. If it isn’tDELIVERED, you must report consumption as zero or the call fails.consumptionPercentageis how much of the purchase the customer used, in milliunits, so 100,000 means all of it.sampleContentProvidedsays whether the customer could try the content, or read what it did, before buying. A free trial counts.refundPreferenceis optional.GRANT_FULLandDECLINEwork for every product type. For an auto-renewing subscription you can also sendGRANT_PRORATED, and Apple works out the percentage itself.
The catch is the first field. You may only send this data if the customer consented to you sharing it with Apple, and that consent has to exist before the request arrives. Apple is specific: consent should be opt-in, the customer must be able to withdraw it, and you may not use the App Tracking Transparency prompt for it. If you adopt the endpoint, your privacy label has to disclose the data too. Without consent, the documented answer is to stay silent.
That makes this a decision to take once, at design time, not in the moment. If your app sells consumables, such as credits, AI generations or in-game currency, the consumption data is the strongest case you can make against a “bought 500 credits, spent 490, asked for a refund” pattern, and a consent line at the point of purchase is worth the copywriting. If you sell a subscription people mostly cancel honestly, it may not be worth the extra privacy surface at all. Both are defensible. Drifting into neither is the expensive option, because every 12-hour window then passes with nothing from you.
After Apple decides
The decision arrives as another notification: REFUND when Apple grants it,
REFUND_DECLINED when it doesn’t, and occasionally
REFUND_REVERSED when Apple undoes a refund it already granted. The one that
matters for your code is REFUND. The money is already gone from your proceeds, so
the entitlement should go too: remove the Pro flag, claw back unspent credits, end the
subscription access. Apps that skip this end up giving the product away to anyone who knows to
ask Apple. And if you handle REFUND, handle REFUND_REVERSED as well,
or a customer whose payment was restored stays locked out.
On Google Play, the clock hands it to you
Google’s consumer policy is built around time. Within 48 hours of a purchase, a customer can ask Google directly, and Google may refund depending on the details. Paid apps also get a short return window right after the first purchase; Google's developer help page puts it at up to two hours, and returning the app uninstalls it. After 48 hours, Google’s help page tells the customer to contact the developer, who “can process refunds according to their policies and applicable laws.”
In other words, past day two, the refund policy on Google Play is whatever you decide it is. You issue refunds from the Order management page in Play Console, on the web or in the Play Console app, and a few mechanics are worth knowing before the first request lands:
- Partial refunds work only on the website, only for in-app purchases and subscriptions (not paid apps), and only on orders placed after March 2018. You can issue several, but never for the whole order total.
- Which subscription order you pick matters. Refunding the most recent order refunds it, removes the subscription immediately and stops renewals. Refunding an older order refunds the money but leaves the subscription running.
- Cancelling isn’t refunding. A cancelled subscriber keeps access until the period ends and gets nothing back.
- Refunds can’t be undone. Click once.
- Google returns its service fee on refunded money, shown on your next earnings report, so a full refund costs you your share of the sale, not the full price.
Refunds that happen outside your console, through Google’s 48-hour flow, a chargeback or
a cancelled payment, still need to reach your entitlement logic. Play sends a
voidedPurchaseNotification through Real-time Developer Notifications, with the
order ID, the product type and whether the refund was full or a partial quantity refund. The
Voided Purchases API lets you pull the same events for a time range, which is useful as a
nightly sweep in case a notification went missing. Treat a voided purchase exactly like
Apple’s REFUND: take the entitlement back.
Write the policy down before you need it
Because Google makes you the decider, the worst time to invent a refund policy is while reading an angry email. A short written rule keeps you consistent and keeps you from being generous to the loudest customer and stingy to the polite one. A workable one fits in three lines, and yours probably can too:
- Something broke on our side (a failed delivery, a double charge, a feature that never worked on their device): refund in full, no argument.
- Forgot to cancel a renewal and hasn’t used it since: refund the latest renewal.
- Used the product heavily and changed their mind: cancel the renewal, explain why the past period stands.
Then put the store-specific routing in your support macros, because the customer doesn’t know or care which store they paid through. App Store purchase: here’s Apple’s refund page. Play purchase under 48 hours: you can request it from Google directly, or we’ll handle it. Play purchase older than that: we’ll look at it, and here’s our rule.
CONSUMPTION_REQUEST within 12 hours or not at all. On
Google, you own every refund after 48 hours, so write the rule down. On both, a refund
notification must remove the entitlement, and a reversal must restore it.
Fewer refunds start on the product page
The cheapest refund is the one nobody asks for, and a lot of “this isn’t what I thought it was” requests trace back to a listing that promised a different app. Keep your screenshots showing what the paid tier actually does, and say where the paywall sits. ShotCanvas makes it quick to keep that set honest as the app changes.