"I paid for this and it wasn't what I expected. Please refund me." I read that one-star review first thing in the morning, before coffee.
When you ship as an indie developer, the review reply box is one of the few places your voice reaches someone. I didn't want to leave them waiting, so I wrote back the same hour: I'll process your refund.
A few days later the same person posted again. No refund had arrived.
What I want to say first is that the refund was never mine to promise. On iOS, there is no mechanism for a developer to refund a purchase. On Android the opposite is true — you can refund it yourself, in a couple of clicks, permanently. The same sentence in a review needs two completely different replies.
On iOS there is no refund button on your side
Apple receives and decides every App Store refund. The customer has three paths:
- Contact Apple Support and ask for a refund
- Sign in to reportaproblem.apple.com and request one there
- Ask their payment method issuer
None of them route through you. Both the evidence and the decision stay between Apple and the customer.
That doesn't mean you're left in the dark. If you've configured App Store Server Notifications, Apple sends a REFUND notification to your server once a refund is processed. Apple's refund notification documentation is explicit that this notification covers consumables, non-consumables, and non-renewing subscriptions. Refunds on auto-renewable subscriptions are not carried by it and have to be detected separately.
When the notification lands, there are only two fields worth reading:
{
"unified_receipt": {
"latest_receipt_info": [
{
"product_id": "com.example.app.coins_100",
"purchase_date_ms": "1757980800000",
"cancellation_date_ms": "1758153600000"
}
]
}
}Several transactions can share a product_id, so pick the one with the newest purchase_date_ms. The cancellation_date_ms is when Apple issued the refund; transactions that weren't refunded don't carry it. Your server has to answer the POST with a 200.
So on iOS the decision happens outside your reach, and only the outcome flows back to you afterwards. Knowing that ordering is what changes the sentence you're allowed to write in a reply.
On Android you can refund it yourself, and you can't take it back
Google Play inverts this. In Play Console you open Order management, find the order by order ID or the buyer's full email address, and issue a full or partial refund. The Play Console app can do the same.
The freedom comes with edges worth knowing before you need them.
First, a refund cannot be reversed. There is no undo if you click the wrong row.
Second, partial refunds have conditions. They don't apply to paid apps at all — only to in-app purchases and subscriptions, and only for orders placed after March 2018.
Third, the money comes from you. Refunded amounts are deducted from a future payout. Google returns its service fee, but if a refund pushes your balance negative and it stays negative for 48 hours, Google debits the bank account that normally receives your payouts. Running small, that one line is worth reading twice.
Fourth, permissions. Anyone other than the account owner needs the "Manage orders" permission to refund. Even working alone, it's better to open that screen on a calm day than on the morning a review arrives.
Keep two replies ready before you need them
| What to check | iOS (App Store) | Android (Google Play) |
|---|---|---|
| Can the developer refund? | No | Yes, via Play Console Order management |
| Where the customer goes | Apple Support or reportaproblem.apple.com | Google Play Help, or straight to you |
| Partial refunds | Not yours to issue | In-app purchases and subscriptions only |
| Reversing a refund | Not applicable | Not possible |
| How you learn the outcome | REFUND in App Store Server Notifications | Order status in Order management |
With that table on the desk, I split my replies in two.
For iOS, I say up front that the decision isn't mine, then point to the exact entry point. Writing only "that's Apple's call" reads as a brush-off; naming the page they should open does not.
For Android, I ask for what I need to locate the order. Search only works on a full email address match, so asking for it in the first reply saves a round trip.
Both replies open with the same kind of question before any refund talk — what, specifically, was different from what they expected.
The part I kept getting wrong came after the refund
On Google Play, cancelling a subscription and refunding it are separate actions. Cancelling issues no refund, and the subscriber keeps access until the billing period ends. Refunding the most recent order in a subscription refunds it, removes access immediately, and stops future renewals. Refunding an older order refunds only that order and leaves the subscription active. One word, three outcomes.
On iOS, everything after the notification is yours. Apple's documentation states plainly that storing, monitoring, and taking appropriate action on each refunded transaction is the developer's responsibility, and that you should tell the customer in-app about anything you do as a result.
Consumables are where this slips. A refund can complete while the coins are already spent, and nothing rebalances on its own. Whether you claw it back, absorb it, or watch for repeat refunds is a decision that lives outside the notification. I've written about a neighbouring case — access quietly disappearing for reasons you didn't trigger — in the four triggers that make IAP vanish under Family Sharing.
The store decides whether a refund happens. I decide what gets taken back afterwards.
Keeping those two apart is what stopped me hedging in review replies.
Where I drew the line between apologising and promising
Looking back at that morning, I don't think I believed I could refund it. I wanted the disappointment to stop quickly, and I wrote that I could before I checked whether I could.
Now the reply has two stages. The first is an apology for the gap between expectation and reality, plus one question about what that gap actually was. The second stage carries the store-specific procedure. Separating them keeps unverified promises out of the first thing someone reads.
Running a wallpaper app and a sleep-sound app over a long stretch taught me something I didn't expect: a fair share of refund requests were not really about money. People couldn't find the feature they'd paid for, or hadn't noticed the restore-purchases path. The strongest wording often came from the smallest dead end. That's what the first-stage question is for. If replying at volume is the bottleneck, how I halved the time I spend on App Store review replies covers the operational side.
Open your own reply box and check one thing: whether any recent reply promises a refund you can't issue. That's where I started. If one does, the matching column in the table above is your second message, more or less verbatim.
If you're still deciding how to charge in the first place, the monetization basics for apps built with Rork is probably the better place to begin. Thank you for reading this far.