Rc One Time Products

RevenueCat/ai-toolkit/revenuecat-play-billing/skills/rc-one-time-products

by RevenueCatccfc038185ec457b2ac9077f3bbf1ba947a44dbbApache-2.0; see LICENSEListed Oct 9, 2026Updated Oct 9, 2026

Use this skill when selling one time products on Android with RevenueCat. Covers fetching offerings, running awaitPurchase on a non subscription package, and relying on the SDK to acknowledge or consume automatically.

AI-generated overview

Guides Android developers through selling one-time products with the RevenueCat SDK, from fetching offerings to handling purchase outcomes.

What it does
This skill provides a phased walkthrough for implementing one-time (non-subscription) product purchases on Android using RevenueCat. It covers scoping consumable versus non-consumable products, configuring products in Google Play Console and the RevenueCat dashboard, fetching offerings, launching purchases with awaitPurchase, and reading access through entitlements or non-subscription transactions. It also explains how to handle cancellation, pending payments, and errors, and how to verify purchases via CustomerInfo and webhooks.
When to use it
Use this skill when integrating one-time product purchases into an Android app that already uses or is adopting the RevenueCat SDK. It is suited to developers who need guidance on the purchase flow, entitlement checks, and edge-case handling without writing BillingClient code directly.
Requirements
Requires an Android app project using the RevenueCat SDK, a Google Play Console account with a configured one-time product, and a RevenueCat dashboard account with an API key and configured offering/package. No scripts are included; it is instructions only.

One Time Products with RevenueCat

Sell one time products on Android without writing BillingClient glue. The RevenueCat SDK fetches products, launches the purchase, verifies the receipt, and acknowledges or consumes the token for you.

Phase 1: Scope

Answer these before touching code.

QuestionDecision
Is the product consumable or non consumable?Mark consumables in the RevenueCat dashboard so the SDK calls consumeAsync for you.
Do you read access through entitlements or transactions?Prefer entitlements so access logic stays decoupled from product IDs.
Do you need server notification of the purchase?Use RevenueCat webhooks. The INITIAL_PURCHASE event fires for every new non subscription purchase.

Do not call BillingClient.queryProductDetailsAsync, acknowledgePurchase, or consumeAsync yourself once RevenueCat is integrated. The SDK owns the BillingClient instance.

Phase 2: Prepare

  • Configure the product in Google Play Console as a one time product.
  • In the RevenueCat dashboard, attach the product to an offering and package, and flag it as consumable if it should be consumed on purchase.
  • Confirm Purchases.configure runs once on app start with your Android API key and the current App User ID.

Phase 3: Execute

Fetch offerings, launch the purchase, then read the result off CustomerInfo.

kotlin
val offerings = Purchases.sharedInstance.awaitOfferings()val pkg = offerings.current?.availablePackages?.first() ?: return

Launch the purchase with awaitPurchase. It suspends until the RevenueCat backend verifies the token.

kotlin
val result = Purchases.sharedInstance.awaitPurchase(    PurchaseParams.Builder(activity, pkg).build())val info = result.customerInfo

Read access through entitlements, or fall back to the non subscription transactions list.

kotlin
val hasAccess = info.entitlements["lifetime_access"]?.isActive == trueval owned = info.nonSubscriptionTransactions    .any { it.productIdentifier == "lifetime_product_id" }

The SDK acknowledges non consumables and consumes consumables automatically once the backend verifies the purchase. You do not call acknowledgePurchase or consumeAsync.

Phase 4: Handle Edge Cases

Wrap awaitPurchase to separate cancellation, pending payments, and real errors.

kotlin
try { /* awaitPurchase */ } catch (e: PurchasesTransactionException) {    when {        e.error.code == PurchasesErrorCode.PaymentPendingError -> showPending()        e.userCancelled -> Unit        else -> showError(e.error.message)    }}
OutcomeSDK signalAction
SuccessawaitPurchase returns with updated CustomerInfoGrant access from entitlements or nonSubscriptionTransactions.
User cancelPurchasesTransactionException, userCancelled == trueSwallow silently.
Pending paymentPurchasesTransactionException, PaymentPendingErrorShow a pending message. The SDK updates the entitlement later through UpdatedCustomerInfoListener.
Other errorPurchasesTransactionException, other codesSurface e.error.message to you.

Phase 5: Verify

  • Trust result.customerInfo from awaitPurchase. Do not grant access from optimistic local state.
  • Pending purchases do not grant entitlements. Register an UpdatedCustomerInfoListener so you react when the payment completes.
  • For server side provisioning, subscribe to the RevenueCat INITIAL_PURCHASE webhook. Do not reimplement Google Play Developer API verification.

References

Source and attribution

Source:RevenueCat/ai-toolkitinrevenuecat-play-billing/skills/rc-one-time-productsat commitccfc038

License: Apache-2.0; see LICENSE

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal