CHARGEBACKSGOOGLE PLAY

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.

Published 5 min read

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.refund cannot refund orders older than three years. With revoke set 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 voidedSource set to developer. For subscriptions, you get both SUBSCRIPTION_REVOKED and a VoidedPurchaseNotification.
  • 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: 1 subscription, 2 one-time product.
  • refundType: 1 full refund, 2 quantity-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: startTime cannot be older than that.
  • By default it returns only one-time products. Pass type=1 to include subscriptions.
  • Each record has a voidedReason: 0 Other, 1 Remorse, 2 Not_received, 3 Defective, 4 Accidental_purchase, 5 Fraud, 6 Friendly_fraud, 7 Chargeback, 8 Unacknowledged_purchase.
  • And a voidedSource: 0 user, 1 developer, 2 Google.

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:

  1. Claw back unused items, such as in-app currency that was granted.
  2. Multiple strikes: an in-app warning for a first case, stronger measures for repeat cases.
  3. Temporarily disable purchases while you look into it.
  4. Restrict access to your app in extreme, repeated cases.
  5. 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 as SUBSCRIPTION_REVOKED and 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.

PROMPT

Read https://www.nochurn.sh/llms.txt,
then follow https://www.nochurn.sh/docs/quickstart/
to add NoChurn to this app. Use a test key
(nc_test_…) until I say we go live.

Stop leaking revenue.

  • Free until $300 MRR
  • No card needed
  • Live in 10 minutes
  • Never a cut of what we recover