Skip to main content
JustOne is a production iOS habit-tracking app that demonstrates every major ZeroSettle feature. Use it as a reference for how to structure your own integration.
JustOne is a real app on the App Store, not a toy example. The patterns shown here are battle-tested in production.

What It Demonstrates

FeatureFileWhat to look at
SDK configurationJustOneApp.swiftZeroSettle.shared.configure() with preloading enabled
Bootstrap & catalogJustOneApp.swiftSingle bootstrap() call on authentication
Real-time entitlementsJustOneApp.swiftentitlementUpdates async stream
Product modelsZeroSettleProduct.swiftSubscription tiers, consumables, pricing with fallbacks
Purchase managerPurchaseManager.swiftState resolution, billing source preference, consumable crediting
Paywall UIPremiumUpsellView.swiftDual pricing (StoreKit vs web), checkout sheet with custom headers
Consumable shopConsumableShopView.swiftOne-time purchases with .checkoutSheet
Subscription statusSettingsView.swiftActive plan display, billing provider, cancel flow
Switch & SaveSettingsView.swiftMigration banner for StoreKit → web

Key Patterns

SDK Initialization

JustOne configures ZeroSettle in the app entry point with preloading enabled for instant checkout:
// JustOneApp.swift
ZeroSettle.shared.configure(.init(
    publishableKey: key,
    preloadCheckout: true,
    maxPreloadedWebViews: nil
))
ZeroSettle.shared.delegate = purchaseManager

Single Bootstrap Call

Instead of calling fetchProducts() and restoreEntitlements() separately, JustOne uses the single bootstrap() call:
// JustOneApp.swift
.task(id: authViewModel.isAuthenticated) {
    if authViewModel.isAuthenticated, let userId = authViewModel.appleUserID {
        let catalog = try await ZeroSettle.shared.bootstrap(userId: userId)
    }
}

Real-Time Entitlement Updates

JustOne subscribes to entitlement updates to credit consumable tokens when web purchases complete:
// JustOneApp.swift
.task {
    for await _ in ZeroSettle.shared.entitlementUpdates {
        purchaseManager.creditNewConsumableTokens()
    }
}

Billing Source Preference

When a user has both StoreKit and web entitlements (e.g., after Switch & Save), JustOne prefers the web checkout entitlement:
// PurchaseManager.swift
var billingProvider: BillingProvider? {
    let matching = candidates.first(where: { $0.source == .webCheckout })
        ?? candidates.first
    // ...
}

Checkout Sheet with Custom Header

JustOne’s paywall shows a branded header above the payment sheet:
// PremiumUpsellView.swift
.checkoutSheet(
    item: $webCheckoutProduct,
    userId: authViewModel.appleUserID ?? "",
    preload: .all
) {
    CheckoutSheetHeader(product: product)
} onComplete: { result in
    let error = await purchaseManager.processWebCheckout(result)
    if case .success = result { dismiss() }
}

Price Resolution with Fallbacks

JustOne resolves live pricing from the SDK catalog but falls back to hardcoded prices if the catalog isn’t loaded yet:
// ZeroSettleProduct.swift
var formattedPrice: String {
    ZeroSettle.shared.product(for: productId)?
        .storeKitPrice?.formatted ?? fallbackPrice
}

Get the Code

git clone https://github.com/RyanElliott10/JustOne.git
cd JustOne
open JustOne.xcodeproj
Configure with your sandbox key to test purchases.

Next Steps

Quickstart

Step-by-step guide to your first integration

Payment Sheet

Full payment sheet reference

Best Practices

Production-ready patterns and recommendations

Testing

Test your integration in sandbox mode