Configuration RevenueCat
Configurez RevenueCat pour les achats in-app et abonnements sur iOS et Android — de la création de compte aux tests sandbox.
Configuration RevenueCat
RevenueCat gère les achats in-app et les abonnements pour iOS et Android. Il encapsule le StoreKit d'Apple et Google Play Billing dans un SDK unique pour que vous n'ayez pas à gérer la validation des reçus, le suivi du statut d'abonnement ou les différences entre plateformes.
Pourquoi pas Stripe ? Apple et Google exigent que les biens numériques vendus dans les apps utilisent leurs systèmes d'achat in-app. Stripe ne peut être utilisé que pour les biens physiques ou les services effectués hors de l'app.
1. Créer un compte RevenueCat
- Allez sur app.revenuecat.com et inscrivez-vous
- Créez un nouveau Projet (ex. "Mon App")
- Ajoutez vos plateformes :
- Apple App Store — vous aurez besoin de vos identifiants App Store Connect
- Google Play Store — vous aurez besoin du compte de service Google Play Console
Configuration Apple App Store
- Dans RevenueCat, allez dans Project Settings > Apps > App Store App
- Entrez votre Bundle ID (doit correspondre à
app.json→ios.bundleIdentifier) - Ajoutez votre App Store Connect Shared Secret :
- Allez sur App Store Connect → Votre App → Général > Informations de l'app > Secret partagé spécifique à l'app
- Copiez le secret et collez-le dans RevenueCat
Configuration Google Play Store
- Dans RevenueCat, allez dans Project Settings > Apps > Play Store App
- Entrez votre Package Name (doit correspondre à
app.json→android.package) - Uploadez votre clé JSON du compte de service :
- Dans Google Play Console → Configuration > Accès API
- Créez un compte de service avec les permissions Données financières
- Téléchargez la clé JSON et uploadez-la dans RevenueCat
2. Configurer les produits
Dans App Store Connect (iOS)
- Allez sur App Store Connect → Votre App → Monétisation > Abonnements
- Créez un Groupe d'abonnements (ex. "Premium")
- Ajoutez les produits d'abonnement :
- Mensuel — ex.
com.yourapp.monthlyà 9,99$/mois - Annuel — ex.
com.yourapp.annualà 79,99$/an
- Mensuel — ex.
- Remplissez le nom d'affichage, la description et les tarifs pour chaque produit
- Soumettez pour review (les produits doivent être approuvés avant de fonctionner en sandbox)
Dans Google Play Console (Android)
- Allez sur Google Play Console → Votre App → Monétiser > Produits > Abonnements
- Créez les produits d'abonnement avec les mêmes IDs que sur iOS :
- Mensuel —
com.yourapp.monthly - Annuel —
com.yourapp.annual
- Mensuel —
- Définissez les tarifs et la période de facturation pour chaque produit
- Activez les produits
3. Configurer les produits RevenueCat
De retour dans le dashboard RevenueCat :
- Allez dans Products et ajoutez chaque ID de produit des deux plateformes
- Créez un Entitlement (ex. "pro") — il représente ce que l'utilisateur débloque
- Attachez vos produits à l'entitlement
- Créez une Offering (ex. "default") — c'est ce que vous affichez aux utilisateurs
- Ajoutez des Packages à l'offering (Mensuel, Annuel) et liez-les à vos produits
4. Installer le SDK
npx expo install react-native-purchasesInitialiser RevenueCat
Récupérez vos clés API depuis le dashboard RevenueCat (Project Settings > Apps > API Keys) :
// lib/revenuecat.ts
import Purchases from "react-native-purchases";
import { Platform } from "react-native";
export async function initRevenueCat() {
Purchases.configure({
apiKey: Platform.OS === "ios"
? "appl_your_ios_api_key"
: "goog_your_android_api_key",
});
}Appelez ceci dans votre layout racine :
// app/_layout.tsx
useEffect(() => {
initRevenueCat();
}, []);Identifier les utilisateurs
Liez RevenueCat à votre utilisateur authentifié pour que le statut d'abonnement se synchronise entre les appareils :
// Après une connexion réussie
const { data: { user } } = await supabase.auth.getUser();
if (user) {
await Purchases.logIn(user.id);
}// Après une connexion réussie
const userId = useConvexAuth().userId;
if (userId) {
await Purchases.logIn(userId);
}5. Configurer les webhooks
Les webhooks RevenueCat notifient votre backend quand un abonnement change (renouvellement, annulation, expiration, etc.).
- Créez une Edge Function Supabase pour gérer les événements webhook :
supabase functions new revenuecat-webhook- Dans le dashboard RevenueCat, allez dans Integrations > Webhooks
- Définissez l'URL du webhook :
https://your-project.supabase.co/functions/v1/revenuecat-webhook - Ajoutez un header d'autorisation pour la sécurité
- Votre Edge Function doit mettre à jour le statut d'abonnement dans votre base de données :
// supabase/functions/revenuecat-webhook/index.ts
Deno.serve(async (req) => {
const body = await req.json();
const event = body.event;
const appUserId = event.app_user_id;
// Mettre à jour le statut d'abonnement selon le type d'événement
// event.type: INITIAL_PURCHASE, RENEWAL, CANCELLATION, EXPIRATION, etc.
await supabase.from("profiles").update({
plan: event.type === "EXPIRATION" ? "free" : "pro",
revenuecat_app_user_id: appUserId,
}).eq("id", appUserId);
return new Response("ok");
});- Créez une action HTTP Convex pour gérer les événements webhook
- Dans le dashboard RevenueCat, allez dans Integrations > Webhooks
- Définissez l'URL du webhook :
https://your-project.convex.site/revenuecat-webhook - Votre action HTTP doit mettre à jour le statut d'abonnement :
// convex/http.ts
http.route({
path: "/revenuecat-webhook",
method: "POST",
handler: async (ctx, req) => {
const body = await req.json();
const event = body.event;
const appUserId = event.app_user_id;
// Mettre à jour le statut d'abonnement selon le type d'événement
await ctx.runMutation(internal.subscriptions.updateStatus, {
userId: appUserId,
plan: event.type === "EXPIRATION" ? "free" : "pro",
});
return new Response("ok");
},
});Types d'événements webhook
| Événement | Quand il se déclenche |
|---|---|
INITIAL_PURCHASE | Premier achat d'abonnement |
RENEWAL | Abonnement renouvelé |
CANCELLATION | Utilisateur a annulé (toujours actif jusqu'à la fin de la période) |
EXPIRATION | Abonnement expiré |
BILLING_ISSUE | Échec de paiement |
PRODUCT_CHANGE | Utilisateur a changé de plan (upgrade/downgrade) |
6. Tester en mode sandbox
Tests sandbox iOS
- Dans App Store Connect, allez dans Utilisateurs et accès > Sandbox > Comptes de test
- Créez un compte testeur sandbox (utilisez un vrai email auquel vous avez accès)
- Sur votre appareil de test : Réglages > App Store > Compte Sandbox — connectez-vous avec le compte sandbox
- Lancez votre build de développement — les achats utiliseront automatiquement l'environnement sandbox
- Les abonnements sandbox se renouvellent à un rythme accéléré :
- 1 semaine → 3 minutes
- 1 mois → 5 minutes
- 1 an → 1 heure
Tests sandbox Android
- Dans Google Play Console, allez dans Configuration > Tests de licence
- Ajoutez les adresses Gmail des testeurs
- Uploadez un APK/AAB sur n'importe quel track (le test interne fonctionne)
- Les testeurs peuvent effectuer des achats sans être facturés
Vérifier dans RevenueCat
- Effectuez un achat test sur votre appareil
- Vérifiez le dashboard RevenueCat → Customers pour voir l'achat
- Vérifiez que votre endpoint webhook a reçu l'événement
- Confirmez que votre base de données a été mise à jour avec le bon statut d'abonnement
RevenueCat Paywall
Construisez un écran paywall pour afficher vos offres :
function PaywallScreen() {
const [offerings, setOfferings] = useState<PurchasesOfferings | null>(null);
useEffect(() => {
Purchases.getOfferings().then(setOfferings);
}, []);
return (
<ScreenLayout>
<Text style={styles.title}>Upgrade to Pro</Text>
<Text style={styles.subtitle}>Unlock all features</Text>
{offerings?.current?.availablePackages.map((pkg) => (
<TouchableOpacity key={pkg.identifier} onPress={() => purchaseSubscription(pkg)}>
<Text>{pkg.product.title}</Text>
<Text>{pkg.product.priceString}/month</Text>
</TouchableOpacity>
))}
<Button title="Restore Purchases" variant="ghost" onPress={restorePurchases} />
</ScreenLayout>
);
}Restaurer les achats
Requis par Apple — les utilisateurs doivent pouvoir restaurer leurs achats sur de nouveaux appareils :
async function restorePurchases() {
try {
const customerInfo = await Purchases.restorePurchases();
const isPro = customerInfo.entitlements.active["pro"] !== undefined;
Alert.alert(isPro ? "Restored!" : "No active subscription found");
} catch (error) {
Alert.alert("Error", "Could not restore purchases");
}
}