rc-one-time-products — Claude Code skill: what it does, how to install
Provides best practices for Android one-time purchases via RevenueCat SDK without manual BillingClient plumbing. Helpful for consumable items and lifetime access.
npx skills add RevenueCat/ai-toolkit --skill rc-one-time-products -a claude-codeWhat rc-one-time-products does
The skill covers a structured workflow for selling non-subscription products on Android. Setup begins in Google Play Console and the RevenueCat dashboard, where consumable goods must be flagged for automatic consumption. Initialisation requires calling Purchases.configure once on application start with an Android API key and user identifier.
Transactions execute through awaitPurchase, which suspends until RevenueCat verifies the purchase receipt. Developers must not call acknowledgePurchase or consumeAsync directly. The SDK manages the underlying BillingClient session and consumes or acknowledges tokens automatically. Entitlement status is then checked via CustomerInfo.
Handling exceptions requires wrapping calls with PurchasesTransactionException. The skill instructs the agent to ignore user cancellations silently, while routing PaymentPendingError to an informative interface state. Pending orders do not grant entitlements immediately, so apps must listen to UpdatedCustomerInfoListener or server webhooks instead.
What it helps with
- configure one-time Android purchases using
awaitPurchase - handle payment cancellations without raising false runtime errors
- inspect granted features via
CustomerInfoentitlements - receive backend purchase confirmations through the
INITIAL_PURCHASEwebhook
Example prompts for the agent
- Show how to retrieve packages and initiate a purchase using
awaitPurchasein Kotlin. - Catch
PurchasesTransactionExceptionto handlePaymentPendingErrorand cancellation separately. - How do I check lifetime access in
CustomerInfowithout relying on product IDs?
How to install rc-one-time-products
1Skills CLI (Vercel)
npx skills add RevenueCat/ai-toolkit --skill rc-one-time-products -a claude-code2Manually: put the files in place
~/.claude/skills/rc-one-time-products/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/rc-one-time-products/
1Skills CLI (Vercel)
npx skills add RevenueCat/ai-toolkit --skill rc-one-time-products -a codex2Manually: put the files in place
.agents/skills/rc-one-time-products/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add RevenueCat/ai-toolkit --skill rc-one-time-products -a cursor2Manually: put the files in place
.cursor/skills/rc-one-time-products/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install RevenueCat/ai-toolkit rc-one-time-products2Manually: put the files in place
.github/skills/rc-one-time-products/SKILL.md1Skills CLI (Vercel)
npx skills add RevenueCat/ai-toolkit --skill rc-one-time-products -a gemini-cli2Platform CLI
gemini skills install https://github.com/RevenueCat/ai-toolkit --path revenuecat-play-billing/skills/rc-one-time-productsManually: put the files in place
.devin/skills/rc-one-time-products/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add RevenueCat/ai-toolkit --skill rc-one-time-products -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about rc-one-time-products
How do I install rc-one-time-products in Claude Code?
Run npx skills add RevenueCat/ai-toolkit --skill rc-one-time-products -a claude-code.
What does rc-one-time-products do?
It instructs AI coding tools on implementing Android one-time and consumable purchases using the RevenueCat SDK.
Should I call acknowledgePurchase or consumeAsync directly?
No, you must avoid calling them manually. The RevenueCat SDK owns the BillingClient lifecycle and acknowledges or consumes tokens automatically once verified.
Source text
SKILL.md · MIT
---
name: rc-one-time-products
description: 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.
license: Apache-2.0; see LICENSE
metadata:
author: RevenueCat
source: revenuecat-handbook chapter 3
keywords:
- android
- revenuecat
- one-time-products
- awaitpurchase
- consumable
- non-consumable
---
# 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.
| Question | Decision |
|---|---|
| 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 == true
val 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)
}
}
```
| Outcome | SDK signal | Action |
|---|---|---|
| Success | `awaitPurchase` returns with updated `CustomerInfo` | Grant access from `entitlements` or `nonSubscriptionTransactions`. |
| User cancel | `PurchasesTransactionException`, `userCancelled == true` | Swallow silently. |
| Pending payment | `PurchasesTransactionException`, `PaymentPendingError` | Show a pending message. The SDK updates the entitlement later through `UpdatedCustomerInfoListener`. |
| Other error | `PurchasesTransactionException`, other codes | Surface `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
- [Full chapter](https://www.revenuecat.com/guides/revenuecat-android-sdk/one-time-products-with-revenuecat)
© RevenueCat · MIT · RevenueCat/ai-toolkit