Skip to main content
Question

Restore via Paywall does nothing, no webhook event fired

  • July 24, 2026
  • 5 replies
  • 65 views

Forum|alt.badge.img+3

I'm testing iOS App Store promo codes. After redeeming a code and coming back into the app, I try to restore the purchase via our RevenueCat Paywall - nothing happens when I tap Restore. I also don't see any event fired to my webhook afterward.

Any ideas on what to check here?

5 replies

Forum|alt.badge.img+5
  • Helper
  • July 24, 2026

Hey ​@omer-7776d7 ,

After redeeming the offer code and returning to the app, tapping Restore should ask the RevenueCat SDK to restore purchases associated with the current Apple Account. However, pressing Restore does not itself guarantee that a webhook will be generated. RevenueCat sends purchase lifecycle webhooks only when it detects a relevant transaction or subscription-state event.

The first thing to verify is whether tapping Restore is actually triggering the SDK request. Please enable RevenueCat debug logs, reproduce the issue, and look for the restore request and its result.

On iOS, you can enable logs with:

Purchases.logLevel = .debug

 


This is a common issue when testing App Store promo codes with RevenueCat paywalls in the Sandbox / StoreKit environment. Here are the key things to check:

1. StoreKit Environment & Apple ID Session Promo codes redeemed via the App Store app often bind to your main Apple ID or Sandbox account, but StoreKit in the test build might not automatically recognize the local receipt until refreshed. Make sure the Sandbox Apple ID logged into the device settings matches the account used for redemption.

2. Purchases.shared.restorePurchases Handler If tapping "Restore" on the RevenueCat paywall literally does nothing (no loader, no error toast):

  • Ensure your UI delegate/listener for restorePurchases is properly attached.

  • If using a custom paywall or SDK integration, verify that Purchases.shared.restorePurchases is actually being invoked on the button tap.

3. Webhook Events & App Store Connect Server Notifications RevenueCat only fires webhooks when its backend receives a valid, signed App Store receipt containing active entitlement transactions. If the local client doesn't send an updated receipt to RevenueCat during the restore call, no webhook event will trigger. Make sure App Store Server Notifications V2 are properly configured in App Store Connect for your environment.

4. Promo Code Receipt Delay Sometimes Apple's Sandbox environment takes a few minutes to sync offer code redemptions to the test receipt. Try calling Purchases.shared.syncPurchases() or force-closing and re-opening the app to force a receipt sync before tapping Restore.

I've run into similar StoreKit/SDK sync quirks while setting up automation flows on this page. Double-checking the Sandbox Apple ID and StoreKit Server Notifications usually resolves this!


guilherme
RevenueCat Staff
Forum|alt.badge.img+6
  • RevenueCat Staff
  • July 28, 2026

Hey ​@omer-7776d7,

When restorePurchases() appears to do nothing on the paywall, it usually means the restore did run but completed with an empty result, as there was no transaction to restore in the StoreKit environment the app is running in. Our paywall only shows a confirmation alert when the restore actually finds active purchases, so a silent outcome is the SDK telling you it found nothing. You can confirm this by enabling debug logs and reproducing, you'll see the restore request complete with an empty result rather than fail.

That could point to where the redemption happened versus where it is being testing. Promo/offer codes redeemed through the App Store app are processed in the production environment, against the Apple Account signed into the App Store. If you then test with an Xcode or TestFlight build, StoreKit is running in the sandbox environment and a restore there won't surface that production redemption. The same happens if the device is signed into a different Apple Account than the one that redeemed the code! Sandbox and TestFlight are known to behave inconsistently for code redemptions in general, from our docs:

Since launch, Apple's in-app Offer Code redemption sheet has proven to be extremely unstable. For example, the sheet may not connect, may not dismiss after a successful redemption, and may not accept valid codes. Additionally, sandbox and TestFlight behavior has been seen to be inconsistent.

more context here: https://www.revenuecat.com/docs/subscription-guidance/subscription-offers/ios-subscription-offers#option-1-in-app-redemption-sheet

So to validate this end to end, I'd recommend testing with the production App Store build of your app, on a device signed into the same Apple Account that redeemed the code. For the redemption flow itself, our recommendation is to send users to the App Store redemption URL and then sync when they come back, from the same docs page:

It is important to call syncPurchases when the user returns back to your app to retrieve their purchase. This may be done by recording when the user leaves the app due to the link, and calling syncPurchases when the user returns to the app. If not, the user may need to trigger a restore within your app when they come back.

more context here: https://www.revenuecat.com/docs/subscription-guidance/subscription-offers/ios-subscription-offers#option-2-redirect-to-app-store-app

On the webhook side, that part is expected! As mentioned above as well, we only send webhooks when our backend ingests a new transaction or subscription state change, and there is no event for a restore attempt itself. Once the redemption actually syncs from the correct environment, you'll see the corresponding event (an INITIAL_PURCHASE for a new subscription) arrive on your webhook.

Worth noting that the legacy promo codes are a path we recommend against, they behave inconsistently with StoreKit and Apple stopped allowing new ones after March 26, 2026.

I hope this helps!


Forum|alt.badge.img+3
  • Author
  • New Member
  • July 29, 2026

Thanks - to clarify, it wasn't a sandbox/TestFlight mismatch on my end. Both the redemption and the restore attempt happened on the same production build, on the device signed into the same Apple Account.
 

Given that, does it still come down to needing syncPurchases() specifically rather than restorePurchases() right after returning from the redemption sheet? Or is there something else worth checking - I haven't pulled debug logs yet, so I can do that next to see whether restore is completing with an empty result or not firing at all


guilherme
RevenueCat Staff
Forum|alt.badge.img+6
  • RevenueCat Staff
  • July 30, 2026

Hey ​@omer-7776d7 ,

Thanks for confirming that, it rules out the environment mismatch!

On your question however, switching to syncPurchases() alone wouldn't change the outcome. Both it and restorePurchases() sync what StoreKit reports for the Apple Account, we just recommend syncPurchases() for this flow because it doesn't require the user to tap anything when they return to the app - note that this “sync” call shouldn’t be done on every app launch, but purely for migration/consolidation flows (e.g new authentication in your app to migrate/check purchases are syncing correctly).

Given that restore keeps coming back empty, it could be that the redemption itself never completed on Apple's side. The in-app redemption sheet is known to fail silently sometimes, as noted on the limitations in that same url from before: www.revenuecat.com/docs/subscription-guidance/subscription-offers/ios-subscription-offers#option-1-in-app-redemption-sheet 

The quickest way to confirm is on the device, under Settings > Apple Account > Subscriptions. If the subscription doesn't show as active there, the code was never redeemed, so there's nothing to restore and no webhook to fire. In that case I'd retry through the App Store redeem URL instead of the in-app sheet: https://apps.apple.com/redeem?ctx=offercodes&id=6472174465&code={code}

If it does show as active there and restore still comes back empty, please open a support ticket with your app user ID and the rough time of the redemption, and we can trace exactly what the device sent us from our side.

I hope this helps!