L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Développement · SKILL.md

revenuecat

revenuecat

Use when integrating RevenueCat in-app subscriptions in Flutter apps — entitlements, offerings, paywalls, purchases_flutter SDK, or Stripe backend sync. Load before writing any RevenueCat or IAP code. Query the RevenueCat MCP server for API verification.

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: revenuecat description: Use when integrating RevenueCat in-app subscriptions in Flutter apps — entitlements, offerings, paywalls, purchases_flutter SDK, or Stripe backend sync. Load before writing any RevenueCat or IAP code. Query the RevenueCat MCP server for API verification. allowed-tools: Bash, Read, Write, Edit metadata: triggers: RevenueCat, in-app purchase, IAP, entitlement, offering, paywall, subscription, StoreKit, Google Play Billing, purchases_flutter related-skills: stripe, flutter-mobile domain: payments role: specialist scope: implementation output-format: code last-reviewed: "2026-03-30"

Iron Law

NO ENTITLEMENT CHECK WITHOUT REVENUECAT SDK — never roll your own subscription validation; always delegate to RevenueCat's server-side receipt verification

RevenueCat In-App Subscription Skill

MCP Server

The RevenueCat MCP server is configured in .mcp.json as a remote HTTP MCP at https://mcp.revenuecat.ai/mcp.

Setup command (already configured in .mcp.json):

claude mcp add --transport http revenuecat https://mcp.revenuecat.ai/mcp --header "Authorization: Bearer ${REVENUECAT_API_V2_SECRET_KEY}"

Authentication options:

  • OAuth (recommended for Claude) — seamless browser-based auth, no API key management
  • API v2 Secret Key — pass via Authorization: Bearer <key> header (configured in .mcp.json)

Claude Code Plugin (alternative):

curl -fsSL https://raw.githubusercontent.com/RevenueCat/rc-claude-code-plugin/main/install.sh | bash

Provides slash commands: /rc:status, /rc:apikey, /rc:create-product, /rc:create-app Plus agents: Project Bootstrap Agent, Troubleshooting Agent

Recommended: Create a dedicated API v2 secret key for the MCP server to keep credentials organized.

Fallback: context7 MCP → resolve purchases_flutter library docs.

Available MCP Tools (26 total)

Project Management (1 tool):

ToolDescription
get_projectRetrieve RevenueCat project details

App Management (6 tools):

ToolDescription
list_appsList all apps in a project (with pagination)
get_appRetrieve details for a specific app
create_appCreate a new app in the project
update_appUpdate an existing app's details
delete_appDelete an app from the project
list_app_api_keysList public API keys for an app

Product Management (2 tools):

ToolDescription
list_productsList all products in a project
create_productCreate a new product

Entitlement Management (7 tools):

ToolDescription
list_entitlementsList all entitlements in a project
get_entitlementRetrieve details for a specific entitlement
create_entitlementCreate a new entitlement
update_entitlementUpdate an existing entitlement
delete_entitlementDelete an entitlement
list_entitlement_productsList products attached to an entitlement
attach_products_to_entitlementAttach products to an entitlement
detach_products_from_entitlementDetach products from an entitlement

Offering & Package Management (5 tools):

ToolDescription
list_offeringsList all offerings in a project
create_offeringCreate a new offering
update_offeringUpdate an existing offering
list_packagesList packages for an offering
create_packageCreate a new package for an offering

Customer Management (additional tools):

ToolDescription
get_customerRetrieve subscriber/customer info
list_customer_active_entitlementsList active entitlements for a customer

Context

RevenueCat manages mobile subscription entitlements for Flutter apps. A typical setup might include:

  • Primary app — Pro and Growth subscription tiers
  • Companion app — Free tier (included with primary subscription)
  • Partner/vendor app — Free tier with optional premium features

Stripe is the payment processor; RevenueCat sits on top as the entitlement/subscription management layer. RevenueCat handles App Store and Google Play receipt validation, cross-platform entitlement sync, and subscription analytics.

Architecture Constraints

  • RevenueCat SDK in Flutter only — purchases_flutter package in all 3 apps
  • Stripe as backend processor — RevenueCat connects to Stripe for web subscriptions; App Store/Google Play for mobile
  • Server-side entitlement checks — backend services verify entitlements via RevenueCat REST API, not client claims
  • Single source of truth — RevenueCat is the canonical source for "does this user have access to X?"
  • No direct StoreKit/BillingClient code — RevenueCat SDK abstracts all store interactions
  • API v2 Secret Key — use REVENUECAT_API_V2_SECRET_KEY for MCP server and server-side API calls
  • Environment variables — REVENUECAT_API_KEY_IOS, REVENUECAT_API_KEY_ANDROID, REVENUECAT_API_V2_SECRET_KEY (server-side)

Entitlement Model

Entitlement IDGrants Access ToTiers
pro_landlordFull property management, AI triage, vendor matchingPro, Growth
premium_vendorPriority queue, analytics dashboardVendor Premium
basic_accessCore features, limited propertiesFree (default)

Offerings Structure

default_offering/
├── $rc_monthly/
│   ├── landlord_pro_monthly      ($9/unit/mo)
│   └── landlord_growth_monthly   ($7/unit/mo)
├── $rc_annual/
│   ├── landlord_pro_annual       ($86.40/unit/yr — 20% discount)
│   └── landlord_growth_annual    ($67.20/unit/yr — 20% discount)
└── vendor_premium/
    └── vendor_premium_monthly    (TBD pricing)

Code Conventions

Flutter (Client-Side)

// pubspec.yaml — pin exact version
// purchases_flutter: 8.x.x

import 'package:purchases_flutter/purchases_flutter.dart';

// Initialize in app startup (main.dart or app initialization)
Future<void> initRevenueCat() async {
  final configuration = PurchasesConfiguration(
    Platform.isIOS
        ? const String.fromEnvironment('REVENUECAT_API_KEY_IOS')
        : const String.fromEnvironment('REVENUECAT_API_KEY_ANDROID'),
  );
  await Purchases.configure(configuration);
}

// Identify user after authentication
Future<void> identifyUser(String userId) async {
  await Purchases.logIn(userId);
}

// Check entitlement
Future<bool> hasProAccess() async {
  final customerInfo = await Purchases.getCustomerInfo();
  return customerInfo.entitlements.all['pro_landlord']?.isActive ?? false;
}

// Present paywall
Future<void> showPaywall(BuildContext context) async {
  final offerings = await Purchases.getOfferings();
  final current = offerings.current;
  if (current == null) {
    logger.error('No current offering available');
    // Fallback: direct user to web subscription page
    return;
  }
  // Navigate to paywall screen with offering data
  context.push('/paywall', extra: current);
}

// Purchase a package
Future<bool> purchasePackage(Package package) async {
  try {
    final customerInfo = await Purchases.purchasePackage(package);
    return customerInfo.entitlements.all['pro_landlord']?.isActive ?? false;
  } on PurchasesErrorCode catch (e) {
    if (e != PurchasesErrorCode.purchaseCancelledError) {
      logger.error('Purchase failed', error: e);
    }
    return false;
  }
}

Riverpod Provider Pattern

// Subscription state provider
@riverpod
class SubscriptionState extends _$SubscriptionState {
  @override
  Future<CustomerInfo> build() async {
    return Purchases.getCustomerInfo();
  }

  Future<void> refresh() async {
    state = const AsyncLoading();
    state = AsyncData(await Purchases.getCustomerInfo());
  }
}

// Entitlement check provider
@riverpod
bool hasProEntitlement(HasProEntitlementRef ref) {
  final customerInfo = ref.watch(subscriptionStateProvider);
  return customerInfo.whenOrNull(
    data: (info) => info.entitlements.all['pro_landlord']?.isActive ?? false,
  ) ?? false;
}

Python (Server-Side Verification)

# Backend entitlement verification via RevenueCat REST API v2
import httpx

REVENUECAT_API_SECRET = settings.REVENUECAT_API_V2_SECRET_KEY
REVENUECAT_BASE_URL = "https://api.revenuecat.com/v2"

async def verify_entitlement(user_id: str, entitlement_id: str) -> bool:
    """Server-side entitlement check — never trust client claims."""
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"{REVENUECAT_BASE_URL}/projects/{PROJECT_ID}/subscribers/{user_id}",
            headers={
                "Authorization": f"Bearer {REVENUECAT_API_SECRET}",
                "Content-Type": "application/json",
            },
        )
        if response.status_code != 200:
            logger.error(f"RevenueCat API error: {response.status_code}")
            return False

        subscriber = response.json()["subscriber"]
        entitlement = subscriber.get("entitlements", {}).get(entitlement_id)
        if not entitlement:
            return False

        # Check expiration
        expires = entitlement.get("expires_date")
        if expires and datetime.fromisoformat(expires) < datetime.now(UTC):
            return False

        return True

Webhook Integration (RevenueCat → Backend)

RevenueCat sends server-to-server webhooks for subscription events:

EventAction
INITIAL_PURCHASECreate/upgrade user tier in Cloud SQL
RENEWALExtend subscription, log payment
CANCELLATIONSchedule downgrade at period end
EXPIRATIONDowngrade to Free tier
BILLING_ISSUEFlag account, trigger dunning email
PRODUCT_CHANGEUpdate tier (Pro ↔ Growth)
TRANSFERHandle family sharing / account transfer
@router.post("/webhooks/revenuecat")
async def revenuecat_webhook(request: Request):
    payload = await request.json()
    # Verify webhook authorization header
    auth = request.headers.get("Authorization")
    if auth != f"Bearer {settings.REVENUECAT_WEBHOOK_SECRET}":
        raise HTTPException(status_code=401, detail="Unauthorized")

    event_type = payload.get("event", {}).get("type")
    app_user_id = payload.get("event", {}).get("app_user_id")

    match event_type:
        case "INITIAL_PURCHASE" | "RENEWAL":
            await activate_subscription(app_user_id, payload)
        case "EXPIRATION" | "CANCELLATION":
            await deactivate_subscription(app_user_id, payload)
        case "BILLING_ISSUE":
            await flag_billing_issue(app_user_id, payload)

    return {"status": "ok"}

Testing

// Mock RevenueCat in Flutter widget tests
class MockPurchases extends Mock implements Purchases {}

// Use RevenueCat sandbox for integration tests
// iOS: App Store Sandbox accounts
// Android: Google Play test tracks
# Mock RevenueCat API in Python tests
@pytest.fixture
def mock_revenuecat(httpx_mock):
    httpx_mock.add_response(
        url="https://api.revenuecat.com/v2/projects/test-project/subscribers/test-user",
        json={
            "subscriber": {
                "entitlements": {
                    "pro_landlord": {
                        "expires_date": "2027-01-01T00:00:00Z",
                        "purchase_date": "2026-01-01T00:00:00Z",
                    }
                }
            }
        },
    )

Security Checklist

  • RevenueCat API keys stored in environment variables only
  • Dedicated API v2 secret key created for MCP server (not shared with other services)
  • Server-side entitlement verification for all gated features (never trust client)
  • Webhook authorization header verified on all RevenueCat webhook endpoints
  • User identification via Purchases.logIn() after authentication
  • Purchases.logOut() on user sign-out to prevent entitlement leaking
  • Sandbox/test keys in dev/staging, production keys in production only
  • No direct StoreKit or Google Play Billing API calls — use RevenueCat SDK only

Reference Files

Paywall UI patterns: See reference/revenuecat-paywalls.md (when populated) for paywall screen templates, A/B testing configuration, promotional offer setup, and conversion tracking. Until then, query the revenuecat MCP or context7 MCP for purchases_flutter docs.

Stripe + RevenueCat sync: See reference/revenuecat-stripe-sync.md (when populated) for cross-platform subscription management, web-to-mobile migration, and entitlement reconciliation patterns. Until then, query the revenuecat MCP for current entitlement/offering configuration.

Process

  1. Query RevenueCat MCP for current API and SDK signatures before writing any integration code — use list_entitlements, list_offerings etc. to verify current state
  2. Configure offerings/entitlements via MCP tools (create_entitlement, create_offering, create_package) or RevenueCat dashboard
  3. Implement server-side verification before client-side feature gates
  4. Test with sandbox accounts — never use production credentials in development
  5. Webhook handler for subscription lifecycle events → sync to Cloud SQL
  6. Use API v2 — all server-side code should use RevenueCat REST API v2, not v1
Skills enregistrées