Upgrade offers prompt eligible subscribers to switch from shorter billing cycles (e.g., monthly) to longer ones (e.g., annual) at a savings. The SDK handles proration for existing web checkout subscribers and shows Apple cancel instructions for StoreKit-to-web migrations.
SwiftUI Modifier
The simplest way to present an upgrade offer is the .upgradeOffer() modifier:
@State private var showUpgradeOffer = false
Button("See Upgrade Options") {
showUpgradeOffer = true
}
.upgradeOffer(
isPresented: $showUpgradeOffer,
productId: "premium_monthly",
userId: currentUser.id
) { result in
switch result {
case .upgraded:
showConfirmation("You've been upgraded!")
case .declined:
break
case .dismissed:
break
}
}
Programmatic API
For more control over when and how offers are presented:
let result = await ZeroSettle.shared.presentUpgradeOffer(
productId: "premium_monthly",
userId: currentUser.id
)
// result is UpgradeOffer.Result: .upgraded, .declined, or .dismissed
The productId parameter specifies the user’s current product. The SDK fetches the configured upgrade target from the dashboard automatically.
Headless API
Fetch the upgrade offer configuration without presenting any UI. Use this to build a custom upgrade experience or to check eligibility before showing your own prompt.
let config = try await ZeroSettle.shared.fetchUpgradeOfferConfig(
productId: "premium_monthly",
userId: currentUser.id
)
if config.available, let target = config.targetProduct {
// Show your own upgrade UI
print("Save \(config.savingsPercent ?? 0)% by switching to \(target.name)")
} else {
// User is not eligible — config.reason explains why
print("Not eligible: \(config.reason?.description ?? "unknown")")
}
The config includes the current product, target product, savings percentage, proration details, and display copy — everything you need to render a custom offer.
Results
| Result | Description |
|---|
upgraded / Upgraded | User accepted the offer and the upgrade was executed |
declined / Declined | User explicitly declined the offer |
dismissed / Dismissed | User dismissed the sheet without acting |
Upgrade Types
The SDK handles two upgrade scenarios automatically:
| Type | Description |
|---|
web_to_web | User has an existing web checkout subscription. The SDK modifies the Stripe subscription in place with proration — the user pays the difference immediately and switches to the new billing cycle. |
storekit_to_web | User has a StoreKit subscription. The SDK creates a new web checkout subscription and shows Apple cancel instructions so the user can stop their App Store billing. |
The upgrade type is determined automatically based on the user’s current entitlement source. No code changes needed.
Dashboard Configuration
Upgrade offers are configured entirely from the ZeroSettle dashboard:
- Upgrade paths — Map source products to target products (e.g., monthly → annual)
- Messaging — Customize the title, body, CTA, and dismiss text. Use
{savings_percent} and {target_name} template variables for dynamic copy
- Minimum subscription age — Only show offers to users who have been subscribed for a minimum number of days
- StoreKit migration messaging — Separate body text and cancel instructions for users migrating from Apple billing
Configure upgrade paths and messaging from the ZeroSettle dashboard. No code changes needed to update targeting or copy.
Next Steps