Deep link contract

The URL format AppMate emits when the public flow completes — what every SDK parses, and how to coexist with your existing handlers.

Shape

text
{yourscheme}://retention-flow/action
  ?type={action_key}
  &session_id={sid}
  [&feature_id=...]
  [&offer_id=...]
  [&paywall_id=...]
  [&topic=...&message=...]
  [&url=...]

Host is always retention-flow, path is always /action. Together they namespace AppMate's URLs so your existing deep-link handlers never accidentally claim one.

Action keys

  • return_to_app — open your home screen.
  • open_premium — show the paywall. Optional paywall_id.
  • open_offer — required offer_id; your app maps it to a StoreKit promo / RevenueCat offering / custom paywall.
  • open_support — optional topic + message for prefill.
  • open_feature — required feature_id.
  • manage_subscription — SDK handles via StoreKit 2; no extra params.
  • external_url — required url, must be https.
  • none — reserved / unknown; handle defensively.

Coexisting with your existing deep links

The SDK's deepLink(from:) returns nil for URLs that don't match the contract. Chain it in front of your existing handler — non-AppMate URLs pass through:

swift
.onOpenURL { url in
    if let link = RetentionFlow.deepLink(from: url) {
        handleAppMate(link)
        return
    }
    handleMyExistingDeepLinks(url)
}
manage_subscription never enters your URL handler — the SDK calls Apple's StoreKit sheet directly.