How i kept subscription state synced between web checkout and the app with Adapty and RevenueCat?

Keeping entitlement state consistent is painful when purchases can happen on web and in the app. We had cases where users bought on the web and the app still showed them as unsubscribed.

Our approach was to treat the web checkout as the source of truth for the initial purchase and then push that purchase to the subscription service (we used Adapty/RevenueCat APIs) and to our own backend. After the web purchase we sent a deep link with a redemption token into the app. On open the app calls our backend which checks RevenueCat/Adapty for the active entitlement and then locally unlocks features.

The key lesson: never assume the mobile SDK will magically pick up a web sale. You must sync server side and verify the entitlement in the app on first open. If you used this pattern, how did you handle race conditions where the app opened before the webhook from the subscription provider arrived?

We push the web sale to RevenueCat via their REST API immediately after payment.

Then we return a deep link with a token. The app redeems the token and queries RevenueCat to confirm entitlements. If the webhook is delayed the app falls back to polling for a short window.

The Web2Wave example flow helped me implement the redemption step quickly.

Important detail is to reconcile on app open. Send the web purchase into RevenueCat and have the app call your backend which checks RevenueCat and returns the entitlement state. That removes timing issues and keeps the UX clean. We automated this with a web-to-app flow template and it saved a bunch of edge case fixes.

We wrote the web checkout to call RevenueCat after a successful charge and stored a short token for the app to redeem.

On app open we verify with RevenueCat and unlock features. It cut down support tickets a lot.

Push web sale to RC
App redeems token
Sync done

Push the purchase server side into your subscription provider and never rely on client SDK sync alone. Implement a redemption token the app can redeem on first open and include a short polling fallback for webhooks. Also surface a clear UI state—“restoring purchase”—so users understand what is happening if there is a small delay.

We saw webhook delays during peak hours. Polling for 30 seconds on app open solved most cases. Only a tiny fraction needed manual support after that.

We mirrored the web sale into Adapty and let the app confirm on open.

Works well in practice.