The CroissantPay React Native SDK provides a simple API to manage in-app purchases, subscriptions, and entitlements in your mobile apps.
Installation
Terminal
# Using npm
npm install @croissantpay/react-native
# Using yarn
yarn add @croissantpay/react-native
# Using pnpm
pnpm add @croissantpay/react-nativeiOS Setup
Install CocoaPods dependencies:
cd ios && pod installAndroid Setup
No additional setup required. The SDK automatically links with React Native 0.60+.
Quick Start
1. Wrap your app with CroissantPayProvider
App.tsx
import { CroissantPayProvider } from '@croissantpay/react-native';
export default function App() {
return (
<CroissantPayProvider
config={{
apiKey: 'mx_public_your_key', // From CroissantPay dashboard
apiUrl: 'https://api.croissantlabs.com', // Or your self-hosted URL
appUserId: user?.id, // Your user's ID
debugLogs: __DEV__, // Enable logs in development
}}
>
<YourApp />
</CroissantPayProvider>
);
}2. Use the usePurchases hook
PaywallScreen.tsx
import { usePurchases } from '@croissantpay/react-native';
export function PaywallScreen() {
const {
offerings,
subscriberInfo,
purchase,
restore,
hasEntitlement,
isLoading,
} = usePurchases();
// Check if user has premium access
if (hasEntitlement('premium')) {
return <PremiumContent />;
}
// Get current offering products
const currentOffering = offerings?.current;
const products = currentOffering?.products || [];
return (
<View style={styles.container}>
<Text style={styles.title}>Unlock Premium</Text>
{products.map((product) => (
<TouchableOpacity
key={product.identifier}
style={styles.productButton}
onPress={() => purchase(product.identifier)}
disabled={isLoading}
>
<Text style={styles.productName}>{product.displayName}</Text>
<Text style={styles.productPrice}>{product.priceString}</Text>
</TouchableOpacity>
))}
<TouchableOpacity onPress={restore} disabled={isLoading}>
<Text>Restore Purchases</Text>
</TouchableOpacity>
</View>
);
}API Reference
CroissantPayProvider Props
| Prop | Type | Description |
|---|---|---|
| apiKey | string | Your CroissantPay public API key (required) |
| apiUrl | string | API URL (defaults to https://api.croissantlabs.com) |
| appUserId | string | Your app's user identifier |
| debugLogs | boolean | Enable debug logging |
usePurchases Hook
| Property | Type | Description |
|---|---|---|
| isConfigured | boolean | Whether SDK is configured |
| isLoading | boolean | Loading state for async operations |
| subscriberInfo | SubscriberInfo | null | Current subscriber data with entitlements |
| offerings | Offerings | null | Available products and packages |
| error | Error | null | Last error that occurred |
Methods
purchase(productIdentifier)Promise<PurchaseResult>Purchase a product by its identifier. Handles native store flow and receipt validation.
restore()Promise<RestoreResult>Restore previous purchases. Useful for users reinstalling the app or switching devices.
identify(appUserId)Promise<SubscriberInfo>Identify or switch the current user. Call this when your user logs in.
refresh()Promise<void>Refresh subscriber info and offerings from the server.
hasEntitlement(entitlementId)booleanCheck if user has an active entitlement. Quick way to gate premium features.
Additional Hooks
useEntitlement
Check a specific entitlement:
import { useEntitlement } from '@croissantpay/react-native';
function PremiumFeature() {
const { isActive, entitlement, isLoading } = useEntitlement('premium');
if (isLoading) return <Loading />;
if (!isActive) return <UpgradePrompt />;
return <PremiumContent expiresAt={entitlement.expiresDate} />;
}useCurrentOffering
Get the current offering directly:
import { useCurrentOffering } from '@croissantpay/react-native';
function Paywall() {
const { offering, isLoading } = useCurrentOffering();
if (isLoading || !offering) return null;
return (
<View>
{offering.monthly && (
<ProductCard product={offering.monthly.product} />
)}
{offering.annual && (
<ProductCard product={offering.annual.product} badge="Best Value" />
)}
</View>
);
}Helper Functions
import {
isSubscription,
isConsumable,
formatPeriod,
getBestPackage
} from '@croissantpay/react-native';
// Check product type
isSubscription(product); // true for subscription products
isConsumable(product); // true for consumable products
// Format subscription period
formatPeriod('P1M'); // "month"
formatPeriod('P1Y'); // "year"
formatPeriod('P7D'); // "7 days"
// Get best package from offering (prefers annual > monthly > weekly)
const bestPackage = getBestPackage(offering);Error Handling
import { CroissantPayError } from '@croissantpay/react-native';
async function handlePurchase(productId: string) {
const result = await purchase(productId);
if (!result.success && result.error) {
const error = CroissantPayError.fromPurchaseError(result.error);
if (error.isCancelled) {
// User cancelled - don't show error
return;
}
if (error.isPending) {
// Purchase pending (e.g., parental approval)
showPendingMessage();
return;
}
if (error.isNetworkError) {
showNetworkError();
return;
}
// Show generic error
showError(error.message);
}
}