Skip to main content
Supported on: iOS SDK 1.0.70+ · Android SDK 1.0.42+ · React Native SDK 1.0.7+ (New Architecture only)
The AppDNA React Native SDK provides a billing module for managing in-app purchases, subscriptions, entitlement verification, and purchase restoration. All billing logic is handled by the native iOS and Android SDKs.

Configuration

Set the billing provider when configuring the SDK:

AppDNABillingProvider Options

You must set the billingProvider in AppDNAOptions before accessing AppDNA.billing. If set to 'none', billing module methods will throw errors.

Billing Module

Access the billing module through AppDNA.billing, which returns an AppDNABilling instance:

Get Products

Fetch product information for one or more product identifiers:
Returns 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:
The 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

The transaction 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):
Returns 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:
Returns boolean.

Get Entitlements

Retrieve all current entitlements for the user:
Returns 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 the AppDNABillingDelegate interface for fine-grained billing lifecycle callbacks:
The 5 methods’ semantics:
  • onPurchaseCompleted(productId, transaction) — fires after the store completes a purchase (paywall, direct AppDNA.billing.purchase(...), or transaction queue retry). The transaction map shape is documented above.
  • onPurchaseFailed(productId, error) — fires on store-side failure (user cancel, payment declined, network). error is the platform’s error message as a string, delivered as unknown — it is not a JS Error, and it has no .message property. Narrow it (String(error)) before displaying. For a machine-readable reason code, use AppDNAPaywallDelegate.onPaywallPurchaseFailed, which also carries errorType.
  • 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 typed Entitlement objects, subscribe with AppDNA.billing.onEntitlementsChanged(...) instead, which parses them for you.
  • onRestoreCompleted(restoredProductIds) — fires when a direct AppDNA.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.
Overlap with 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

Always test purchases using sandbox/test accounts. On iOS, use StoreKit Testing in Xcode or a Sandbox Apple ID. On Android, use license testing accounts configured in the Google Play Console.

Auto-Tracked Events

The SDK automatically tracks the following billing events. You don’t need to call AppDNA.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.