Instructions : Configuration RevenueCat — Propsync System
Document généré par Jarvis le 2026-08-25.
Objectif : remettre à plat toute la configuration RevenueCat (dashboard + code Flutter), supprimer ce qui est obsolète, et aligner avec les plans Supabase en production.
1. Contexte — Architecture de monétisation Propsync System
Propsync System utilise deux canaux de paiement selon la plateforme :
| Canal | Où | Géré par |
|---|---|---|
| Web (abonnement Stripe) | app.propsync-system.com | Stripe direct → webhook Supabase |
| In-app iOS | App Store | RevenueCat → webhook Supabase |
| In-app Android | Google Play | RevenueCat → webhook Supabase |
RevenueCat est une couche d’abstraction : il gère Apple IAP + Google Play Billing et notifie Supabase via webhook.
2. Plans Propsync System (source de vérité : table plans Supabase PROD)
| Plan ID (Supabase) | Nom affiché | plan_key | Prix mensuel | Prix annuel |
|---|---|---|---|---|
free | Free | free | 0 € | — |
starter | Starter | medium ⚠️ | 11,90 € | 119 €/an |
patrimoine | Patrimoine | premium ⚠️ | 22,90 € | 229 €/an |
⚠️ Les
plan_keysont encore sur les anciens noms (medium/premium) en base. Une migration SQL est en attente (voir section 6).
3. Ce qui doit exister dans le dashboard RevenueCat
3.1 Produits (Products)
Créer ou vérifier les produits suivants dans RevenueCat :
| Identifiant RevenueCat | Type | Store ID Android | Store ID iOS | Prix |
|---|---|---|---|---|
propsync_starter_monthly | Auto-renewing | propsync_starter_monthly | propsync_starter_monthly | 11,99 € |
propsync_starter_yearly | Auto-renewing | propsync_starter_yearly | propsync_starter_yearly | 119,99 € |
propsync_patrimoine_monthly | Auto-renewing | propsync_patrimoine_monthly | propsync_patrimoine_monthly | 22,99 € |
propsync_patrimoine_yearly | Auto-renewing | propsync_patrimoine_yearly | propsync_patrimoine_yearly | 229,99 € |
Les Store IDs doivent correspondre exactement aux identifiants créés dans Google Play Console et App Store Connect.
3.2 Entitlements (Droits d’accès)
| Entitlement ID | Description | Produits attachés |
|---|---|---|
starter | Accès Starter | propsync_starter_monthly, propsync_starter_yearly |
patrimoine | Accès Patrimoine | propsync_patrimoine_monthly, propsync_patrimoine_yearly |
Le plan
freene nécessite pas d’entitlement RevenueCat (c’est l’état par défaut sans achat).
3.3 Offerings (Offres présentées à l’utilisateur)
| Offering ID | Description | Packages inclus |
|---|---|---|
default | Offre principale | starter_monthly, starter_yearly, patrimoine_monthly, patrimoine_yearly |
Packages dans l’offering default :
| Package ID | Type | Produit |
|---|---|---|
$rc_monthly (ou starter_monthly) | MONTHLY | propsync_starter_monthly |
starter_yearly | ANNUAL | propsync_starter_yearly |
patrimoine_monthly | MONTHLY | propsync_patrimoine_monthly |
patrimoine_yearly | ANNUAL | propsync_patrimoine_yearly |
4. Clés et configuration
Clés disponibles (à compléter)
| Clé | Valeur | Usage |
|---|---|---|
| SDK Key Android (TEST/Sandbox) | test_phbnmHkLpYPVCpYpvHXBmYptCsf | SDK Flutter en mode debug |
| SDK Public Key Android (PROD) | goog_qwFcYBSGQoOYVcivYtsDWcANrgt | SDK Flutter en release Android |
| SDK Public Key iOS (PROD) | ❌ MANQUANT | SDK Flutter en release iOS |
| Secret API Key REST | ❌ MANQUANT | Lecture API côté serveur / monitoring |
La Secret API Key se trouve dans RevenueCat Dashboard → Project Settings → API Keys → Secret keys.
Elle commence parsk_(ne pas confondre avec les SDK keys).
Utilisation dans Flutter
// lib/services/revenue_cat_service.dart
import 'package:purchases_flutter/purchases_flutter.dart';
import 'package:flutter/foundation.dart';
class RevenueCatService {
static const String _androidApiKeyProd = 'goog_qwFcYBSGQoOYVcivYtsDWcANrgt';
static const String _androidApiKeyTest = 'test_phbnmHkLpYPVCpYpvHXBmYptCsf';
static const String _iosApiKey = 'REMPLACER_PAR_CLE_IOS'; // ← À compléter
static Future<void> initialize(String userId) async {
final apiKey = _getApiKey();
await Purchases.setLogLevel(kDebugMode ? LogLevel.debug : LogLevel.error);
PurchasesConfiguration config = PurchasesConfiguration(apiKey)
..appUserID = userId; // Utiliser l'ID Supabase auth.users.id
await Purchases.configure(config);
}
static String _getApiKey() {
if (defaultTargetPlatform == TargetPlatform.android) {
return kDebugMode ? _androidApiKeyTest : _androidApiKeyProd;
} else if (defaultTargetPlatform == TargetPlatform.iOS) {
return _iosApiKey;
}
throw UnsupportedError('Platform not supported');
}
// Récupérer les offerings
static Future<Offerings?> getOfferings() async {
try {
return await Purchases.getOfferings();
} catch (e) {
debugPrint('RevenueCat getOfferings error: $e');
return null;
}
}
// Acheter un package
static Future<CustomerInfo?> purchasePackage(Package package) async {
try {
final customerInfo = await Purchases.purchasePackage(package);
return customerInfo;
} catch (e) {
debugPrint('RevenueCat purchase error: $e');
return null;
}
}
// Vérifier l'entitlement actif
static Future<String> getActivePlan() async {
try {
final customerInfo = await Purchases.getCustomerInfo();
if (customerInfo.entitlements.active.containsKey('patrimoine')) {
return 'patrimoine';
} else if (customerInfo.entitlements.active.containsKey('starter')) {
return 'starter';
}
return 'free';
} catch (e) {
return 'free';
}
}
}5. Webhook RevenueCat → Supabase
RevenueCat doit notifier Supabase à chaque événement d’abonnement.
Configuration webhook dans RevenueCat Dashboard
- URL webhook :
https://udzkrijolqjtmiriyimb.supabase.co/functions/v1/revenuecat-webhook - Events à activer :
INITIAL_PURCHASERENEWALCANCELLATIONEXPIRATIONBILLING_ISSUEPRODUCT_CHANGE
Edge Function Supabase à créer/vérifier : revenuecat-webhook
// supabase/functions/revenuecat-webhook/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
serve(async (req) => {
const body = await req.json()
const event = body.event
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
)
const appUserId = event.app_user_id // = auth.users.id Supabase
const eventType = event.type
// Mapper entitlement → plan Supabase
const entitlementToPlan: Record<string, string> = {
'patrimoine': 'patrimoine',
'starter': 'starter',
}
let newPlan = 'free'
const activeEntitlements = event.subscriber_attributes || {}
if (event.product_id?.includes('patrimoine')) {
newPlan = 'patrimoine'
} else if (event.product_id?.includes('starter')) {
newPlan = 'starter'
}
if (['CANCELLATION', 'EXPIRATION'].includes(eventType)) {
newPlan = 'free'
}
// Mettre à jour subscriptions
await supabase
.from('subscriptions')
.upsert({
user_id: appUserId,
plan: newPlan,
status: ['CANCELLATION', 'EXPIRATION'].includes(eventType) ? 'cancelled' : 'active',
updated_at: new Date().toISOString(),
}, { onConflict: 'user_id' })
return new Response('OK', { status: 200 })
})6. Migration SQL en attente (Supabase DEV + PROD)
Exécuter dans le SQL Editor Supabase pour les deux environnements :
BEGIN;
ALTER TABLE subscriptions DROP CONSTRAINT subscriptions_plan_check;
UPDATE subscriptions SET plan = 'patrimoine' WHERE plan = 'premium';
UPDATE subscriptions SET plan = 'starter' WHERE plan = 'medium';
ALTER TABLE subscriptions
ADD CONSTRAINT subscriptions_plan_check
CHECK (plan IN ('free', 'starter', 'patrimoine'));
COMMIT;7. Checklist de validation
- Dashboard RevenueCat : produits créés et liés aux Store IDs Google Play + App Store
- Dashboard RevenueCat : entitlements
starteretpatrimoineconfigurés - Dashboard RevenueCat : offering
defaultavec les 4 packages - Flutter :
RevenueCatService.initialize(userId)appelé au démarrage (après auth Supabase) - Flutter :
appUserID=supabase.auth.currentUser!.id(synchronisation identité) - Flutter : clé iOS renseignée dans
_iosApiKey - Supabase : Edge Function
revenuecat-webhookdéployée - RevenueCat Dashboard : webhook URL configurée vers l’Edge Function
- Migration SQL plan_key exécutée sur DEV puis PROD
- Test : achat sandbox Android → Supabase mis à jour → dashboard admin reflète le changement
8. Clés manquantes à récupérer dans le dashboard
- Secret API Key : RevenueCat Dashboard → Project Settings → API Keys → onglet “Secret keys” →
sk_... - iOS Public Key : RevenueCat Dashboard → Project Settings → API Keys → onglet “Public keys” →
appl_... - App ID Android : Google Play Console → identifiant du produit d’abonnement exact
- App ID iOS : App Store Connect → identifiant du produit d’abonnement exact