# Upgrade from IAP version 4 to version 5

> Follow this guide to migrate from Unity In-App Purchasing version 4 to version 5.

In-App Purchasing (IAP) version 5 (v5) introduces significant architectural improvements that give you better control over each step of your connection and purchase flow. While migration requires that you make significant updates to your existing IAP implementation, this guide provides step-by-step instructions and code samples to help you transition.

> **Note:**
>
> From SDK v5.4, Unity IAP processes Developer Data as part of the [Developer Data framework](/cloud/developer-data.md.md). As such, it is your responsibility to [manage user consent](/cloud/developer-data/user-consent.md.md) using the [UnityConsent](https://docs.unity3d.com/ScriptReference/UnityConsent.ConsentState.html) module.

> **Note:**
>
> Starting in IAP version 5.3.0, you can access IAP AI skills to help migrate your project from version 4 to version 5.
>
> At the bottom of **Project Settings** > **Services** > **In-App Purchasing**, choose one of the following options:
>
> * **Open Skills Folder**: Opens the folder that contains the skill files. Use this option to copy or install the IAP AI Skill in your preferred AI tool.
> * **Install to Claude Code**: Adds the skill directly to Claude Code. This installs a skill named `in-app-purchases`.
>
> After you install the skill, run `in-app-purchases` from your AI tool, and prompt it to migrate your project from version 4 to version 5.

## Overview of changes

The following table summarizes the changes in IAP v5 and what you need to update in your implementation. For more information on the benefits of upgrading, refer to the [Why you should upgrade to Unity In-App Purchasing (IAP) v5.x](https://support.unity.com/hc/articles/47757890052372-Why-you-should-upgrade-to-Unity-In-App-Purchasing-IAP-v5-x) support article.

| Change                                                                                                                                          | Required update                                                                                                               |
| ----------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| Initialization is split into separate async calls for store connection, product fetching, and purchase fetching.                                | [Replace UnityPurchasing.Initialize()](./upgrade-to-iap-v5.md#replace-unitypurchasing.initialize\(\))                         |
| `ConfigurationBuilder` is removed. Products are now defined via a `CatalogProvider` or a list of `ProductDefinitions`.                          | [Replace ConfigurationBuilder](./upgrade-to-iap-v5.md#replace-configurationbuilder)                                           |
| Store Extensions are replaced with Store Extended Services.                                                                                     | [Replace ConfigurationBuilder](./upgrade-to-iap-v5.md#replace-configurationbuilder)                                           |
| `IDetailedStoreListener` and `IStoreListener` are replaced with optional event handlers on `StoreController` and the individual store services. | [Replace IDetailedStoreListener and IStoreListener](./upgrade-to-iap-v5.md#replace-idetailedstorelistener-and-istorelistener) |
| `IStoreController` is replaced with `StoreController`, which can be fetched at any time via `UnityIAPServices.StoreController()`.               | [Replace IStoreController](./upgrade-to-iap-v5.md#replace-istorecontroller)                                                   |
| The `ProcessPurchase` callback is replaced with `OnPurchasePending` for new purchases and `OnPurchasesFetched` for restored purchases.          | [Replace purchase flow](./upgrade-to-iap-v5.md#replace-purchase-flow)                                                         |
| `RestoreTransactions` has moved from Store Extensions to `StoreController` and `PurchaseService`.                                               | [Restore transactions](./upgrade-to-iap-v5.md#restore-transactions)                                                           |
| Entitlement checks are now event-based, using `FetchPurchases` or `CheckEntitlement`.                                                           | [Replace entitlement checks](./upgrade-to-iap-v5.md#replace-entitlement-checks)                                               |
| Apple App Store receipt validation is deprecated. Google Play receipt validation now uses `Order.Info.Receipt`.                                 | [Update receipt validation](./upgrade-to-iap-v5.md#receipt-validation)                                                        |
| `CodelessIAPStoreListener.initializationComplete` is replaced with `CodelessIAPStoreListener.IsInitialized()`.                                  | [Update Codeless IAP](./upgrade-to-iap-v5.md#codeless-iap-specifics)                                                          |

## Replace UnityPurchasing.Initialize()

As of IAP v5, you can initialize the Unity IAP package with greater flexibility. You can connect to the store, fetch products, and handle purchases independently and asynchronously. This approach can help you identify and resolve issues that might block a successful initialization.

> **Note:**
>
> In versions 4 and earlier, the Unity IAP package connects to the store, fetches products, and fetches purchases synchronously at package initialization. The package reports a successful initialization only after completing all these steps.

Follow these steps to replace the behavior of `UnityPurchasing.Initialize()`:

1. Call and await `StoreController.Connect()`:
   * When this call completes, IAP is connected to your current app store.
2. Call `FetchProducts()`:
   * You can add products to an instance of `CatalogProvider`, similar to adding products to the `ConfigurationBuilder`. You can also pass a list of `ProductDefinitions` to `ProductService.FetchProducts()` or `StoreController.FetchProducts()`. For more information, refer to [Code sample of new initialization process](./upgrade-to-iap-v5.md#code-sample-of-new-initialization-process-using-storecontroller).
   * Your `OnProductsFetched` event handler is called when the request has successfully completed. If no specified products could be fetched, `OnProductsFetchFailed` is invoked.
3. Call `FetchPurchases()` after your products have been successfully fetched:
   * Your `OnPurchasesFetched` event handler is called when the request has successfully completed. The `Orders` object contains a filterable collection of all deferred, pending, and completed orders returned by the app store. On failure, `OnPurchasesFetchFailed` is invoked.

> **Note:**
>
> By default, calling `FetchPurchases` invokes `OnPurchasePending` for any pending purchases which have not yet been handled in the session. You can disable this behaviour with `StoreController.ProcessPendingOrdersOnPurchasesFetched(false)`.

### Code sample of new initialization process using StoreController

The following example shows how to initialize IAP v5:

```cs
StoreController m_StoreController;  
  
async void InitializeIAP()  
{  
    m_StoreController = UnityIAPServices.StoreController();  
  
    m_StoreController.OnPurchasePending += OnPurchasePending;  
  
    await m_StoreController.Connect();  
  
    m_StoreController.OnProductsFetched += OnProductsFetched;
    m_StoreController.OnPurchasesFetched += OnPurchasesFetched;  
  
    var initialProductsToFetch = new List<ProductDefinition>  
    {  
        new(goldProductId, ProductType.Consumable),  
        new(diamondProductId, ProductType.Consumable)  
    };  
  
    m_StoreController.FetchProducts(initialProductsToFetch);  
}
void OnProductsFetched(List<Product> products)  
{  
    // Handle fetched products  
    m_StoreController.FetchPurchases();  
}  
void OnPurchasesFetched(Orders orders) {  
   // Process purchases, for example, check for entitlements from completed orders  
}
```

## Replace IDetailedStoreListener and IStoreListener

IAP v5 no longer requires an implementation of `IDetailedStoreListener` or `IStoreListener` for handling purchases or initialization. Replace functionality previously handled by `IDetailedStoreListener` by attaching event handlers to `StoreController`, or to the individual `ProductService`, `PurchaseService`, and `StoreService` services.

For an example of adding event handlers to `StoreController`, refer to [Code sample of new initialization process](./upgrade-to-iap-v5.md#code-sample-of-new-initialization-process-using-storecontroller).

> **Note:**
>
> You can add or remove event handlers at any time, however certain event handlers are recommended before calling certain methods. Unity IAP displays a warning when you call a function before the recommended event handlers have been attached.

To migrate, replace each `IDetailedStoreListener` function with the following:

| `IDetailedStoreListener` functions                                             | IAP v5 replacement                                                                                                                                                                                                                                                                                      |
| ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `OnPurchaseFailed(Product, PurchaseFailureDescription)`                        | Add an event handler to `StoreController.OnPurchaseFailed(FailedOrder)` or `PurchaseService.OnPurchaseFailed(FailedOrder)`                                                                                                                                                                              |
| `OnInitialized(IStoreController controller, IExtensionProvider extensions)`    | Continue execution after `StoreController.Connect()` or `StoreService.Connect()` completes.                                                                                                                                                                                                             |
| `OnInitializeFailed(InitializationFailureReason error)`                        | Add event handlers to  `StoreService.OnStoreDisconnected(StoreConnectionFailureDescription)`, `ProductService.OnProductsFetchFailed(ProductFetchFailed)`, and  `PurchaseService.OnPurchasesFetchFailed(PurchasesFetchFailureDescription)`. You can also add these event handlers via `StoreController`. |
| `OnInitializeFailed(InitializationFailureReason error, string message = null)` | Add an event handler to `StoreController.OnStoreDisconnected(StoreConnectionFailureDescription)` or `StoreService.OnStoreDisconnected(StoreConnectionFailureDescription)`                                                                                                                               |
| `PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)`             | Add an event handler to `StoreController.OnPurchasePending(PendingOrder)` or `PurchaseService.OnPurchasePending(PendingOrder)`                                                                                                                                                                          |

## Replace ConfigurationBuilder

Replace the following `ConfigurationBuilder` functions with the following behaviours:

| `ConfigurationBuilder` functions                 | IAP v5 replacement                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ConfigurationBuilder.AddProduct()`              | Rather than calling `ConfigurationBuilder.AddProduct()`, you can add products to an instance of a `CatalogProvider` via `CatalogProvider.AddProduct()` or `CatalogProvider.AddProducts()`. To fetch products, you can call `CatalogProvider.FetchProducts` and pass a callback, such as `UnityIAPServices.DefaultProduct().FetchProductsWithNoRetries`. For more information on products and `CatalogProvider`, refer to [Create a catalog in the Editor](./create-catalog-in-editor.md). You can also create `ProductDefinitions` and pass them directly to a `FetchProducts()` call on `StoreController` or `ProductService`. |
| `IAppleConfiguration` and `IGoogleConfiguration` | You can find functionality in `IAppleConfiguration` and `IGoogleConfiguration` in the Extended Store Services, such as `AppleStoreExtendedService`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |

> **Note:**
>
> If you fetch a Store Extended Service on an unsupported platform (for example, fetching `AppleStoreExtendedService` in the Editor or on Android), the service will be null. Always check that the service isn't null before adding event handlers or changing settings.

## Replace IStoreController

Replace `IStoreController` with `StoreController`. `StoreController` exposes IAP functionality similar to `IStoreListener`, but you can fetch `StoreController` by calling `UnityIAPServices.StoreController()` at any time.

Replace these methods from `IStoreController` with the following methods from `StoreController`:

| IStoreController          | StoreController                 | Notes                                                                                                                      |
| ------------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `products`                | `GetProducts`                   | `GetProducts` returns a list of products.                                                                                  |
| `InitiatePurchase`        | `Purchase` or `PurchaseProduct` | `Purchase` functions no longer have a `payload` argument. Support for developer payloads was removed in Google Billing v3. |
| `FetchAdditionalProducts` | `FetchProducts`                 | `FetchProducts` is also used to fetch initial products.                                                                    |
| `ConfirmPendingPurchase`  | `ConfirmPurchase`               | `ConfirmPurchase` requires a `PendingOrder`.                                                                               |

## Replace purchase flow

To initiate a purchase, call `Purchase()` or `PurchaseProduct()`on `StoreController` or `PurchaseService`. To confirm a pending purchase, call `StoreController.ConfirmPurchase(PendingOrder)` or `PurchaseService.ConfirmPurchase(PendingOrder)` with the `PendingOrder` you want to confirm. For more information about the purchase flow, refer to [Purchases](./purchases.md).

In IAP v4 and earlier, the `ProcessPurchase` method automatically handled all purchase events. In IAP v5, purchase handling uses the following callbacks:

* `OnPurchasePending`: Called for new purchases.
* `OnPurchasesFetched`: Called for restored purchases.

Use your existing `ProcessPurchase` logic within both of these new callbacks.

## Restore transactions

`RestoreTransactions` has moved from Store Extensions to `StoreController` and `PurchaseService`.

Confirmed purchases are automatically restored when you call `FetchPurchases()` or through  calling `CheckEntitlement()`.

## Replace entitlement checks

To check a user's entitlement to a product, IAP relies on events. You can check the entitlements for all your fetched products by calling `FetchPurchases` and handling the `OnPurchasesFetched` event. To check the entitlement for a single product, call `CheckEntitlement` and handle the `OnCheckEntitlement` event.

## Fetch additional products

Call `FetchProducts` on either `StoreController` or `ProductService` with a list of additional products to trigger your `OnPurchasesFetched` event handler. Alternatively, you can call `FetchProducts` on a `CatalogProvider` instance. For an example of fetching products via `ProductService`, refer to [Code sample of new initialization process](./upgrade-to-iap-v5.md#code-sample-of-new-initialization-process-using-storecontroller). For an example of calling `FetchProducts` on `CatalogProvider`, refer to [Create a catalog in the Editor](./create-catalog-in-editor.md).

## Receipt validation

Receipt validation for Apple App Store receipts has been deprecated. Receipt validation is supported only for Google Play Store. To fetch receipts, use `Order.Info.Receipt` from `Order` instead of `Product.Receipt`.

> **Note:**
>
> Move from StoreKit 1 receipts to [StoreKit 2 jwsRepresentation](https://developer.apple.com/documentation/storekit/verificationresult/jwsrepresentation-21vgo) as soon as possible to improve reliability, security, performance, and ultimately deliver a better experience for your users.

> **Note:**
>
> Use [OrderInfo.Apple.jwsRepresentation](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.IAppleOrderInfo.html#UnityEngine_Purchasing_IAppleOrderInfo_jwsRepresentation) for server-side validation.

## Codeless IAP specifics

Replace the following `CodelessIAPStoreListener` function with the following:

| `CodelessIAPStoreListener` function               | IAP v5 replacement                         |
| ------------------------------------------------- | ------------------------------------------ |
| `CodelessIAPStoreListener.initializationComplete` | `CodelessIAPStoreListener.IsInitialized()` |
