> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.qonversion.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Using No-Codes with custom purchases handling

> By default, Qonversion No-Codes utilize the Qonversion SDK for managing purchases. This implies that you should operate Qonversion in subscription management mode. However, if you have your own purchasing infrastructure, you can manage purchases and restores from No-Code screens on your end. It’s as straightforward as supplying a single delegate to Qonversion No-Codes prior to showing the screen.

Integrating Qonversion No-Codes with your own purchasing infrastructure necessitates:

* creating a product within the Qonversion dashboard and associating it with a purchase action on your screen,
* implementing and providing a `PurchaseDelegate` to Qonversion No-Codes that is responsible for managing purchase and restore requests from No-Code screens.

<Warning>
  ### Unity warning

  On Android, when a No-Codes screen is displayed, Unity's game loop is paused because the No-Codes screen runs as a separate Activity on top of Unity's Activity. This means that this delegate will only work on iOS, and will not work on Android.
</Warning>

## Implementing `PurchaseDelegate`

To handle purchase and restore requests from No-Code screens on your end, you should implement `PurchaseDelegate`. It has two simple methods - `purchase`, accepting the requested product, and `restore`.

<CodeGroup>
  ```swift Swift theme={null}
  extension MyPurchaseHandler: NoCodesPurchaseDelegate {
    func purchase(product: Qonversion.Product) async throws {
      // Execute the purchase as you wish here
      // You can throw exceptions in case of errors
    }
    
    func restore() async throws {
      // Execute the restore as you wish here
      // You can throw exceptions in case of errors
    }
  }
  ```

  ```kotlin Kotlin theme={null}
  // You can use either coroutine interface as follows:
  class MyPurchasesHandler : PurchaseDelegate {
      override suspend fun purchase(product: QProduct) {
          // Execute the purchase as you wish here
          // You can throw exceptions in case of errors
      }

      override suspend fun restore() {
          // Execute the restore as you wish here
          // You can throw exceptions in case of errors
      }
  }

  // Or you can use callbacks interface:
  class MyPurchaseHandler : PurchaseDelegateWithCallbacks {
      override fun purchase(
          product: QProduct,
          onSuccess: PurchaseDelegateWithCallbacks.OnSuccess,
          onError: PurchaseDelegateWithCallbacks.OnError
      ) {
          // Execute the purchase as you wish here
          // And call onSuccess once everything is done to close the No-Code screen
          onSuccess()
          // Call onError with exception in case of error.
      }

      override fun restore(
          onSuccess: PurchaseDelegateWithCallbacks.OnSuccess,
          onError: PurchaseDelegateWithCallbacks.OnError
      ) {
          // Execute the restore as you wish here
          // And call onSuccess once everything is done to close the No-Code screen
          onSuccess()
          // Call onError with exception in case of error.
      }
  }
  ```

  ```java Java theme={null}
  class MyPurchasesHandler implements PurchaseDelegateWithCallbacks {
      @Override
      public void purchase(@NonNull QProduct product, @NonNull OnSuccess onSuccess, @NonNull OnError onError) {
          // Execute the purchase as you wish here
          // And call onSuccess once everything is done to close the No-Code screen
          onSuccess.invoke();
          // Call onError with exception in case of error.
      }

      @Override
      public void restore(@NonNull OnSuccess onSuccess, @NonNull OnError onError) {
          // Execute the restore as you wish here
          // And call onSuccess once everything is done to close the No-Code screen
          onSuccess.invoke()
          // Call onError with exception in case of error.
      }
  }
  ```

  ```typescript React Native theme={null}
  class MyPurchaseDelegate implements PurchaseDelegate {
    async purchase(product: Product): Promise<void> {
      // Execute the purchase as you wish here
      // You can throw exceptions in case of errors
    }

    async restore(): Promise<void> {
      // Execute the restore as you wish here
      // You can throw exceptions in case of errors
    }
  }
  ```

  ```dart Flutter theme={null}
  class MyPurchaseDelegate implements NoCodesPurchaseDelegate {
    @override
    Future<void> purchase(QProduct product) async {
      // Execute the purchase as you wish here
      // You can throw exceptions in case of errors
    }

    @override
    Future<void> restore() async {
      // Execute the restore as you wish here
      // You can throw exceptions in case of errors
    }
  }
  ```

  ```csharp Unity theme={null}
  public class MyPurchaseDelegate : NoCodesPurchaseDelegate
  {
      public void Purchase(Product product, System.Action onSuccess, System.Action<string> onError)
      {
          // Execute the purchase as you wish here
          // Call onSuccess() when purchase completes successfully
          // Call onError("error message") in case of errors
          
          try
          {
              // Your purchase logic here
              onSuccess();
          }
          catch (System.Exception e)
          {
              onError(e.Message);
          }
      }

      public void Restore(System.Action onSuccess, System.Action<string> onError)
      {
          // Execute the restore as you wish here
          // Call onSuccess() when restore completes successfully
          // Call onError("error message") in case of errors
          
          try
          {
              // Your restore logic here
              onSuccess();
          }
          catch (System.Exception e)
          {
              onError(e.Message);
          }
      }
  }
  ```

  ```typescript Cordova theme={null}
  class MyPurchaseDelegate implements Qonversion.PurchaseDelegate {
    async purchase(product: Qonversion.Product): Promise<void> {
      // Execute the purchase as you wish here
      // You can throw exceptions in case of errors
    }

    async restore(): Promise<void> {
      // Execute the restore as you wish here
      // You can throw exceptions in case of errors
    }
  }
  ```

  ```typescript Capacitor theme={null}
  class MyPurchaseDelegate implements PurchaseDelegate {
    async purchase(product: Product): Promise<void> {
      // Execute the purchase as you wish here
      // You can throw exceptions in case of errors
    }

    async restore(): Promise<void> {
      // Execute the restore as you wish here
      // You can throw exceptions in case of errors
    }
  }
  ```
</CodeGroup>

## Providing `PurchaseDelegate`

Once you've implemented the `PurchaseDelegate`, you need to provide it to Qonversion No-Codes. There are two equal ways to do it - during the initialization via configuration or after - via the No-Codes method.

<CodeGroup>
  ```swift Swift theme={null}
  // Providing during the initialization
  let purchaseDelegate = MyPurchaseHandler()
  let configuration = NoCodesConfiguration(projectKey: "projectKey", purchaseDelegate: purchaseDelegate)
  NoCodes.initialize(with: configuration)

  // Or after initialization
  let purchaseDelegate = MyPurchaseHandler()
  NoCodes.shared.set(purchaseDelegate: purchaseDelegate)
  ```

  ```kotlin Kotlin theme={null}
  // Providing during the initialization
  val purchaseDelegate = MyPurchaseHandler()
  val noCodesConfig = NoCodesConfig.Builder(this, "projectKey")
      .setPurchaseDelegate(purchaseDelegate)
      .build()
  NoCodes.initialize(noCodesConfig)

  // Or after initialization
  val purchaseDelegate = MyPurchaseHandler()
  NoCodes.shared.setPurchaseDelegate(purchaseDelegate)
  ```

  ```java Java theme={null}
  // Providing during the initialization
  final PurchaseDelegateWithCallbacks purchaseDelegate = new MyPurchaseHandler();
  final NoCodesConfig noCodesConfig = new NoCodesConfig.Builder(this, "projectKey")
      .setPurchaseDelegate(purchaseDelegate)
      .build();
  NoCodes.initialize(noCodesConfig);

  // Or after initialization
  final PurchaseDelegateWithCallbacks purchaseDelegate = new MyPurchaseHandler();
  NoCodes.getSharedInstance().setPurchaseDelegate(purchaseDelegate);
  ```

  ```typescript React Native theme={null}
  // Providing during the initialization
  const purchaseDelegate = MyPurchaseHandler()
  const noCodesConfig = new NoCodesConfigBuilder('projectKey')
    .setPurchaseDelegate(purchaseDelegate)
    .build();
  NoCodes.initialize(noCodesConfig);

  // Or after initialization
  const purchaseDelegate = MyPurchaseHandler()
  NoCodes.getSharedInstance().setPurchaseDelegate(purchaseDelegate);
  ```

  ```dart Flutter theme={null}
  // Providing during the initialization
  final purchaseDelegate = MyPurchaseDelegate();
  final noCodesConfig = NoCodesConfigBuilder('projectKey')
      .setPurchaseDelegate(purchaseDelegate)
      .build();
  NoCodes.initialize(noCodesConfig);

  // Or after initialization
  final purchaseDelegate = MyPurchaseDelegate();
  await NoCodes.getSharedInstance().setPurchaseDelegate(purchaseDelegate);
  ```

  ```csharp Unity theme={null}
  // Providing during the initialization
  var purchaseDelegate = new MyPurchaseDelegate();
  var noCodesConfig = new NoCodesConfigBuilder("projectKey")
      .SetPurchaseDelegate(purchaseDelegate)
      .Build();
  NoCodes.Initialize(noCodesConfig);

  // Or after initialization
  var purchaseDelegate = new MyPurchaseDelegate();
  NoCodes.GetSharedInstance().SetPurchaseDelegate(purchaseDelegate);
  ```

  ```typescript Cordova theme={null}
  // Providing during the initialization
  const purchaseDelegate = MyPurchaseHandler()
  const noCodesConfig = new Qonversion.NoCodesConfigBuilder('projectKey')
    .setPurchaseDelegate(purchaseDelegate)
    .build();
  Qonversion.NoCodes.initialize(noCodesConfig);

  // Or after initialization
  const purchaseDelegate = MyPurchaseHandler()
  Qonversion.NoCodes.getSharedInstance().setPurchaseDelegate(purchaseDelegate);
  ```

  ```typescript Capacitor theme={null}
  // Providing during the initialization
  const purchaseDelegate = MyPurchaseHandler()
  const noCodesConfig = new NoCodesConfigBuilder('projectKey')
    .setPurchaseDelegate(purchaseDelegate)
    .build();
  NoCodes.initialize(noCodesConfig);

  // Or after initialization
  const purchaseDelegate = MyPurchaseHandler()
  NoCodes.getSharedInstance().setPurchaseDelegate(purchaseDelegate);
  ```
</CodeGroup>

## Availability

The described feature is available in the following SDK versions

| Platform     | SDK version     |
| ------------ | --------------- |
| iOS          | 6.1.0+          |
| Android      | No-Codes 1.2.1+ |
| React Native | 10.1.0+         |
| Flutter      | 11.1.0+         |
| Unity        | 9.0.0+          |
| Cordova      | 7.0.0+          |
| Capacitor    | 1.0.0+          |

***

[Success and Failure Actions](success-failure-actions)

[Create Offerings](offerings)
