Skip to main content
ZeroSettle supports three integration patterns for user identity. Choose based on your app’s auth system.

Integration Patterns

RevenueCat

Already use RevenueCat? Pass your existing appUserID.

Custom Auth

Have your own auth? Pass your user ID.

Anonymous

No auth system? Email from checkout is used.

Option 1: RevenueCat Users

If you use RevenueCat for subscription management, pass the same user ID:
import SwiftUI
import ZeroSettleKit
import RevenueCat

// Configure - disable StoreKit sync since RevenueCat handles it
ZeroSettle.shared.configure(.init(
    publishableKey: "pk_live_...",
    syncStoreKitTransactions: false
))

// Purchase - use your RC user ID
@State private var selectedProduct: Product?

Button("Buy") { selectedProduct = product }
    .checkoutSheet(item: $selectedProduct, userId: Purchases.shared.appUserID) { result in
        switch result {
        case .success(let transaction):
            print("Purchased: \(transaction.productId)")
        case .failure(let error):
            print("Error: \(error)")
        }
    }
How it works: ZeroSettle processes the web payment and pushes it to RevenueCat via webhook. RevenueCat manages entitlements—you query RC as usual. Restoration: RevenueCat handles it. Call Purchases.shared.restorePurchases().
Set syncStoreKitTransactions: false when using RevenueCat. This prevents duplicate transaction reporting since RevenueCat already handles StoreKit.
If you have your own authentication system:
import SwiftUI
import ZeroSettleKit

// Configure
ZeroSettle.shared.configure(.init(publishableKey: "pk_live_..."))

// Purchase - use your user ID
@State private var selectedProduct: Product?

Button("Buy") { selectedProduct = product }
    .checkoutSheet(item: $selectedProduct, userId: Auth.currentUser.id) { result in
        switch result {
        case .success(let transaction):
            print("Purchased: \(transaction.productId)")
        case .failure(let error):
            print("Error: \(error)")
        }
    }

// Later: restore entitlements
let entitlements = try await ZeroSettle.shared.restoreEntitlements(
    userId: Auth.currentUser.id
)
How it works: ZeroSettle links purchases to your user ID and tracks entitlements. The restoreEntitlements(userId:) method fetches all active entitlements from both web checkout and StoreKit sources. Restoration: Call restoreEntitlements(userId:) after login or on app launch. Works across devices.

Option 3: Anonymous Users

No user system? Users are identified by their email from checkout:
import SwiftUI
import ZeroSettleKit

// Configure
ZeroSettle.shared.configure(.init(publishableKey: "pk_live_..."))

// Purchase - pass empty string for userId
@State private var selectedProduct: Product?

Button("Buy") { selectedProduct = product }
    .checkoutSheet(item: $selectedProduct, userId: "") { result in
        switch result {
        case .success(let transaction):
            print("Purchased: \(transaction.productId)")
        case .failure(let error):
            print("Error: \(error)")
        }
    }
How it works: When userId is empty, the user enters their email during Stripe checkout. ZeroSettle links the purchase to that email address. Restoration: The user’s entitlements are tied to their email. If you later add user accounts, you can query entitlements using the email they provided at checkout.
Anonymous users cannot use restoreEntitlements() without an account system. Consider prompting users to create an account after purchase for better cross-device support.

Checking Entitlements

After restoring entitlements, check if a user has access:
let entitlements = try await ZeroSettle.shared.restoreEntitlements(
    userId: currentUser.id
)

// Check for a specific product
let hasPremium = entitlements.contains {
    $0.productId == "premium_monthly" && $0.isActive
}

// Or check if any entitlement is active
let hasAnyAccess = entitlements.contains { $0.isActive }
Each Entitlement includes:
PropertyTypeDescription
idStringUnique entitlement identifier
productIdStringThe product ID this entitlement grants
sourceEntitlementSource.webCheckout, .storeKit (iOS), or .playStore (Android)
isActiveBoolWhether currently valid
expiresAtDate?Expiration date for subscriptions
purchasedAtDateWhen the purchase was made

Entitlement Sources

Entitlements can come from three sources:
  • .webCheckout: Purchases made through ZeroSettle’s Stripe checkout
  • .storeKit: Purchases made through Apple’s native StoreKit (if syncStoreKitTransactions: true)
  • .playStore: Purchases made through Google Play Billing (if syncPlayStoreTransactions: true)
The SDK merges entitlements from all sources when you call restoreEntitlements().

Best Practices

Use a stable identifier that doesn’t change. UUIDs work well. Avoid using email addresses directly as they can change.
This ensures entitlements are synced even if the app was deleted and reinstalled, or if a purchase was made on another device.
Implement the universal link handler to capture successful purchases. See the Quickstart for setup.

User ID Guidelines

DoDon’t
Use your backend’s user IDUse device identifiers (they change)
Use a UUID you generateUse email (users change emails)
Keep it consistent across platformsUse different IDs per platform

Quickstart

Get started with the full SDK setup