Chapter 6: The Purchase Flow
Implementing the purchase flow directly means building BillingFlowParams, calling launchBillingFlow(), handling the PurchasesUpdatedListener callback, dealing with result codes, posting purchases to your backend, acknowledging, and managing edge cases like duplicate purchases and mid-flow disconnections.
The RevenueCat purchase flow is:
The rest is handled by the SDK. This chapter explains what happens inside that call and the decisions you still need to make.
The Complete Flow

What awaitPurchase() Does Internally
- Builds
BillingFlowParamswith the correctProductDetailsParams: maps yourPackageto the right offer token and product details format that Google Play expects. - Calls
BillingClient.launchBillingFlow(): opens the Google Play purchase sheet attached to the activity you passed inPurchaseParams. - Waits for the
PurchasesUpdatedListenerresult: suspends the coroutine until Google Play delivers the outcome, whether success, cancellation, or an error code. - If result is
OK, posts the purchase token to the RevenueCat backend: sends the raw token from Google Play to RevenueCat so it can be recorded and verified server side. - RevenueCat backend calls
purchases.subscriptionsv2.getorpurchases.products.getto verify: RevenueCat hits the Google Play Developer API to confirm the purchase is genuine before granting any entitlement. - SDK acknowledges or consumes the purchase: calls
acknowledgePurchase()for subscriptions and non-consumables, orconsumePurchase()for consumables, within the 3 day window Google requires. - Returns
PurchaseResult(storeTransaction, customerInfo): hands back the verified transaction and updated entitlement state so your code can gate access immediately.
If any step fails with a retriable error, the SDK retries automatically. You do not write retry logic.
Callback Style (without coroutines)
If you prefer callbacks:
Personalized Pricing (EU)
For EU compliance with personalized pricing:
This passes isOfferPersonalized = true to BillingFlowParams, which shows the "This price has been customized for you" notice on the Google Play purchase dialog.
Purchasing a Specific SubscriptionOption
When you pass a Package to PurchaseParams, the SDK uses defaultOption (best available offer). To purchase a specific offer:
What the StoreTransaction Contains
PurchaseResult.storeTransaction is a StoreTransaction:
You typically do not need to use this directly. The customerInfo in the same result object is the canonical source of truth for entitlements.
Restoring Purchases
For users who reinstall the app or switch devices:
awaitRestore() calls queryPurchasesAsync() internally, posts all found purchases to RevenueCat, and returns the updated CustomerInfo.