Skip to main content
Use this guide to diagnose and fix common issues with ZeroSettle integration. Each section includes the symptom, likely causes, and step-by-step solutions.

Products Not Loading

Symptom: fetchProducts() returns an empty array or throws an error.
Verify you’re using the correct key for your environment:
  • Sandbox: zs_pk_test_...
  • Live: zs_pk_live_...
Check in your app code:
ZeroSettle.shared.configure(.init(
    publishableKey: "zs_pk_test_..."  // Must match your environment
))
Products exist separately in sandbox and live modes. If you created products in live mode, they won’t appear in sandbox unless you sync them.Fix: Go to the ZeroSettle dashboard, toggle to the correct mode (Sandbox/Live) in the top bar, and verify products exist under the Products tab.
A product must have an active Stripe price mapping to appear in the SDK. If you created a product but didn’t set up pricing, it won’t be returned by fetchProducts().Fix: On the dashboard, check that each product has a web price configured. For BYOS users, ensure your Stripe catalog mapping is complete — see Stripe Catalog.
Check the console for error logs. Common causes:
  • Invalid or expired API key
  • Network connectivity issues
  • Backend server temporarily unavailable
Fix: Regenerate your API key from the dashboard under Settings > API Keys if needed.

Payment Sheet Not Appearing

Symptom: Calling checkoutSheet or triggering a purchase does nothing — no payment UI is shown.
ZeroSettle respects jurisdiction configurations set on your dashboard. If web checkout is disabled for the user’s region, the SDK won’t present a payment sheet.Fix: Check isWebCheckoutEnabled on the product or call fetchProducts() and inspect the jurisdictionConfig. Enable web checkout for the target jurisdiction on the dashboard.
The checkoutSheet modifier requires a non-nil item binding. If selectedProduct is never set, the sheet won’t present.
// Ensure selectedProduct is set before the sheet can appear
Button("Buy") {
    selectedProduct = product  // This must happen
}
.checkoutSheet(item: $selectedProduct, userId: user.id) { result in
    // ...
}
Check the console for errors from the SDK. The PaymentIntent may fail to create if:
  • The product doesn’t have a valid Stripe price mapping
  • The Stripe account isn’t fully onboarded
  • The API key doesn’t match the product’s environment
Fix: Verify your Stripe integration status on the dashboard. For BYOS, ensure your connected account is fully verified.

Apple Pay Not Working

Symptom: The payment sheet appears but Apple Pay is not available as a payment option.
Apple Pay on web requires the checkout domain to be registered with Stripe for your account.For Managed accounts: This is handled automatically.For BYOS accounts: Domain registration happens during OAuth onboarding. If Apple Pay still isn’t working, contact support@zerosettle.io.
Apple Pay requires:
  • A real device (not the iOS Simulator for web-based Apple Pay)
  • Apple Pay configured with at least one card in Wallet
  • A supported region
Fix: Test on a physical device with Apple Pay set up.
The merchant_country parameter must match the Stripe connected account’s country. A mismatch will cause Apple Pay to silently fail.Fix: This is handled automatically by ZeroSettle — the backend resolves the country from your Stripe account. If you suspect an issue, check your Stripe account country in the Stripe dashboard.

Entitlements Not Updating

Symptom: After a successful purchase, restoreEntitlements() doesn’t return the new entitlement.
Entitlements are created when ZeroSettle’s backend processes the Stripe webhook for payment_intent.succeeded. There can be a short delay (usually under 5 seconds).Fix: Call restoreEntitlements() again after a brief delay, or use the delegate callback zeroSettleEntitlementsDidUpdate for real-time updates.
Entitlements are tied to the userId passed during checkout. If you use a different user ID when restoring, the entitlements won’t match.Fix: Ensure the same userId is used consistently across bootstrap(), checkoutSheet, and restoreEntitlements().
A purchase made with a sandbox key creates sandbox entitlements. Restoring with a live key (or vice versa) won’t find them.Fix: Ensure your API key environment matches where the purchase was made.

Checkout URL Not Loading

Symptom: The payment sheet opens but shows a blank page or loading error.
The checkout page is hosted by ZeroSettle and requires internet access. Ensure the device has connectivity.
Some enterprise MDM profiles or content blockers can interfere with WKWebView loading. Test on a device without restrictions.
If your Stripe Express or Standard account onboarding is incomplete, PaymentIntent creation will fail silently.Fix: Check the dashboard under Payouts — your Stripe account status should show as “Active” with charges enabled.
Symptom: After completing checkout in Safari, the app doesn’t reopen or the transaction result is lost.
Universal links require a valid apple-app-site-association file hosted at your domain.Fix: Follow the complete Universal Links setup guide.
During development, universal links only work if the app was installed via Xcode with the Associated Domains entitlement properly configured.Fix: Ensure your app’s Associated Domains capability includes applinks:yourdomain.com.
The SDK needs to intercept the universal link callback. Without the handler, the link opens but the transaction result is lost.
// Add to your root view
ContentView()
    .zeroSettleHandler()
For UIKit, handle it in your SceneDelegate:
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    guard let url = userActivity.webpageURL else { return }
    ZeroSettle.shared.handleUniversalLink(url)
}
iOS caches the apple-app-site-association file aggressively. Changes can take up to 24 hours to propagate.Fix: During development, use the Apple Associated Domains diagnostics to verify your configuration. You can also use swcutil on a Mac to clear the cache.

Delegate Not Called

Symptom: Purchase succeeds but zeroSettleCheckoutDidComplete is never called.
The delegate must be assigned before triggering the purchase:
// Set this early — e.g., in your App init or first view's onAppear
ZeroSettle.shared.delegate = self
If the delegate is a view model or coordinator, ensure it stays in memory throughout the checkout flow. Use @StateObject or a singleton pattern to prevent deallocation.

StoreKit Sync Issues

Symptom: StoreKit purchases aren’t being tracked in the ZeroSettle dashboard.
If you set syncStoreKitTransactions: false during configuration (e.g., because you’re using RevenueCat), StoreKit transactions won’t be forwarded to ZeroSettle.Fix: If you want ZeroSettle to track StoreKit purchases, set syncStoreKitTransactions: true (the default).
The backend verifies the StoreKit transaction’s JWS signature against Apple’s root CA. If verification fails (e.g., due to a tampered transaction), the sync will be rejected.Fix: This typically indicates a security issue. Check the server logs for details.

Debug Logging

Enable verbose SDK logging to diagnose issues:
ZeroSettle.shared.configure(.init(
    publishableKey: "zs_pk_test_...",
))
The SDK logs key events to the console with these prefixes:
  • [ZeroSettle] — General SDK events (configure, bootstrap, product fetch)
  • [ZSCheckout] — Checkout flow events (PaymentIntent creation, sheet presentation, callbacks)
  • [ZSMigrateTipView Business Logic] — Switch & Save visibility decisions
  • [ZSStoreKit] — StoreKit sync events (transaction forwarding, verification)
Filter your Xcode console by ZeroSettle to see all SDK logs in one view.

Still Stuck?

Testing Guide

Walk through a complete end-to-end test flow

Contact Support

Reach out with your issue details and any relevant logs