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. Optionalpaywall_id.open_offer— requiredoffer_id; your app maps it to a StoreKit promo / RevenueCat offering / custom paywall.open_support— optionaltopic+messagefor prefill.open_feature— requiredfeature_id.manage_subscription— SDK handles via StoreKit 2; no extra params.external_url— requiredurl, 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.