Missed refund notifications can cost you the only refunds you're allowed to contest, and both stores let you get them back if you look in time
When your server misses a refund notification, the two refund flows that ask for your evidence close without you. Here's how Apple and Google Play retry, how far back you can recover missed refund notifications, and where the recovery gaps are.

Key takeaways
- Apple retries a failed App Store Server Notifications V2 delivery five times, at 1, 12, 24, 48 and 72 hours after the previous attempt, so the second retry lands about 13 hours after the first try.
- Apple asks developers to answer a CONSUMPTION_REQUEST within 12 hours of receiving it, so a server that misses the first delivery and the one-hour retry can see the request only after that window has likely passed.
- Apple's Get Notification History endpoint returns V2 notifications from the past 180 days in production, 20 records per page, and its onlyFailures flag limits the results to notifications that never reached your server, plus any still being retried.
- Google Play delivers chargeback reviews only through a PendingRefundReviewNotification, and the pendingRefundToken needed to call orders.reviewrefund within 24 hours comes in that notification. Google documents no separate API that lists pending reviews.
- Google Cloud Pub/Sub keeps unacknowledged messages for 7 days by default, with a maximum of 31 days, and deletes a subscription after 31 days without subscriber activity unless you change its expiration period.
- The Google Play Voided Purchases API recovers refunds, revocations and chargebacks from the past 30 days, with a quota of 6,000 queries per day and 30 queries in any 30-second period, but it can't recover a chargeback review you never answered.
- Apple's sandbox sends each notification once with no retries, so a recovery routine that only ever ran against sandbox has never been tested against Apple's real retry schedule.
Missed refund notifications are the quiet way a developer loses the only two refund decisions they get a say in. Apple's CONSUMPTION_REQUEST and Google Play's chargeback review both start with a notification, and both close on a short clock: 12 hours on Apple, 24 hours on Google. If your server is down, slow or misconfigured when that message arrives, the store doesn't wait for you. It decides with whatever it already has.
The good news is that neither store throws the message away on the first failure. Apple retries and keeps a 180-day history you can query. Google publishes through Pub/Sub, which holds unacknowledged messages for days. The bad news is that the retry timing doesn't line up with the response windows, and one of the two flows has no recovery API at all.
How each store delivers refund notifications
Apple sends App Store Server Notifications straight to an HTTPS URL you set in App Store Connect. Google doesn't call your server directly. It publishes Real-time developer notifications to a Google Cloud Pub/Sub topic, and your subscription on that topic either pushes them to your endpoint or waits for your server to pull them.
| Question | App Store | Google Play |
|---|---|---|
| Delivery channel | HTTPS POST to your URL | Cloud Pub/Sub topic, push or pull |
| What counts as success | HTTP 200 to 206 | Acknowledging the Pub/Sub message, or a success code on a push endpoint |
| Retries | 5 for V2, at 1, 12, 24, 48 and 72 hours after the previous attempt | Pub/Sub redelivers until acknowledged or the retention period ends |
| How long a missed message survives | 180 days in Get Notification History | 7 days by default in the subscription, up to 31 days |
| Refund that asks for your evidence | CONSUMPTION_REQUEST, answer within 12 hours | PendingRefundReviewNotification, answer within 24 hours |
| Pull-based backup for granted refunds | Get Notification History, Get Refund History | Voided Purchases API, past 30 days |
| Sandbox or test behavior | One attempt, no retries | Send Test Message from Play Console |
What Apple treats as a failure
Apple's documentation is specific. Return any status from 200 to 206 and the delivery is done. Return a 40x or 50x and Apple retries. Apple considers every other code unsuccessful too. Each attempt is logged with a sendAttemptResult, and the values read like a checklist of real outages: TIMED_OUT, TLS_ISSUE, CIRCULAR_REDIRECT, NO_RESPONSE, PREMATURE_CLOSE, UNSUCCESSFUL_HTTP_RESPONSE_CODE and a few more. For TIMED_OUT, Apple's own advice is to check that your server isn't processing messages in line.
What Google treats as a failure
On a push subscription, a success response code from your endpoint is the acknowledgement. On a pull subscription, your server has to acknowledge each message it pulls, or Pub/Sub delivers it again. The default acknowledgement deadline is 10 seconds and the maximum is 600 seconds. Google's RTDN guide adds one more rule worth repeating: a notification only says that something changed, so you still call the Google Play Developer API to get the full purchase state.
Why Apple's retry schedule doesn't fit the 12-hour window
Apple's retry intervals are measured from the previous attempt, not from the first one. Add them up and you get this timeline for a single V2 notification your server keeps failing.
| Attempt | Wait after previous attempt | Hours since first attempt |
|---|---|---|
| First delivery | None | 0 |
| Retry 1 | 1 hour | 1 |
| Retry 2 | 12 hours | 13 |
| Retry 3 | 24 hours | 37 |
| Retry 4 | 48 hours | 85 |
| Retry 5 | 72 hours | 157 |
Apple tells you to respond within 12 hours of receiving the CONSUMPTION_REQUEST. If your server is down for the first delivery and for the retry an hour later, the next attempt arrives 13 hours after the first one. Apple doesn't say whether a request first received on a retry gets a fresh 12 hours. The careful reading is to treat the first attempt as the start of the clock, which means retries alone won't save a request you missed by more than an hour.
Does Apple retry after an HTTP 400?
Yes, according to the documentation. Apple lists 40x and 50x as the codes that trigger a retry. In March 2026 a developer reported on Apple's forums that retries after 400 responses seemed to stop, then said deliveries resumed a day or two later, and Apple asked for a Feedback Assistant report. Treat the documented behavior as the rule and your own monitoring as the proof.
Recover missed App Store notifications with Get Notification History
Get Notification History returns the version 2 notifications Apple attempted to send to your server in a timespan you choose. Each record carries the full signed payload, so you can feed it to the same handler as a live notification. Each record also includes a sendAttempts array of up to six entries, one for the first try and one for each of the five retries.
- startDate and endDate are required, and the startDate must fall within the past 180 days in production or the past 30 days in sandbox.
- Set onlyFailures to true to get only the notifications that haven't reached your server, plus the ones Apple is still retrying.
- Filter by one notificationType, such as CONSUMPTION_REQUEST or REFUND, or by a transactionId for a single customer, but not both in the same request.
- Each call returns up to 20 records. Keep calling with the paginationToken while hasMore is true, and send the same request body each time.
One caveat matters for refunds. Apple says history records reflect the state of a purchase when the notification was first sent, not now. So a recovered REFUND is a fact about the past. Before you revoke access, check current state with the transaction or subscription status endpoints.
V1 notifications can't be recovered this way
Get Notification History only covers version 2. Apple retries V1 notifications three times, at 6, 24 and 48 hours after the previous attempt, and if all of them fail there's no history to replay. That's one more reason to move any app still on V1 to V2.
Recover missed Google Play refund notifications
Google's safety net is Pub/Sub itself. As long as your subscription exists, a message nobody acknowledged stays there for the retention period, 7 days by default and up to 31 days if you raise it. When your endpoint comes back, delivery resumes. Two settings can quietly defeat that.
- A dead-letter topic moves a message out of your subscription after a set number of failed delivery attempts. The default is 5, and with the default retry policy of immediate redelivery, five attempts can pass quickly. If you use one, watch the dead-letter topic like a second inbox.
- A subscription with no subscriber activity, such as open connections, active pulls or successful pushes, expires after 31 days by default. An endpoint that stays broken for a month can lose the subscription itself, along with everything waiting in it.
Voided refunds have a 30-day backup
For refunds that already happened, the Voided Purchases API is the pull-based backup. It lists voided purchases from the past 30 days, up to 1,000 per page, with a quota of 6,000 queries per day and 30 queries in any 30-second period for each app. Pass type 1 to include subscriptions alongside one-time products. Running it daily catches any refund your notification pipeline dropped, which keeps entitlements and revenue numbers honest.
Chargeback reviews don't have one
A PendingRefundReviewNotification is different. It carries the pendingRefundToken you must pass to orders.reviewrefund, and you have 24 hours from receiving it to send your refund preference and usage evidence. Google records your first call and ignores the rest. Google's documentation describes no endpoint that lists pending reviews, so if that Pub/Sub message is lost, your evidence for that chargeback is lost with it.
What a missed refund notification costs in money
A missed notification for a refund that's already final costs you bookkeeping. You find it later in the Voided Purchases API or Get Notification History, revoke access if your policy calls for it, and your reports catch up. Annoying, but cheap.
A missed notification in one of the two contestable flows costs real money, because the store decides without your evidence. On Apple, that means the refund decision is made without your consumption data. On Google Play, for orders placed after August 3, 2026, a lost chargeback costs you the purchase price less Play's service fee, plus the chargeback fee your buyer's bank charges. Google covers only its own service fee.
And the money you spent delivering the purchase was gone before the dispute started.
- Compute: GPU and server time behind every generation, render or model response the buyer already used.
- API calls: third-party requests billed the moment they fired, often per call.
- Storage: files and media the buyer created, still on your hosting bill.
- Payouts: revenue shares already paid to creators, affiliates or partners on that sale.
None of that comes back when a refund goes through. The evidence you send in those 12 or 24 hours is the one lever you have, and a missed notification removes it.
A recovery routine that holds up
- Acknowledge first. Store the raw payload, return a success code, then process it in a queue.
- Poll Apple's Get Notification History with onlyFailures every few minutes for CONSUMPTION_REQUEST, so an outage costs minutes of the 12-hour window.
- Run a daily Get Notification History sweep with onlyFailures over the past few days for every type, and replay what you find.
- Run a daily Voided Purchases API call with type 1 for each Google Play app, and reconcile it against the refunds you already recorded.
- On Pub/Sub, keep message retention at 7 days or more, alert on the dead-letter topic if you have one, and alert when undelivered messages pile up.
- Test the whole path in production too. Apple's sandbox sends each notification once with no retries, and Request a Test Notification plus Get Test Notification Status shows exactly how your server answered.

RefundHalt receives both stores' notifications for you, answers CONSUMPTION_REQUEST and chargeback reviews automatically inside their windows, so you aren't the one watching the clock.
Frequently asked questions
- How long does Apple keep retrying a failed App Store server notification?
- About six and a half days for version 2. Apple retries five times, at 1, 12, 24, 48 and 72 hours after the previous attempt, so the last retry comes 157 hours after the first delivery. Version 1 notifications get three retries, at 6, 24 and 48 hours after the previous attempt.
- How far back can I recover missed App Store server notifications?
- 180 days in production. Apple's Get Notification History endpoint returns version 2 notifications from the past 180 days, or the past 30 days in sandbox, 20 records per call, and the onlyFailures flag limits results to notifications that never reached your server.
- Does Apple retry a notification if my server returns HTTP 400?
- Yes, according to Apple's documentation. Apple retries when your server returns a 40x or 50x status, and treats 200 to 206 as success. Any other status also counts as unsuccessful.
- Can I recover a missed Google Play chargeback review?
- Only while the Pub/Sub message still exists. The pendingRefundToken you need for orders.reviewrefund arrives in the PendingRefundReviewNotification, and Google documents no API that lists pending reviews, so the subscription's unacknowledged messages, kept 7 days by default, are your only copy.
- How do I find Google Play refunds my server missed?
- Call the Voided Purchases API. It returns voided purchases from the past 30 days, including refunds, revocations and chargebacks, with up to 1,000 results per page and a quota of 6,000 queries per day per app. Pass type 1 to include subscriptions.
Sources and further reading
- Apple Developer: Responding to App Store Server Notifications
- Apple Developer: Get Notification History
- Apple Developer: NotificationHistoryRequest
- Apple Developer: Send Consumption Information
- Android Developers: Real-time developer notifications reference
- Android Developers: Help Google dispute chargebacks
- Google Play Developer API: Voided Purchases API
- Google Cloud: Pub/Sub subscription properties
- Play Console Help: Updates to refund protection and chargeback cost responsibility
RefundHalt
The refund autopilot for the App Store and Google Play
Keep reading
Excessive refund requests can cost you more than the refunds, because both app stores treat them as a quality signal
Apple's Guideline 5.6.4 names excessive refund requests as a sign an app isn't meeting quality standards, and Google's Distribution Agreement lets it remove new developers' apps on refund rates. Here's what each store says, what removal costs, and how to stay clear.
Verify App Store server notifications before you act on a refund, because anyone can post to your webhook URL
A refund notification is just an HTTPS request until you check its signature. Here's how to verify App Store server notifications and Google Play RTDN messages, what each store signs, and what a forged or wrongly rejected refund costs you.