---
title: "Verify iOS purchases"
description: "Test a paywall from StoreKit checkout to Feature access."
search:
  tags: ["Features", "iOS"]
  keywords: ["sandbox checkout", "StoreKit test", "purchase verification"]
---

Try your paywall with an App Store sandbox account to see the whole purchase flow: the offer appears, StoreKit completes checkout, and your app unlocks the right Feature.

This walkthrough uses an installed iOS app. [Preview](/docs/guides/preview) is useful for trying the design and paths first, while sandbox checkout exercises the actual purchase integration. See [Paywalls](/docs/guides/paywalls) for how the offer fits together.

## Before you begin

You'll need an app in Nuxie and App Store Connect, a StoreKit Product, an App Store sandbox test account, and an Xcode project targeting iOS 15 or later.

Connect [App Store Connect](/docs/integrations/app-store-connect) and map your app before syncing the catalog. For this walkthrough, use an Xcode development build with the app's `pk_test_` key and a test Experience. The key comes from **Connect your app**. Sandbox purchases belong in Nuxie's test environment.

## 1. Create or import the Product

Create the Product in App Store Connect. In Nuxie, open **Products** and choose **Sync Products**. If you haven't connected the source yet, choose **Connect product source** first.

Open the imported Product and check that its Product ID matches the StoreKit identifier. Its **Prices** tab shows the provider terms. Choose the offer you want to sell; StoreKit supplies the customer's localized price and eligibility in the app.

## 2. Define the access it grants

Create the Feature your app will unlock after purchase. Open the Product's **Entitlements** tab, choose **Grant Feature**, and select it.

Use a Boolean grant for on/off access, or **Unlimited** for a metered capability without a cap. Copy the Feature key for your app. The example below uses `unlimited-exports`; replace it with your configured key.

<span id="3-review-design-and-flow" />

## 3. Review the paywall

Open the paywall's **Canvas** in **Design** mode and connect its starting point, trigger, purchase, restore, and dismissal paths. Decide what the customer sees if they cancel, have a payment pending, or encounter an error or unavailable Product.

Bind the price and offer terms to the Product so they match StoreKit's localized values. If you want to measure conversion, choose a confirmed purchase goal and an attribution window.

Run the paths in **Preview** before continuing. Purchases there are simulated; you'll use StoreKit in the installed app.

## 4. Publish

Choose **Publish**, select your app, and review the trigger, audience, and optional goal. When the Experience reaches **Published**, open **Connect your app**.

For later updates, **Your device first** lets you try the new version before **Go live** makes it available for production delivery.

## 5. Configure the SDK

Install the SDK and set it up with the `pk_test_` key from **Connect your app**, replacing `your_api_key` below. Native StoreKit checkout is the default:

```swift
// nuxie-doc-snippet: first-paywall-setup
import Nuxie

let configuration = NuxieConfiguration(apiKey: "your_api_key")
try NuxieSDK.shared.setup(with: configuration)
```

If your app uses another purchase provider, configure a `NuxiePurchaseDelegate` instead. Use `.observer` when your app or provider also finishes StoreKit transactions. The [SDK purchase guide](/docs/ios-sdk/purchases) includes those options.

## 6. Fire the real trigger

Send the event configured on your Experience from the intended app action:

```swift
// nuxie-doc-snippet: first-paywall-trigger
import Nuxie

NuxieSDK.shared.trigger("export_limit_reached")
```

Replace the sample event name with yours. **Connect your app** shows **Connected** when the SDK connects and **Shown** when the Experience appears.

## 7. Complete and verify purchase

Buy the Product with your sandbox account, then read the Feature your purchase should unlock:

```swift
// nuxie-doc-snippet: first-paywall-feature-access
import Nuxie

func canExportWithoutLimit() async throws -> Bool {
    let access = try await NuxieSDK.shared.hasFeature("unlimited-exports")
    return access.allowed
}
```

Use that result to enable the capability in your app. For an action that spends quota or credits, wait for [`useFeatureAndWait()`](/docs/ios-sdk/features-and-entitlements#consume-usage) and check its `success` field before doing the work. If you configured a conversion goal, its matching outcome is recorded within the attribution window.

## 8. Verify recovery paths

Try the alternatives customers will encounter too:

| Path | What to expect |
| --- | --- |
| **Cancel** | Your cancellation path, with no new access granted. |
| **Pending** | Paid access stays locked until a verified result is available. |
| **Failure or unavailable Product** | Your error or retry path. |
| **Restore with ownership** | Existing access returns without a new sale. |
| **Restore without ownership** | The customer doesn't receive a Feature they don't own. |

Relaunch the app after purchase to check the refreshed access. You can follow the run in the customer's **Journeys** tab and read any answers in the Experience's **Responses** tab.

For later paywall changes, [Versions and updates](/docs/guides/versions-and-updates) explains how to try a new version on your device before rolling it out.

<span id="next-steps" />

## Related guides

[Products and prices](/docs/monetization/products-and-prices) covers the catalog, and [Feature entitlements](/docs/monetization/features-and-entitlements) explains what a purchase includes. For the app methods, see [Purchases (SDK)](/docs/ios-sdk/purchases). [Analytics and revenue](/docs/guides/measurement) explains how to read the results.
