Make and restore purchases
Build a custom purchase UI with store-backed products.
Hosted paywalls already handle purchase and restore actions. Use the APIs on this page when you build your own purchase screen.
Load products
The SDK returns the store-backed products configured in your project, with prices already formatted for the customer's storefront:
let products = try await voidhash.getProducts()
let monthly = products.first(where: { $0.slug == "monthly" })
if let monthly {
Text(monthly.displayPrice)
}A product is absent from the result when it is not available on the current store account, environment, or provider configuration.
Start a purchase
purchase(product:) buys through StoreKit 2, syncs the transaction to Voidhash for server
validation, and only then finishes it with the store. The current person refreshes after success,
so entitlement grants update without extra work:
do {
try await voidhash.purchase(product: monthly)
dismiss()
} catch let error as VoidhashStoreError where error.code == "USER_CANCELLED" {
// The customer dismissed the store sheet.
} catch {
reportError(error)
}Errors surface as VoidhashStoreError, whose string form is "CODE: message". Match known codes
such as USER_CANCELLED and PURCHASE_PENDING when recovery differs. See
Errors for the full list.
Grant access from Voidhash state
A successful store dialog is not the entitlement check. Unlock the feature only after the refreshed person contains an active grant.
Restore purchases
Apps should expose a visible restore action. Restore reconciles every purchase the store still reports with Voidhash and refreshes the current person. It does not create a second purchase:
try await voidhash.restorePurchases()Store sheets
try await voidhash.presentCodeRedemptionSheet()
try await voidhash.showManageSubscriptions()Common failure cases
- Product is missing — verify the store product mapping in Studio and the Sandbox environment.
- Purchase already in progress — disable repeated taps while a purchase is running.
- Customer cancels — match
USER_CANCELLEDand treat it as an expected result, not an error. - Purchase succeeds but access is absent — retry the person fetch and verify the product grants the expected perk in Studio.
- Restore finds nothing — confirm the device uses the same App Store account as the original purchase.