Google Play refunds and voided purchases: what to do with them
How refunds, revocations and chargebacks work for Google Play subscriptions: voided purchase notifications, the Voided Purchases API and refund reviews.
On Google Play, money can go back to a subscriber in several ways: the user gets a refund, you refund them from the Play Console or the API, a purchase is never acknowledged, or the payment is charged back. Google groups all of these under one term: a voided purchase. If you grant access or credits from your own backend, you need to know about every one of them.
This guide explains where voided purchases show up, what Google tells you about each one, the newer refund review for chargebacks, and how to respond. It sticks to Google’s documentation: the real-time developer notifications reference, the security best practices on voided purchases, handling rejected purchases, the subscription lifecycle, and the Google Play Developer API reference for voided purchases, orders.refund and orders.reviewrefund (all accessed November 2026).
What counts as a voided purchase
Google’s security page defines voided purchases as “purchases that have been canceled, revoked, or charged back,” and lists the main causes:
- The purchase is canceled by the user, the developer or Google, including purchases auto-canceled because they were never acknowledged. For subscriptions, this means canceling the purchase itself, not just turning off renewal.
- The purchase is charged back.
- The developer cancels or refunds an order and checks the “revoke” option.
A normal subscription cancellation (the user stops renewal) is not a voided purchase. It is a SUBSCRIPTION_CANCELED event, and the user keeps access until the end of the period.
Refund, revoke or both
You have three actions, and they do different things:
| Action | API | Money | Access |
|---|---|---|---|
| Refund only | orders.refund without revoke |
Refunded | Kept |
| Refund and revoke | orders.refund with revoke=true, or purchases.subscriptionsv2.revoke with a full refund |
Refunded | Ended immediately |
| Cancel | purchases.subscriptionsv2.cancel |
Not refunded | Kept until the period ends |
Points from Google’s docs worth knowing:
orders.refundcannot refund orders older than three years. Withrevokeset to true, access ends immediately and, for a recurring subscription, all future payments stop.- Google’s integration guide says that developer revocations and refunds with revoke trigger notifications and appear in the Voided Purchases API with
voidedSourceset to developer. For subscriptions, you get bothSUBSCRIPTION_REVOKEDand aVoidedPurchaseNotification. - A refund without revoke “doesn’t trigger a revocation or voided purchase notification.” If you use it, record it yourself.
- If you do not acknowledge a new subscription within three days, the user is automatically refunded and the purchase is revoked. Google asks you not to rely on this to reject purchases: revoke and refund explicitly instead.
Where voided purchases show up
In real time: VoidedPurchaseNotification
If your Play app has real-time developer notifications enabled, a voided purchase arrives as a voidedPurchaseNotification with:
purchaseToken: the purchase that was voided.orderId: the exact order. For subscriptions, each renewal has its own order ID, so this tells you which payment was voided.productType:1subscription,2one-time product.refundType:1full refund,2quantity-based partial refund (multi-quantity purchases only).
Google notes that this is enough to “locate the right purchase and order for entitlement adjustments.” For subscriptions, a revocation also sends a SUBSCRIPTION_REVOKED subscription notification; the lifecycle guide says to revoke the user’s entitlement immediately in that case.
In bulk: the Voided Purchases API
purchases.voidedpurchases.list is a pull API. From the API reference:
- It covers the last 30 days:
startTimecannot be older than that. - By default it returns only one-time products. Pass
type=1to include subscriptions. - Each record has a
voidedReason:0Other,1Remorse,2Not_received,3Defective,4Accidental_purchase,5Fraud,6Friendly_fraud,7Chargeback,8Unacknowledged_purchase. - And a
voidedSource:0user,1developer,2Google.
The reason codes are the most useful part, because the notification does not include them. One caveat from the security page: voided purchases “without any associated clawback content are not exposed by the Voided Purchases API.”
Use both: the notification to act within seconds, and a daily API pull to get reasons and catch anything you missed.
Chargebacks: the refund review
Google has added a way for developers to weigh in on some chargebacks. When a user requests a chargeback that needs developer review, you receive a pendingRefundReviewNotification. According to the RTDN reference, you should evaluate the request and send “a refund suggestion and purchase usage evidence within 24 hours” by calling orders.reviewrefund. Pending reviews currently support only CHARGEBACK as the reason.
The request body, per the API reference:
| Field | Meaning |
|---|---|
pendingRefundToken |
From the notification; required |
refundPreference |
APPROVE, DECLINE or NEUTRAL; required |
sampleContentProvided |
Whether you offered a free sample, trial or description before purchase; required |
consumptionPercentageMilliunits |
Optional, 0 to 100,000 (45,200 means 45.2%) |
consumptionUsageEvents |
Optional list of usage events (time, item description, IP address, location, obfuscated account or profile ID); lists over 1,000 items are rejected |
The notification includes the obfuscatedAccountId and obfuscatedProfileId if you set them at purchase. Without them, you will struggle to find the user’s usage within 24 hours.
Be truthful. If the user could not use what they paid for, APPROVE is the right answer. If they used the subscription throughout the period, a DECLINE with concrete usage events is what the field is for.
What to do with each voided purchase
Google’s security guide recommends, depending on the reason and the user’s history:
- Claw back unused items, such as in-app currency that was granted.
- Multiple strikes: an in-app warning for a first case, stronger measures for repeat cases.
- Temporarily disable purchases while you look into it.
- Restrict access to your app in extreme, repeated cases.
- Call the Voided Purchases API more often once you detect voided purchases.
For a subscription app, a practical policy looks like this:
| Reason | Suggested response |
|---|---|
| Accidental purchase, remorse | End access for the refunded period; no warning. Maybe ask for feedback |
| Not received, defective | Treat as a product bug; investigate the user’s account |
| Unacknowledged purchase | Fix your purchase processing; this is your bug, not the user’s |
| Fraud, friendly fraud, chargeback | End access, flag the account, block new purchases until reviewed |
Common mistakes
- Only handling
SUBSCRIPTION_CANCELED. It means “stop renewing”, not “refunded”. Revocations come asSUBSCRIPTION_REVOKEDand voided purchase notifications. - Refunding without revoke and forgetting it. No notification will remind you.
- Polling the API less than monthly. Anything older than 30 days is gone from the API.
- No obfuscated account ID. You cannot answer a refund review in time if you cannot find the user.
- Punishing remorse refunds like fraud. The reason codes exist so you can tell them apart.
Doing this with NoChurn
NoChurn reads your Google Play real-time developer notifications and the Voided Purchases API, so refunds, revocations and chargebacks appear on each customer’s timeline with their reason and feed the churn score. On Google Play, refunds are read-only in NoChurn: refund decisions and refund reviews stay with you and Google, and payments and retries stay with Google. To match purchases to customers, set an obfuscated account ID at purchase. See NoChurn + Google Play.