RevenueCat webhook
Wire RevenueCat to ActivationPal so revenue, trials, and churn land as rc_* events next to your client events.
Other guides: quickstart.md · events.md · agent-api.md · apps.md · apple-ads.md
SDK events carry a device_id; RevenueCat events carry the RevenueCat app user id. Pass userId: Purchases.shared.appUserID to configure (quickstart.md) to join them: purchases land on the buying device's timeline, revenue splits by country and pricing tier, and the revenue chart, revenue mix, and RevenueCat-health cards populate.
Setup
RevenueCat dashboard → Project → Integrations → Webhooks → New webhook:
| Field | Value |
|---|---|
| Webhook URL | https://activationpal.com/api/rc (same URL for every app) |
| Authorization header value | the app's ActivationPal API key verbatim — ap_pk_..., no Bearer prefix |
| Environment | Production |
| Event types | all |
One webhook per app. The key is the same one the SDK uses (apps.md); it routes events to the right app.
What arrives
Each event is stored as rc_ + the lowercased RevenueCat type, full payload in props:
rc_initial_purchase, rc_renewal, rc_cancellation, rc_uncancellation, rc_expiration, rc_billing_issue, rc_non_renewing_purchase, rc_product_change, rc_transfer
Dashboard semantics:
- Trial start =
rc_initial_purchasewithperiod_type: "TRIAL"— price 0, counted as a trial, not revenue. - Trial conversion =
rc_renewalwithis_trial_conversion: true— counted as new-subscriber revenue, not a renewal. - Refund =
rc_cancellationwithcancel_reason: "CUSTOMER_SUPPORT". - One-time purchase =
rc_non_renewing_purchase. - Transfer =
rc_transfer—transferred_from/transferred_toarrays, attributed to the receiving user. - Revenue on every surface = sum of positive
priceprops onrc_*events (gross).
Each event is stamped with the last device that reported the same user id (or an alias) via the SDK — that places purchases on user timelines and city-level geo. RevenueCat's event id is stored uniquely: webhook retries never double-count.
Gotchas
- SANDBOX events are stored
env=debug, outside release numbers — set the environment to Production. Test purchases withpaywall_purchasedfrom a DEBUG build instead. - No
userId, no join:rc_*events still arrive and total correctly, but user timelines and funnel-to-revenue joins stay empty. - Rotating the API key (apps.md) kills the old key immediately — update the webhook's Authorization header in the same sitting, or RevenueCat gets 401s and flags the webhook as failing.
- An event that fails auth is not redelivered by ActivationPal; RevenueCat retries non-200s on its own schedule.
Verify
After a production purchase (or the next real renewal): dashboard live feed, or with an agent API key (agent-api.md):
curl -s "https://activationpal.com/api/v1/get_events?app=myapp&source=revenuecat" \
-H "Authorization: Bearer $AP_KEY"