Skip to main content
Version: 14.6 (Next)

Purchases

tip

For complete working examples, see Purchase Flow and Subscription Flow.

Key Concepts

  1. Event-driven: Purchases are handled through callbacks, not promises
  2. Asynchronous: Purchases may complete after your app is closed
  3. Validation required: Always validate receipts on your server
  4. Finish transactions: Always call finishTransaction() after validation
const {products, requestPurchase, finishTransaction} = useIAP({
onPurchaseSuccess: async (purchase) => {
// Validate on your server, then finish
await finishTransaction({purchase, isConsumable: true});
},
onPurchaseError: (error) => {
if (error.code !== ErrorCode.UserCancelled) {
Alert.alert('Error', error.message);
}
},
});

Direct Listeners

useEffect(() => {
initConnection().then(() => {
const purchaseUpdate = purchaseUpdatedListener((purchase) => {
handlePurchaseUpdate(purchase);
});

const purchaseError = purchaseErrorListener((error) => {
console.log('purchaseErrorListener', error);
});

return () => {
purchaseUpdate.remove();
purchaseError.remove();
};
});
}, []);

Request Purchase

Products (In-App)

await requestPurchase({
request: {
ios: {sku: 'product_id'},
android: {skus: ['product_id']},
},
type: 'in-app',
});

Subscriptions

const subscription = subscriptions.find((s) => s.id === 'sub_id');

await requestPurchase({
request: {
ios: {sku: 'sub_id'},
android: {
skus: ['sub_id'],
subscriptionOffers:
subscription?.subscriptionOfferDetailsAndroid?.map((offer) => ({
sku: 'sub_id',
offerToken: offer.offerToken,
})) || [],
},
},
type: 'subs',
});

Platform Differences

FeatureiOSAndroid
SKU formatSingle skuArray skus
SubscriptionsSimple SKURequires subscriptionOffers
ExpirationexpirationDateIOSautoRenewingAndroid

Finish Transaction

// Consumable (can be purchased again)
await finishTransaction({purchase, isConsumable: true});

// Non-consumable or subscription
await finishTransaction({purchase, isConsumable: false});

Error Handling

import {ErrorCode} from 'react-native-iap';

if (error.code === ErrorCode.UserCancelled) return;
if (error.code === ErrorCode.NetworkError) showRetry();
if (error.code === ErrorCode.ItemUnavailable) showUnavailable();

Purchase Verification

Always validate on your server:

// Send to your server for validation
const isValid = await yourAPI.validateReceipt({
purchaseToken: purchase.purchaseToken,
productId: purchase.productId,
});

if (isValid) {
await finishTransaction({purchase});
}

Resources