Back to Explore
GuideVibeFix 编辑部Updated Nov 5, 2026

New Phone, Membership Gone? In-App Purchase Restore That Actually Works

Restoring a purchase is not finding an order — it is re-confirming what the user owns right now with a store credential: one server-side entitlement table, idempotent restore, and failure messages that say what to do next.

Real photograph of a man holding an iPhone in a brown leather case

First, the verdict: restoring a purchase is not “finding an order” — it is re-confirming an entitlement

Real photograph of a man holding an iPhone in a brown leather case

Almost every team that has shipped a paid app has received the same support email: “I got a new phone — where did my membership go?” When users write that, they are not thinking about receipts, order numbers, or transaction records. They are thinking about one thing: does the money I already spent still count? Many teams react by looking up the order. The order is there, the money was collected, the system looks fine. But the user never asked “is the order there?” They asked “is my Pro still mine?” Looking up the order answers the finance department’s question, not the user’s.

My verdict up front: restoring a purchase is really “using the store’s credential to confirm, once more, what this user is entitled to right now.” Three words in that definition are non-negotiable. First, the credential comes from the store — not from the user saying “I bought it,” and not from a boolean stored locally on the device. Second, the confirmation happens on the server; the client only shows the result, it never decides it. Third, what gets confirmed is “what the user owns right now,” not “what they once bought.” A subscription that expired, a refunded purchase, or a family-sharing grant that ended are all cases where “once bought” and “currently owns” are different things, and restore has to answer for the present, not the past.

The product “Green Barley Meditation” and the people and numbers in the examples below are fictional, used only to illustrate the restore flow; the descriptions of store rules are general summaries of public platform practice, not tied to a specific version of any terms at a specific date.

Step 1: Learn the two stores’ division of labor — do not merge two rulebooks into one

Apple’s and Google’s restore mechanisms look similar in outline and differ everywhere in the details. Merge them into one code path and one side will break sooner or later. On Apple’s side, there is a review-level hard requirement: apps offering auto-renewable or non-consumable purchases must show users a visible restore entry point in the interface — it cannot live only in a support script that says “please contact us.” Restoring means asking the store, under the currently signed-in Apple ID, which entitlements are valid right now, and syncing the answer back to your own server. The key phrase is “the currently signed-in account.” If the user switched Apple IDs, the store cannot see the old purchase. That is not a bug; it is how the store’s account model works.

On Google’s side, more of the restore work happens when the app starts: the app re-queries the user’s purchases for that app through Play Billing, covering one-time purchases and subscriptions. Once the results come back, the app must handle them by purchase type: consumables get consumed after use, non-consumables and subscriptions get acknowledged, and the valid state gets written to the server. Google also has one line that is easy to trip over: if a purchase is not acknowledged, the system refunds it automatically after a window of time. In other words, restore is not “query once and done” — it is “after querying, complete the acknowledgement and the entitlement write,” or a user who genuinely paid will quietly lose their entitlement a few days later.

One purchase type gets overlooked most often: family sharing. Apple’s family sharing lets family members share eligible purchases, but “can be shared” and “is being shared” are two different things — they depend on whether the buyer turned sharing on and whether that product type supports sharing at all. When a user says “my family member bought it, why do I not have it?” do not rush to fix code. Ask three things first: whose account bought it, whether that product type supports sharing, and whether sharing is turned on. Eight times out of ten, the answer is in the settings, not in the code.

Step 2: One entitlement table on the server is the only truth — the client only displays

The most common architecture mistake in purchase restore is storing “is this user Pro?” on the device. A boolean in local storage disappears when the phone changes, vanishes when data is cleared, and can be bypassed by changing the clock, the package name, or forging a request. Worse, when the client and the server each keep a copy and the two disagree, nobody knows which one to believe — the user is stuck in the middle and support cannot explain it either.

The right approach is a server-side entitlement table as the single source of truth. It needs at least five columns: who the user is, what the entitlement is (for example, a Pro membership), which store it came from, when it expires, and when the credential was last verified. Restore then becomes a straight line: the user taps “Restore Purchases” → the app asks the store with the store credential → the server verifies that credential against the store once more → if verification passes, the entitlement table is written with the store’s latest state → the app displays the result from the table. The client never decides anything along the way; it only forwards the tap and shows the server’s conclusion.

Two details in that straight line deserve their own mention. First, server-side verification cannot be skipped. Trusting only what the client reports — “the store says I bought it” — is like letting customers guard the cash register themselves. The stores provide server-side verification endpoints precisely for developers to use; not using them is leaving the door open on purpose. Second, restore must be idempotent. A nervous user taps “Restore Purchases” three times in a row; a shaky network re-sends the request twice. The entitlement table has to guarantee that restoring the same purchase any number of times produces the same result: no duplicate entitlements, no double-counted grants, no three identical rows. Idempotency is not an optimization; it is the baseline of a restore flow.

Step 3: Five failure scenes, each with its own diagnostic sentence

Restore failures are rarely caused by wrong code. Most of the time the scene differs from what the code assumed. Writing the five most common failure scenes as diagnostic sentences — shared by support and engineering from the same sheet — speeds up triage by an order of magnitude.

First, the store account changed. The user bought with account A and the phone is now signed in with account B; the store looks up account B and finds nothing. The diagnostic sentence is: “Is the store account signed in during restore the same one used for the purchase?” The fix is not a code change — it is telling the user to switch back to the purchasing account and tap restore again, and writing that in the failure message itself instead of only “no purchase found.”

Second, family sharing is not turned on. The buyer is a family member, sharing is off, or that product type does not support sharing. The diagnostic sentence is: “Who bought it, and is sharing turned on?” The fix is to give the user a path they can walk themselves: check the sharing state in the buyer’s account settings, instead of tapping restore over and over on their own phone.

Third, sandbox account residue. During testing, someone bought with a sandbox account; sandbox purchases stay attached to the test device and test account, invisible in production and unrestorable under the production account. The diagnostic sentence is: “Has this device ever signed in with a sandbox test account?” The fix is a testing rule: sandbox tests use dedicated devices and dedicated accounts, sign out when done, and “sandbox residue” goes on the pre-release checklist to be cleared item by item.

Fourth, the subscription has expired, been refunded, or sits in a grace period. The user remembers “I bought it,” but the subscription ended last month or was refunded. Restore answers for the present: expired means expired, refunded means no entitlement. The diagnostic sentence is: “What expiry date does the store return right now?” The fix is to show the expiry date plainly on the restore result page — “Pro membership valid until 3 December 2026” — instead of only writing “Restore succeeded.” When users see the date, they can judge for themselves whether it is right.

Fifth, cross-platform. The user bought Pro on iOS and wants to keep using it on an Android phone, or the other way around. The diagnostic sentence is: “Which store did the purchase happen in?” A store’s purchase records are only valid inside its own ecosystem; an Apple receipt means nothing to Google. The fix has to be decided at the product level first: whether cross-platform entitlements are merged at all, and what merges them — usually the account system, where the user signs in with the same account and the server merges entitlements by account. That rule must be told to users before they buy, not discovered after they switch phones and find the two sides do not recognize each other.

Step 4: Put the restore entry where users can find it, and write the copy in plain language

Many products hide the restore entry like an Easter egg: Settings → Account → Subscription → More → Restore Purchases. Four levels deep, and the user gives up at the second. Worse, some products have no entry at all, and the support script says “please delete and reinstall and try again,” outsourcing the restore flow to the user’s patience. Apple’s review requirement is only the floor; above the floor, the entry belongs where users see it at first glance: a “Restore Purchases” button right in the subscription area of the settings page. On the paywall, if the user is already a member, the page should show the membership state directly instead of pitching the same plan again.

The button copy should just say “Restore Purchases” — do not invent a new term. “Sync subscription status,” “verify order history,” and “recover membership benefits” are phrases no user understands. During restore, show progress: after the tap, the button becomes “Restoring…” instead of leaving the user staring at an unresponsive screen wondering whether anything is happening. When restore fails, give the reason plus the next step, not a bare “Restore failed” popup. A good failure message looks like this: “No purchase was found under the Apple ID currently signed in. If you bought with a different account, please switch accounts and try again.” After reading it, the user knows what to do next without writing to support.

One more detail: when restore succeeds, do not dismiss it with a single toast. The success page should state three things: which entitlement was restored, when it expires, and who to contact if it looks wrong. Those three lines confirm things for the user — and save support three emails.

Step 5: The test checklist — a restore flow never tested in sandbox is a gamble at launch

Testing a restore flow has one signature trait: everyone tests the happy path; only a checklist catches the failure paths. My checklist has six items, each mapped to a real user scene. First, the full sandbox flow: buy once with a sandbox account, restore once, then restore again on a different device — all three results must agree. Second, restore after expiry: after a subscription lapses, tapping restore should return “no valid entitlement,” not an error and not a wrongly re-granted entitlement. Third, restore after a refund: after a refund, restore should take the entitlement back and say why. Fourth, restore under a different account: tapping restore with account B should not find account A’s purchase, and should tell the user to switch accounts. Fifth, restore with no network: the message should be “network unavailable, please check and try again,” not a spinner that ends in an error code nobody understands. Sixth, tapping restore repeatedly: three rapid taps should leave exactly one entitlement record and show success once.

Once those six pass, test the category most often missed: state sync after restore. The user restores successfully on the phone, opens the tablet, and the membership state there is still the old one. The entitlement table lives on the server, so the tablet only needs to fetch it again the next time it opens — but if the tablet serves a stale disk cache, the cache lifetime has to be shorter than the rate at which entitlements change. My rule: entitlement data gets memory-level caching only, no long-lived disk cache; when the app opens, fetch the entitlement first and only then render the paywall. One extra request, and one fewer class of tickets that read “I restored it, but the tablet still shows the free plan.”

Step 6: Treat a failed restore as the highest-priority ticket

Users hitting a failed restore are users who have paid. Their mood is nothing like a free user hitting a bug: a free user closes the app, but a paying user who sees “my membership is gone” feels cheated. So failed-restore tickets should go to the top of the queue — support answers first, engineering looks first, and the user should not wait three days.

Support can triage with three questions that take about a minute. First: “Which store account was used for the purchase?” Second: “Is the same account signed in now?” Third: “What was purchased, and roughly when?” After those three, the five failure scenes above can almost always be pinned to one. The support script should never contain empty phrases like “please wait patiently.” Give the user a concrete next step: “Please switch to the account used for the purchase, tap Restore Purchases on the settings page once more, and if it still fails, send me the order number and I will look it up directly.”

On the data side, track two numbers. The first is the restore success rate: of the users who tap restore, how many succeed on the first try. Below ninety percent, something in the entry point, the copy, or the flow is systematically broken and needs scheduled work — not one-by-one explanations from support. The second is the distribution of failure reasons: how much is account switching, how much is expiry, how much is family sharing. The distribution tells you what the next release should fix. If account switching is half the failures, the next version should say “switch accounts and retry” right on the failure page; if expiry is half, the next version should state the subscription validity more clearly before purchase. A failed restore is not a burden on support — it is the most honest user feedback a product gets.

Launch checklist: ten items to tick before you ship

Here is a checklist to run through before launch. First, the restore entry sits in the subscription area of the settings page where it can be seen at a glance, and the button simply says “Restore Purchases.” Second, the restore flow verifies on the server; the client never decides, and the entitlement table is the only truth. Third, restore is idempotent: restoring the same purchase any number of times gives the same result. Fourth, the restore result states the entitlement and its expiry date, not only “Restore succeeded.” Fifth, failure messages give the reason plus the next step, and the account-switch case tells the user to switch accounts directly. Sixth, family sharing, cross-platform, and sandbox residue each have an explanation ready, both before purchase and on restore failure. Seventh, all six tests pass: the full sandbox flow, after expiry, after a refund, under a different account, with no network, and repeated taps. Eighth, the out-of-sync problem is handled: the app fetches entitlements before rendering the paywall, with no long-lived disk cache. Ninth, failed-restore tickets get the highest priority, and support can locate the scene in a minute with three questions. Tenth, track the restore success rate and the failure-reason distribution; below ninety percent, schedule a fix, and let the distribution decide what the next release changes.

And four anti-patterns to fix on sight. First, deciding entitlement on the client only: a local boolean disappears when data is cleared, is lost when the phone changes, and can be forged. Second, skipping server-side verification: trusting what the client reports about a purchase is like letting customers guard the cash register themselves. Third, no idempotency: the user taps three times and the entitlement table ends up with three rows, leaving support to reconcile the mess. Fourth, hiding restore: no entry point, or one buried four menus deep, so by the time users write to support, half the trust is already gone.

When restore works well, users never notice it — it only appears at the user’s most anxious moment: a new phone, a fresh install, a membership that suddenly looks gone. The answer the product gives in that moment decides whether the user thinks “that money was well spent” or “never again.” Designing restore as part of the product, instead of remembering it later as a support patch, is everything this article set out to say.

Views 0Comments 0

Comments (0)

ME
0/1000
Loading comments...
Browse projectsPublish your project

Related articles

Real photograph of a laptop on a desk showing a file list with folders and documents
Guide
Don't Make Users Download First: File Preview for Vibe Projects

Preview is the first gate for any file product: confirm in three seconds that this is the right file. Rendering choices per file type, security boundaries, mobile, and performance — in that order.

Developer WorkflowProduct LaunchAI Coding