AppActor on iOS separates normal purchase, user-facing restore, quiet sync, and explicit queue-drain recovery. They sound similar, but they are not interchangeable.

Standard purchase paths

You can also purchase:
  • a StoreKit Product directly with purchase(product:)
  • a promoted PurchaseIntent with purchase(intent:) on iOS 16.4+
Both product and intent variants also accept an optional placement string for host-app attribution.

Receipt pipeline diagnostics

Use onReceiptPipelineEvent when you need visibility into posting, retries, and dead-letter behavior.
This is the best place to debug stuck receipts instead of guessing from UI state.

Deferred and promoted purchase handling

  • onPurchaseIntent is for promoted purchases and win-back style intents on iOS 16.4+
  • onDeferredPurchaseResolved fires when a previously pending purchase later resolves
Register both before configure if your app has custom purchase UX around those cases.

Restore vs sync vs queue drain

Use the right recovery tool:
  • restorePurchases(syncWithAppStore: false) is the user-facing restore flow
  • restorePurchases(syncWithAppStore: true) forces AppStore.sync() first and may trigger Apple sign-in UI
  • syncPurchases() is the quiet reconciliation path when you do not want restore UX
  • drainReceiptQueueAndRefreshCustomer() is the explicit advanced queue flush path and preserves older syncPurchases()-style behavior from earlier surfaces
  • restore button in settings: restorePurchases()
  • silent catch-up after app/account transitions: syncPurchases()
  • operational recovery when you know receipts are queued locally: drainReceiptQueueAndRefreshCustomer()
Do not expose queue drain as your normal restore button unless you intentionally want that lower-level behavior.