All articles
Playbook8 min read

Apple and Google refund one store at a time, so your cross-platform subscription has to end access everywhere else

When Apple or Google refunds a cross-platform subscription, your Android app, iPhone app and website don't find out on their own. Here's how to tie each store purchase to one account, revoke the right entitlement, and stop paying to serve refunded users.

An iPhone, an Android phone and a laptop side by side on a desk, each signed in to the same account of a cross-platform subscription

Key takeaways

  • Apple's App Review Guideline 3.1.3(b) lets apps that operate across multiple platforms give users access to content and subscriptions acquired on other platforms or the developer's website, as long as those items are also available as in-app purchases in the app.
  • Apple and Google only refund purchases made in their own store, so an Apple refund on a cross-platform subscription doesn't reach the customer's Google Play or web billing. The developer's server has to remove the access it granted on every platform.
  • Apple sends a REFUND notification through App Store Server Notifications V2 when it refunds a consumable, a non-consumable, a non-renewing subscription or an auto-renewable subscription, and it says the developer is responsible for storing, monitoring and acting on each refunded transaction.
  • Apple's appAccountToken is a UUID a developer attaches to an In-App Purchase, and the App Store Server API's Set App Account Token endpoint can add one later to purchases made outside the app, such as a redeemed offer code.
  • Google Play's setObfuscatedAccountId links a purchase to an account in the developer's app, is limited to 64 characters, and gets purchases blocked if it holds cleartext personal data such as an email.
  • Google Play's Voided Purchases API reports refunded and charged-back purchases with an orderId and a voidedSource of 0 for User, 1 for Developer or 2 for Google.
  • For Google Play orders placed after August 3, 2026, the developer pays the purchase price, less Play's service fee, plus the bank's chargeback fees when a chargeback goes through.

Your subscriber paid Apple, opened your Android app the same afternoon, and now uses your website at work. Then Apple refunds them. Google Play doesn't know. Your web billing doesn't know. Unless your own server ends access, a refunded cross-platform subscription keeps working on every screen that reads your account database. The stores refund one storefront at a time, and your account system is the only place where the whole subscription exists. That makes it the only place that can end it.

Why one store's refund doesn't end a cross-platform subscription

Apple allows this setup in so many words. App Review Guideline 3.1.3(b), Multiplatform Services, says apps that operate across multiple platforms may let users access content, subscriptions or features they acquired in your app on other platforms or on your website, provided those items are also available as in-app purchases in the app.

Apple's guide to offering one subscription across several apps describes how this works in practice. Your server grants access, using a unified account database, and every app reads from it. The same guide warns that if a purchase isn't propagated to the other apps, the user can end up paying more than once for the same service.

That design has a consequence people miss. The entitlement lives in your database, but each store only knows its own receipts. Apple can refund the iPhone purchase and tell your server. It can't tell your Android app or your website anything. If the refund handler only updates the iOS client, the customer gets their money back and keeps the subscription everywhere else.

Where they paidWho decides the refundHow your server hears about itWho can stop renewals
App StoreAppleREFUND notification in App Store Server Notifications V2The customer, in their App Store subscription settings or a manage screen your app opens
Google PlayGoogle in the first 48 hours, then you or GoogleVoided Purchases API and real-time developer notificationsThe customer, or you through purchases.subscriptionsv2.cancel
Your websiteYouYour payment processor's webhooksYou

How to revoke access on every platform after a refund

Tie every store purchase to one account

Matching a refund to a person is the hard part, because each store identifies the buyer in its own way. Both give you a field for your own account ID. Use it on every purchase.

  • On Apple, set an appAccountToken, a UUID you generate, when the purchase starts. The App Store returns the same UUID in the transaction and renewal information. Apple says you can reuse one value for every transaction that belongs to the same customer.
  • If the customer bought outside your app, for example by redeeming an offer code in the App Store, the transaction has no token. The Set App Account Token endpoint adds one. For an auto-renewable subscription it applies to the current renewal and later ones, not past transactions, and it doesn't work for purchases shared through Family Sharing.
  • On Google Play, pass an obfuscated account ID with setObfuscatedAccountId when you launch the billing flow. It's limited to 64 characters. Google says cleartext personal data such as an email gets purchases blocked, and recommends encryption or a one-way hash.

Listen to both stores, then write one entitlement

Apple sends REFUND when it refunds any product type, auto-renewable subscriptions included. It sends REFUND_REVERSED when it reverses a refund it already granted, because of a dispute the customer raised. On Google Play, the Voided Purchases API lists refunded and charged-back purchases, each with an orderId that identifies the exact purchase or renewal. Your web processor sends its own refund event. All three should land in the same handler and change the same record.

Revoke the entitlement, not the account

A refund cancels a purchase, not a person. Remove the access that came from the refunded purchase, then recompute what the account still has. If the customer also holds an active subscription from another store, they keep access through that one. If they don't, every client loses premium features the next time it checks your server.

When the same person subscribes on two stores

Double subscriptions are the other half of the problem. Someone subscribes on Android, gets a new iPhone, doesn't sign in, and subscribes again. Now they're paying twice for one service, and one of those charges usually becomes a refund request. Apple's commerce team, answering a developer on the Apple Developer Forums, put it simply: an app account system should include logic to prevent the duplicate purchase on another platform.

Check every store before showing the paywall

Sign the user in before the paywall, look up all of their active purchases on your server, and skip the offer if any of them covers this platform. That one check prevents most duplicate charges before they happen.

Which purchase should I refund when it already happened?

Refund the one you control. On Google Play you can issue the refund yourself in Play Console, and purchases.subscriptionsv2.cancel with DEVELOPER_REQUESTED_STOP_PAYMENTS stops the next payment. Your web subscription is yours to refund outright. App Store refunds are decided by Apple, so if the duplicate is on the iPhone, the customer requests it from Apple, and your app can open that request with StoreKit's refund request API.

What a refund that misses a platform costs you

The refunded price is only the first loss. A customer whose Apple refund never reached your Android app or website keeps using what you pay to run. Every session still burns compute. Every AI feature still makes third-party API calls you're billed for. Their files still take up storage, and if your app pays creators per view or per use, those payouts keep going out. On an annual plan, that can mean a full year of serving costs for an account that now pays nothing.

The bank route makes it worse. For Google Play orders placed after August 3, 2026, Google says that when a chargeback goes through, the developer is responsible for the purchase price, less Play's service fee, plus the chargeback fees the financial institution charges. A chargeback is final at the bank. A customer who's charged back and still has access has cost you the price, the fees and the serving cost at once.

What keeps running after a missed revokeWho pays for it
Server compute for each session on Android or webYou
Third-party API calls your features makeYou
Storage for the user's files and historyYou
Per-use or per-view payouts to creatorsYou
Chargeback fees on a Google Play order after August 3, 2026You, on top of the purchase price less Play's service fee
A hand holding a smartphone next to an open laptop, with a second phone lying face down, the everyday setup of a cross-platform subscription user

Cross-platform usage is still evidence

One account across platforms also helps when a store asks for your side. Apple's consumption information asks what portion of a consumable, non-consumable or non-renewing subscription the customer consumed. For auto-renewable subscriptions you don't send a percentage, because Apple calculates it from elapsed time. Google Play's chargeback review accepts up to 1,000 consumption usage events, each of which can carry the obfuscated account ID. Usage logged under one account ID, whatever device produced it, is usage you can show.

Which refunds never ask for your side

Most refunds are decided without you. Google Play may refund a purchase within 48 hours through its own refund flow. Store support refunds, voided purchases and Google's automatic refund of purchases you never acknowledge, at about 72 hours, all happen first and get reported afterward. For those, the revoke logic above is the whole job.

Only two flows ask for evidence. Apple's CONSUMPTION_REQUEST gives you 12 hours to send consumption information. Google Play's chargeback review gives you 24 hours from the PendingRefundReviewNotification to answer through orders.reviewrefund, and Google records only your first call. RefundHalt answers both inside the window, using the usage data you already collect, keyed to the same account across your apps.

A short checklist for cross-platform refunds

  • Set appAccountToken on Apple purchases and an obfuscated account ID on Google Play purchases.
  • Backfill missing Apple tokens with Set App Account Token for offer code redemptions.
  • Route Apple REFUND and REFUND_REVERSED, Google Play voided purchases and web refunds into one handler.
  • Store each purchase with its source, and compute access from all active purchases.
  • Check every store's purchases before showing a paywall on any platform.

Frequently asked questions

Can I let iPhone users access a subscription they bought on Android or my website?
Yes. Apple's App Review Guideline 3.1.3(b) lets apps that operate across multiple platforms give users access to content, subscriptions or features acquired on other platforms or your website, as long as those items are also available as in-app purchases in the iPhone app.
If Apple refunds a subscriber, do Google Play or my web billing find out?
No. Apple tells your server through a REFUND notification in App Store Server Notifications V2, and nothing else. Your server has to remove the access that purchase granted on Android, on the web and anywhere else the account signs in.
How do I match an App Store refund to a user account?
Use appAccountToken, a UUID your app attaches to the purchase, which the App Store returns in the transaction information. For purchases made outside your app, such as an offer code redemption, Apple's Set App Account Token endpoint adds or replaces the token. It doesn't support Family Sharing transactions.
A customer is subscribed on both the App Store and Google Play. Which one should I refund?
Refund the one you control. You can refund a Google Play order in Play Console and stop its next payment with purchases.subscriptionsv2.cancel. Apple decides App Store refunds, so an iPhone duplicate goes through Apple's refund request, which your app can open with StoreKit.
Does usage on my website or Android app count as evidence in a refund review?
Usage logged under one account can support your answer. Apple's consumption information asks what portion of a consumable, non-consumable or non-renewing subscription was consumed, and Google Play's chargeback review accepts up to 1,000 usage events that can carry the obfuscated account ID.

Sources and further reading

RefundHalt

The refund autopilot for the App Store and Google Play

Keep reading

The next refund request is already on its way.

Set up RefundHalt in the time it takes to read another support email about a refund you didn't get to contest.