Supported on: iOS SDK
1.0.70+ · Android SDK 1.0.42+ · React Native SDK 1.0.7+ (New Architecture only)Configuration
Set the billing provider when configuring the SDK:AppDNABillingProvider Options
Billing Module
Access the billing module throughAppDNA.billing, which returns an AppDNABilling instance:
Get Products
Fetch product information for one or more product identifiers:ProductInfo[].
ProductInfo
Platform-specific keys are omitted, never faked: an absent key means the platform has no concept of it.There is no numeric
price field. iOS’s native price is a Decimal, which cannot cross the bridge without loss, so both platforms send integer priceMicros. Render displayPrice, or divide priceMicros by 1,000,000 when you need the number.Purchase a Product
Initiate a purchase for a product:code is identical on iOS and Android:
Returns a
TransactionInfo.
TransactionInfo
The entitlement the purchase granted arrives on
getEntitlements() / onEntitlementsChanged, which is where entitlement state has always lived.
Transaction Object Keys
Thetransaction payload delivered to onPurchaseCompleted (and AppDNAPaywallDelegate.onPaywallPurchaseCompleted) is the same four keys, as a Record<string, unknown>:
The
offerToken argument on purchase(...) is optional. On Android, pass the offer token from ProductInfo.offerToken to select a specific subscription offer. On iOS, this parameter is ignored. For Apple promotional offers (iOS), the SDK auto-applies any offer associated with the product in App Store Connect.Server-side receipt verification is performed automatically by the SDK. You do not need to send receipts to your own server for validation.
Restore Purchases
Restore previously purchased products (e.g., after reinstalling the app or switching devices):string[] — the restored product IDs, not entitlements.
Apple requires that all apps with in-app purchases include a restore mechanism. Call
restorePurchases() when the user taps a “Restore Purchases” button.Check Active Subscription
Check whether the user has an active subscription:boolean.
Get Entitlements
Retrieve all current entitlements for the user:Entitlement[].
Entitlement
Real-Time Entitlement Changes
Subscription callback
Listen for entitlement changes in real time. The first subscriber starts the native entitlement observer, so nothing is missed:onEntitlementsChanged returns an unsubscribe function. Call it on component unmount to avoid leaks.
AppDNABillingDelegate
Implement theAppDNABillingDelegate interface for fine-grained billing lifecycle callbacks:
onPurchaseCompleted(productId, transaction)— fires after the store completes a purchase (paywall, directAppDNA.billing.purchase(...), or transaction queue retry). Thetransactionmap shape is documented above.onPurchaseFailed(productId, error)— fires on store-side failure (user cancel, payment declined, network).erroris the platform’s error message as a string, delivered asunknown— it is not a JSError, and it has no.messageproperty. Narrow it (String(error)) before displaying. For a machine-readable reason code, useAppDNAPaywallDelegate.onPaywallPurchaseFailed, which also carrieserrorType.onEntitlementsChanged(entitlements)— fires whenever the active entitlement set changes (purchase, restore, renewal, expiry, refund). Delivers an array of entitlement maps (productId,store,status,expiresAt,isTrial,offerType) — not product-ID strings. For typedEntitlementobjects, subscribe withAppDNA.billing.onEntitlementsChanged(...)instead, which parses them for you.onRestoreCompleted(restoredProductIds)— fires when a directAppDNA.billing.restorePurchases()call resolves. Empty array means no prior purchases on file.onBillingUnavailable()— Android only. Play Services is missing or broken and billing will never work on this device. Never fires on iOS. Hide your purchase UI.
AppDNAPaywallDelegate. When a purchase originates from a paywall, the paywall delegate fires onPaywallPurchaseStarted / onPaywallPurchaseCompleted / onPaywallPurchaseFailed. The billing delegate ALSO fires onPurchaseCompleted / onPurchaseFailed for that same purchase — they’re independent observers. Register both if you want paywall-specific UI (banners, confetti) AND a global purchase log; register only the billing delegate if you only care about the eventual state.
Example Implementation
Full Example
Auto-Tracked Events
The SDK automatically tracks the following billing events. You don’t need to callAppDNA.track(...) for any of them.
Android-only events (fired by Play Billing’s subscription lifecycle):
These events flow into the AppDNA Console exactly like any custom event you track yourself, and feed retention / monetization dashboards out of the box.

