1. Choose the integration roles
An app can use Superwall for paywalls while RevenueCat handles purchases. Those are separate choices.
- If Revenue provider = Superwall, configure the signed webhook below. Do not also send RevenueCat webhooks to ActivationPal for this app.
- If Revenue provider = RevenueCat and Paywall platform = Superwall, keep the ActivationPal RevenueCat webhook and do not enable the ActivationPal Superwall webhook. RevenueCat may forward revenue to Superwall for Superwall's own reporting.
ActivationPal accepts one revenue source per app and derives a store-transaction key during provider changes. This prevents the same purchase being counted twice.
One ActivationPal app represents one store application. If a product ships separate iOS and Android Superwall applications, add each platform as its own ActivationPal app.
2. Join revenue to the device
Configure ActivationPal with the same UUID that Superwall uses. For apps without accounts, generate and persist an anonymous UUID, then identify it in both SDKs. Do not use an email address or another personal value. When the identity changes, update both SDKs together.
Native Swift:
ActivationPal.shared.configure(
app: "YOUR_APP_SLUG",
key: "YOUR_ACTIVATIONPAL_API_KEY",
userId: Superwall.shared.userId
)
If you identify a signed-in user, use a UUID and pass the same value to both:
let userId = account.id.uuidString
Superwall.shared.identify(userId: userId)
ActivationPal.shared.setUserId(userId)
React Native / Expo uses Superwall's current provider and hook API:
import { useEffect } from "react";
import { SuperwallProvider, useUser } from "expo-superwall";
import ActivationPal from "activationpal-react-native";
function RevenueIdentity({ userId }: { userId: string }) {
const { identify } = useUser();
useEffect(() => {
if (!identify) return;
void identify(userId).then(() => ActivationPal.setUserId(userId));
}, [identify, userId]);
return null;
}
export default function App() {
return (
<SuperwallProvider apiKeys={{ ios: "YOUR_SUPERWALL_API_KEY" }}>
<RevenueIdentity userId={persistedAnonymousOrAccountUUID} />
<RootNavigator />
</SuperwallProvider>
);
}
Flutter:
await Superwall.shared.identify(userId);
ActivationPal.setUserId(userId);
Native Android:
Superwall.instance.identify(userId)
ActivationPal.setUserId(userId)
Use current Superwall SDKs and UUID identifiers. On iOS, the UUID travels as the StoreKit app account token. Older Superwall SDKs can omit or vary the original app user id, and non-UUID identifiers fall back to Superwall's alias, so either case can prevent a device join.
3. Add the signed webhook
In ActivationPal, open app settings → Superwall webhook. Copy the app-specific URL:
https://activationpal.com/api/superwall?app=YOUR_APP_SLUG
Then in Superwall:
- Open Integrations → Webhooks and add the URL.
- Enable the subscription and payment event types.
- Open the endpoint details and copy its signing secret. It starts with
whsec_. - Paste that signing secret into ActivationPal app settings and save it.
The signing secret is encrypted at rest and is never returned after saving. Superwall authenticates each delivery with svix-id, svix-timestamp, and svix-signature; ActivationPal verifies those headers against the untouched raw request body and rejects stale or modified requests.
4. Event semantics
For API compatibility, both revenue providers use the existing rc_* lifecycle names. The source field tells you which provider delivered the event, and props.provider is superwall.
rc_initial_purchase, rc_renewal, rc_cancellation, rc_uncancellation, rc_expiration, rc_billing_issue, rc_product_change, rc_subscription_paused, rc_non_renewing_purchase
- Trial start =
rc_initial_purchasewithperiod_type: "TRIAL". - Trial conversion =
rc_renewalwithis_trial_conversion: true. - Refund = any event with negative
priceandproceeds. priceis customer revenue in USD.proceedsis net USD after tax and store commission.- Gross revenue sums positive prices. Net revenue sums signed proceeds, so refunds reduce it. Refund totals are the absolute value of negative price/proceeds.
price_in_purchased_currencyandcurrencypreserve the original checkout amount.PRODUCTIONbecomesenv=release;SANDBOXbecomesenv=debugand stays out of release numbers.
The complete verified Superwall envelope is retained in props.provider_payload. Superwall's event id and the derived store-transaction key make retries idempotent.
5. Verify
Use a sandbox store transaction, then check the ActivationPal live feed or agent API. Local StoreKit configuration transactions do not generate App Store server notifications; use a sandbox Apple account or TestFlight transaction on iOS.
curl -s "https://activationpal.com/api/v1/get_events?app=YOUR_APP_SLUG&source=superwall" \
-H "Authorization: Bearer YOUR_AGENT_KEY"
Expect source: "superwall". Sandbox events show env: "debug"; production events show env: "release".