Overview
Flex integrates with RevenueCat to help you manage subscriptions seamlessly across platforms. This guide walks you through connecting your RevenueCat account to Flex, passing a stable customer identifier, saving the integration, and understanding how events map between systems.Installation Guide
Add RevenueCat in Flex
-
You can find these in your RevenueCat project under App Settings.

Configure in RevenueCat


Pass a Custom User Identifier to RevenueCat
metadata as REVENUE_CAT_CUSTOMER_ID.Save and Sync
Tip: If you have existing subscriptions, run an initial sync (or perform a backfill) so historical subscriptions are recognized in RevenueCat.
How Flex Integrates with RevenueCat
There are two ways subscriptions can flow into RevenueCat:Native Stripe Integration
"STRIPE".Flex External Purchases API
POST /v1/receipts/external). RC generates events with store: "EXTERNAL".storeis"EXTERNAL", not"STRIPE"— update any webhook consumers that filter by store- Refund events have
price: 0.0, never negative — use the RC Subscriber API or Flex API for refund amounts expiration_reasonis alwaysnull— usecancel_reasonon preceding CANCELLATION events instead- Prorated refunds are invisible in webhooks — no
CUSTOMER_SUPPORTevent is generated; use Flex API to detect partial refunds - IDs use Flex format (
fprod_,fsub_,fcus_) instead of Stripe format (prod_,si_,cus_) — treat all IDs as opaque strings
Subscription Lifecycle Events
Flex syncs the following RevenueCat event types. This is the complete list — every event type that Flex sends to RC:ProductChange (upgrades/downgrades) is not currently supported. All other subscription lifecycle events are fully implemented and synced in real-time.Stripe Trigger Mapping
Each Flex RC sync event is triggered by a specific Stripe webhook event:Event Sequences by Scenario
New Subscription (No Trial)
New Subscription (No Trial)
New Subscription (With Free Trial)
New Subscription (With Free Trial)
INITIAL_PURCHASE in RC webhooks. The first has price 0 and status trialing; the second has the actual price and status active.Renewal
Renewal
Payment Failure → Recovery
Payment Failure → Recovery
EXPIRATION event when Stripe deletes it.Cancel at End of Billing Period (Option A)
Cancel at End of Billing Period (Option A)
Undo Cancel / Re-subscribe Before Period Ends
Undo Cancel / Re-subscribe Before Period Ends
Cancel Immediately + Full Refund (Option B)
Cancel Immediately + Full Refund (Option B)
Cancel Immediately + Prorated Refund (Option C)
Cancel Immediately + Prorated Refund (Option C)
Subscription Expires Naturally (After Cancel at Period End)
Subscription Expires Naturally (After Cancel at Period End)
CancelAtPeriodEnd was set.Field Reference
Every RC webhook event from Flex will have these field values:Key Differences from Stripe-Native Integration
If your webhook consumer was originally built for a native Stripe → RevenueCat integration, the following differences apply when receiving events from Flex. These are inherent to the RevenueCat External Purchases API and have been confirmed with the RevenueCat team (March 2026).Refund Handling
Refund visibility in RC webhooks depends on the refund type and flow:How to detect and measure refunds
Recommendations for Webhook Consumers
Handling the store field
Accept events where store is either"STRIPE" or "EXTERNAL":
Detecting subscription state changes
Use the event type andcancel_reason to determine subscription state:
Handling refunds
Detect refund occurrence
cancel_reason == "CUSTOMER_SUPPORT" on CANCELLATION events.Do NOT rely on negative price
0.0 for External store events.Get refund amounts
Handle prorated/custom refunds
Handling expiration events
Acceptexpiration_reason: null. The External store does not populate this field. To determine why a subscription expired, look at the preceding CANCELLATION event’s cancel_reason.
ID formats
Treat all IDs as opaque strings. Do not parse, validate format, or assume a prefix:Example Payloads
All payloads below are from real webhook captures in the RevenueCat sandbox.- INITIAL_PURCHASE (Trial Start)
- INITIAL_PURCHASE (Conversion)
- RENEWAL
- CANCELLATION (User)
- CANCELLATION (Refund)
- UNCANCELLATION
- EXPIRATION
- BILLING_ISSUE
FAQ
Why is store EXTERNAL instead of STRIPE?
Why is store EXTERNAL instead of STRIPE?
"EXTERNAL" for all events processed through this API. This is expected behavior, not a misconfiguration.Why is price 0.0 on refund events instead of negative?
Why is price 0.0 on refund events instead of negative?
How do I know the refund amount?
How do I know the refund amount?
- RC Subscriber API:
GET /v1/subscribers/{app_user_id}— checktotal_revenue_in_usd - Flex Webhooks: Use Flex’s own webhook events, which include exact refund amounts and types
- Flex API: Query the Flex API for subscription/refund details
Why is there no refund event for prorated refunds?
Why is there no refund event for prorated refunds?
CANCELLATION (CUSTOMER_SUPPORT) event for full refunds processed through the External API. Prorated and custom refunds adjust revenue internally but do not trigger a distinct webhook event. Use the Flex API or RC Subscriber API to detect partial refunds.Why is expiration_reason null?
Why is expiration_reason null?
cancel_reason on the preceding CANCELLATION event.Is revenue correctly tracked despite these differences?
Is revenue correctly tracked despite these differences?
GET /v1/subscribers/{id} to get accurate revenue figures.Does Flex support trial subscriptions?
Does Flex support trial subscriptions?
TrialPurchase (trial start, $0 invoice) and TrialConversion (first real payment after trial). Both appear as INITIAL_PURCHASE in RC webhooks — differentiate by checking price (0.0 for trial start, positive for conversion).Does Flex support undo-cancel (re-subscribe)?
Does Flex support undo-cancel (re-subscribe)?
cancel_at_period_end is reversed, Flex sends an UndoCancelAtPeriodEnd event which appears as UNCANCELLATION in RC webhooks.Does Flex handle billing failures and recovery?
Does Flex handle billing failures and recovery?
BillingIssue is sent when payment fails (status: in_grace_period, gives_access: true). BillingSucceeds is sent when payment recovers (same logic as Renewal).Will these differences change in the future?
Will these differences change in the future?