docs
Documentation menu

RevenueCat

Bring subscription events into Pushlane.

#How it works

Pushlane receives RevenueCat subscription events through a server-to-server webhook. Each incoming event is authenticated, deduplicated, and written to your revenue ledger. For most event types Pushlane also emits a synthetic event into your flow engine — so a flow can trigger on revenuecat.trial_started and send a push the moment a trial begins, with the expiration timestamp available as a branch condition.

Identity linking is the critical piece: Pushlane attributes a purchase to a user only when RevenueCat's appUserID equals the id passed to Pushlane.identify. The convenience method Pushlane.identifyForRevenueCat keeps both in sync at one call site.

#Step 1 — share the same user id

In your iOS app, replace separate Pushlane.identify and Purchases.configure calls with the single convenience method. It calls Pushlane.identify internally and returns the id so you can chain it directly.

swift
import RevenueCat
import PushlaneCore

// Use ONE id for both SDKs — this is what links a purchase to a Pushlane user.
// Pushlane.identifyForRevenueCat calls Pushlane.identify and returns the id so you
// can chain it directly into Purchases.configure.
let uid = Pushlane.identifyForRevenueCat(currentUser.id)
Purchases.configure(withAPIKey: "appl_…", appUserID: uid)

// On login later, keep both SDKs in lockstep at one call site:
Purchases.shared.logIn(uid) { _, _, _ in }
Pushlane.identifyForRevenueCat(uid)
Heads up
If the two ids ever differ — for example because RevenueCat generated an anonymous id before login — Pushlane cannot link the purchase to the user. Keep the calls in lockstep on every login and identity change.

#Step 2 — generate your webhook secret

In Pushlane → Settings → Integrations → RevenueCat, click Generate webhook secret. Pushlane creates a dedicated high-entropy secret (rcw_…) for your workspace, stores it encrypted, and shows it exactly once — copy it immediately. It can never be re-displayed; if you lose it, rotate it (the old value stops working the moment you do).

Heads up
The webhook secret is not your SDK write-key. The lpk_live_… key ships inside your app binary and is publishable by design — anyone can extract it, so it must never authenticate revenue or entitlement webhooks. Only the server-side rcw_… secret does.

#Step 3 — point the webhook at Pushlane

In RevenueCat → Project → Integrations → Webhooks, add a new webhook with the URL below and set the custom Authorization header value to the rcw_… webhook secret you generated in step 2.

text
POST https://<your-ingest-url>/v1/webhooks/revenuecat
Authorization: rcw_…   ← your RevenueCat webhook secret (NOT the SDK write-key)
Note
Pushlane derives your workspace from the webhook secret server-side, so no tenantId query parameter is needed. A missing or unknown secret is rejected with 401, and a secret can only ever reach its own tenant.

Enable at minimum the event types you want to trigger flows on: TRIAL_STARTED, INITIAL_PURCHASE, RENEWAL, CANCELLATION, EXPIRATION. Enabling all events is fine — unknown future types are ignored gracefully.

#Events Pushlane handles

Pushlane accepts all 14 RevenueCat event types. Most are bridged into the flow engine so you can trigger a push from them. Two types — TRANSFER and TEMPORARY_ENTITLEMENT_GRANT — are still persisted to Pushlane's revenue tables but never enter flows (they are internal RevenueCat bookkeeping, not user-driven signals).

RevenueCat typeFlow event nameBridged to flows
INITIAL_PURCHASErevenuecat.initial_purchaseYes
TRIAL_STARTEDrevenuecat.trial_startedYes
TRIAL_CONVERTEDrevenuecat.trial_convertedYes
RENEWALrevenuecat.renewalYes
CANCELLATIONrevenuecat.cancellationYes
EXPIRATIONrevenuecat.expirationYes
BILLING_ISSUErevenuecat.billing_issueYes
PRODUCT_CHANGErevenuecat.product_changeYes
NON_RENEWING_PURCHASErevenuecat.non_renewing_purchaseYes
UNCANCELLATIONrevenuecat.uncancellationYes
SUBSCRIPTION_PAUSEDrevenuecat.subscription_pausedYes
SUBSCRIPTION_EXTENDEDrevenuecat.subscription_extendedYes
TRANSFERNo (identity bookkeeping)
TEMPORARY_ENTITLEMENT_GRANTNo (internal RC grant)

#Event properties in flows

When a RevenueCat event enters a flow, these properties are available on the event node for branch conditions and notification variables. They are the same across all bridged types — only their values differ.

json
// A flow triggered on revenuecat.trial_started has these properties
// available on the event (usable in branch conditions):
{
  "product_id":          "com.myapp.premium_monthly",
  "store":               "APP_STORE",          // APP_STORE | PLAY_STORE | …
  "environment":         "PRODUCTION",         // PRODUCTION | SANDBOX
  "period_type":         "TRIAL",              // TRIAL | INTRO | NORMAL
  "currency":            "USD",
  "price":               9.99,                 // gross, original currency
  "net_revenue":         6.99,                 // price × (1 − commission) × (1 − tax)
  "is_trial":            true,
  "is_trial_conversion": false,
  "is_production":       true,
  "reward_eligible":     true,
  "purchased_at_ms":     1719878400000,
  "expiration_at_ms":    1722470400000,        // trial end — use in delay nodes
  "revenuecat_event_id": "abc123…",
  "revenuecat_type":     "TRIAL_STARTED",
  "entitlement_ids":     ["premium"]           // present when RC sends them
}
Note
expiration_at_ms is particularly useful: it tells you exactly when the trial or subscription period ends. You can use it in a branch to gate a "trial expiring soon" push on how much time is left.

#Sandbox and test events

Send test event. The RevenueCat dashboard provides a Send test event button (in the webhook configuration view) that emits an event of type TEST. Pushlane acknowledges it with 200 {"ok":true,"test":true} without persisting anything to the revenue tables or entering any flow. This happens after authentication — a test event with a missing or invalid webhook secret still gets 401 — so a green result in the RevenueCat dashboard confirms that the Authorization header is correctly configured for your workspace.

Sandbox subscriptions. Pushlane records all non-test events regardless of environment, but sandbox events are never credited to the reward ledger. An event is reward-eligible only when environment === "PRODUCTION" and store is not PROMOTIONAL or TEST_STORE.

Flow execution is not gated on environment — a sandbox revenuecat.trial_started will enter any matching flow and can send a push. Use a branch condition on is_production if you want to skip sandbox in production flows.

#Deduplication

Pushlane deduplicates on RevenueCat's event.id. A replayed webhook for the same event id returns 200 {"ok":true,"deduped":true} without re-inserting any row or re-entering any flow. It is safe for RevenueCat to retry.

Next: Building flows — trigger a flow on revenuecat.trial_started and send a push when a trial begins.