Skip to article
ActivationPal/docs
Browse docsSuperwall webhook

Superwall webhook

Send Superwall subscription lifecycle events to ActivationPal: trials, paid starts, renewals, cancellations, expirations, billing issues, one-time purchases, and refunds.

View Markdown

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:

  1. Open Integrations → Webhooks and add the URL.
  2. Enable the subscription and payment event types.
  3. Open the endpoint details and copy its signing secret. It starts with whsec_.
  4. 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_purchase with period_type: "TRIAL".
  • Trial conversion = rc_renewal with is_trial_conversion: true.
  • Refund = any event with negative price and proceeds.
  • price is customer revenue in USD. proceeds is 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_currency and currency preserve the original checkout amount.
  • PRODUCTION becomes env=release; SANDBOX becomes env=debug and 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".