Making Purchases

Make in-app purchases with Qonversion SDK

Make sure to configure Products and Permissions in the Qonversion dashboard before you start handling purchases with Qonversion SDK:

Discover Product-Center Concept
Create Permissions
Create Products

1. Make a purchase

When Products and Permissions are set, you can start making purchases with purchaseProduct for iOS and purchase for Android:

Qonversion.purchaseProduct(product) { (permissions, error, isCancelled) in
  
  if let premium: Qonversion.Permission = permissions["premium"], premium.isActive {
    // Flow for success state
  }
}
[Qonversion purchaseProduct:product completion:^(NSDictionary<NSString *,QNPermission *> * _Nonnull permissions,
                                          NSError * _Nullable error,
                                          BOOL cancelled) {
  QNPermission *premiumPermission = permissions[@"premium"];
  
  if (premiumPermission && premiumPermission.isActive) {
    // Flow for success state
  }
}];
Qonversion.purchase(this, product, new QonversionPermissionsCallback() {
    @Override
    public void onSuccess(@NotNull Map<String, QPermission> permissions) {
        QPermission premiumPermission = permissions.get("premium");

        if (premiumPermission != null && premiumPermission.isActive()) {
            // handle active permission here
        }
    }

    @Override
    public void onError(@NotNull QonversionError error) {
        // handle error here
    }
});
Qonversion.purchase(this, product, callback = object: QonversionPermissionsCallback {
    override fun onSuccess(permissions: Map<String, QPermission>) {
        val premiumPermission = permissions["premium"]
        if (premiumPermission != null && premiumPermission.isActive()) {
            // handle active permission here
        }
    }

    override fun onError(error: QonversionError) {
        // handle error here
    }
})
try {
  final Map<String, QPermission> permissions = await Qonversion.purchaseProduct(product);
} on QPurchaseException catch (e) {
  print(e);
}
// purchaseProduct method and A/B testing is not yet available on React Native.
// You can use purchase method and Qonversion product ID:
try {
  const permissions: Map<string, Permission> = await Qonversion.purchase('main');
} catch (e) {
  if (e.userCanceled) {
    // purchase canceled by the user
  }
  console.log(e);
}
Qonversion.PurchaseProduct(product, (permissions, error) =>
{
      if (error == null)
      {
          if (permissions.TryGetValue("premium", out Permission premium) && premium.IsActive)
          {
             // Handle the active permission here
          }
      }
      else
      {
        // Handle the error  
        Debug.Log("Error" + error.ToString());
      }
});

Where "product" is the Qonversion Product created in the Product Center. See the previous step to display Products.

🚧

The purchase method to make purchases as shown below will be depreciated:

Alternatively, you can use purchase method and Qonversion product ID (which will be deprecated):

Qonversion.purchase("main") { (permissions, error, isCancelled) in
  
  if let premium: Qonversion.Permission = permissions["premium"], premium.isActive {
    // Flow for success state
  }
}
[Qonversion purchase:@"main" completion:^(NSDictionary<NSString *,QNPermission *> * _Nonnull permissions,
                                          NSError * _Nullable error,
                                          BOOL cancelled) {
  QNPermission *premiumPermission = permissions[@"premium"];
  
  if (premiumPermission && premiumPermission.isActive) {
    // Flow for success state
  }
}];
Qonversion.purchase(this, "main", new QonversionPermissionsCallback() {
    @Override
    public void onSuccess(@NotNull Map<String, QPermission> permissions) {
        QPermission premiumPermission = permissions.get("premium");

        if (premiumPermission != null && premiumPermission.isActive()) {
            // handle active permission here
        }
    }

    @Override
    public void onError(@NotNull QonversionError error) {
        // handle error here
    }
});
Qonversion.purchase(this, "main", callback = object: QonversionPermissionsCallback {
    override fun onSuccess(permissions: Map<String, QPermission>) {
        val premiumPermission = permissions["premium"]
        if (premiumPermission != null && premiumPermission.isActive()) {
            // handle active permission here
        }
    }

    override fun onError(error: QonversionError) {
        // handle error here
    }
})
try {
  final Map<String, QPermission> permissions = await Qonversion.purchase('main');
} on QPurchaseException catch (e) {
    print(e);
}
try {
  const permissions: Map<string, Permission> = await Qonversion.purchase('main');
} catch (e) {
  if (e.userCanceled) {
    // purchase canceled by the user
  }
  console.log(e);
}
Qonversion.Purchase("main", (permissions, error) =>
{
      if (error == null)
      {
          if (permissions.TryGetValue("premium", out Permission premium) && premium.IsActive)
          {
             // Handle the active permission here
          }
      }
      else
      {
        // Handle the error  
        Debug.Log("Error" + error.ToString());
      }
});

Where "main" is the Qonversion Product Identifier created in the Product Center.

2. Handle a purchase result

The purchaseProduct completion block returns the following three variables:

  • permissions – dictionary with user's permissions
  • error - error
  • isCancelled – (iOS only) boolean, true if a user canceled the purchasing process

Permission IDs are the keys to the permissions dictionary.
The values are the objects of Qonversion.Permission class.
Qonversion.Permission contains the following data:

Var Name

Description

permissionID

Qonversion Permission ID. For example, premium

productID

Product ID created in Qonversion Dashboard

isActive

Boolean. true means a user has active permission.
Please note, isActive = true does not mean that a subscription will be renewed. A user can have active permission, while auto-renewal for the subscription was switched off.

renewState

A renewal state of the product that unlocked the permission. It can have the following values:
nonRenewable – consumable or non-consumable in-app purchase
willRenew – Subscription is active, and auto-renew status is on
billingIssue – There was some billing issue.

startedDate

Initial transaction date. For a subscription with a trial period, the date will be when the trial starts.

expirationDate

The expiration date for a subscription.
null for a consumable/non-consumable in-app purchase or a lifetime subscription

3. Update purchases (Android only)

Upgrading, downgrading, or changing a subscription on Google Play Store requires calling updatePurchase() function.
See Google Play Documentation for more details.

Qonversion.updatePurchase(this, newProduct, "oldProductId", new QonversionPermissionsCallback() {
    @Override
    public void onSuccess(@NotNull Map<String, QPermission> permissions) {
        QPermission premiumPermission = permissions.get("premium");

        if (premiumPermission != null && premiumPermission.isActive()) {
            // handle active permission here
        }
    }

    @Override
    public void onError(@NotNull QonversionError error) {
        // handle error here
    }
});
Qonversion.updatePurchase(this, newProduct, "oldProductId", callback = object: QonversionPermissionsCallback {
    override fun onSuccess(permissions: Map<String, QPermission>) {
        val premiumPermission = permissions["premium"]
        if (premiumPermission != null && premiumPermission.isActive()) {
            // handle active permission here
        }
    }

    override fun onError(error: QonversionError) {
        // handle error here
    }
})
try {
  final Map<String, QPermission> permissions = await Qonversion.updatePurchaseWithProduct(
    newProduct: product,
    oldProductId: 'oldId',
  );
} catch (e) {
  print(e);
}
// Will be available soon
Qonversion.UpdatePurchaseWithProduct(newProduct, "oldId", (permissions, error) =>
{
    if (error == null)
      {
          if (permissions.TryGetValue("premium", out Permission premium) && premium.IsActive)
          {
             // Handle the active permission here
          }
      }
      else
      {
        // Handle the error  
        Debug.Log("Error" + error.ToString());
      }
});

Alternatively, you can use Qonversion product ID for the new product (this option will be deprecated soon):

Qonversion.updatePurchase(this, "newProductId", "oldProductId", new QonversionPermissionsCallback() {
    @Override
    public void onSuccess(@NotNull Map<String, QPermission> permissions) {
        QPermission premiumPermission = permissions.get("premium");

        if (premiumPermission != null && premiumPermission.isActive()) {
            // handle active permission here
        }
    }

    @Override
    public void onError(@NotNull QonversionError error) {
        // handle error here
    }
});
Qonversion.updatePurchase(this, "newProductId", "oldProductId", callback = object: QonversionPermissionsCallback {
    override fun onSuccess(permissions: Map<String, QPermission>) {
        val premiumPermission = permissions["premium"]
        if (premiumPermission != null && premiumPermission.isActive()) {
            // handle active permission here
        }
    }

    override fun onError(error: QonversionError) {
        // handle error here
    }
})
try {
  final Map<String, QPermission> permissions = await Qonversion.updatePurchase(
    newProductId: 'newId',
    oldProductId: 'oldId',
  );
} catch (e) {
  print(e);
}
try {
  const permissions: Map<string, Permission> = await Qonversion.updatePurchase('newId', 'oldId');
} catch (e) {
  console.log(e);
}
Qonversion.UpdatePurchase("newId", "oldId", (permissions, error) =>
{
      if (error == null)
      {
         // Handle permissions here
      }
      else
      {
        // Handle the error  
        Debug.Log("Error" + error.ToString());
      }
}, ProrationMode.ImmediateWithTimeProration);

4. Check user permissions

You need to call the checkPermissions method at the start of your app to check if a user has the required permission. This method will check the user receipt and will return the current permissions. If Apple or Google servers are not responding at the time of the request, Qonversion provides the latest permissions data from its database.

🚧

Note please that the permission object will be available only in case the user made any purchase. In case there were no purchases you will receive an empty result.

Qonversion.checkPermissions { (permissions, error) in
  if let error = error {
    // handle error
    return
  }
  
  if let premium: Qonversion.Permission = permissions["premium"], premium.isActive {
    switch premium.renewState {
       case .willRenew, .nonRenewable:
         // .willRenew is the state of an auto-renewable subscription 
         // .nonRenewable is the state of consumable/non-consumable IAPs that could unlock lifetime access
         break
       case .billingIssue:
         // Grace period: permission is active, but there was some billing issue.
         // Prompt the user to update the payment method.
         break
       case .cancelled:
         // The user has turned off auto-renewal for the subscription, but the subscription has not expired yet.
         // Prompt the user to resubscribe with a special offer.
         break
       default: break
    }
  }
}
[Qonversion checkPermissions:^(NSDictionary<NSString *,QNPermission *> * _Nonnull permissions,
                               NSError * _Nullable error) {
  
  QNPermission *premiumPermission = permissions[@"premium"];
  if (premiumPermission && premiumPermission.isActive) {
    switch (premiumPermission.renewState) {
      case QNPermissionRenewStateWillRenew:
      case QNPermissionRenewStateNonRenewable:
        // QNPermissionRenewStateWillRenew is state for auto-renewable purchases
        // QNPermissionRenewStateNonRenewable is state for in-app purchases that unlock the permission lifetime
        break;
      case QNPermissionRenewStateBillingIssue:
        // Grace period: permission is active, but there was some billing issue.
        // Prompt the user to update the payment method.
        break;
      case QNPermissionRenewStateCancelled:
        // The user canceled the subscription, but the subscription has not expired yet.
        // Prompt the user to resubscribe with some special offer.
        break;
      default:
        break;
    }
  }
}];
Qonversion.checkPermissions(new QonversionPermissionsCallback() {
            @Override
            public void onSuccess(@NotNull Map<String, QPermission> permissions) {
                QPermission premiumPermission = permissions.get("premium");

                if (premiumPermission != null && premiumPermission.isActive()) {
                    switch (premiumPermission.getRenewState()) {
                        case NonRenewable:
                        case WillRenew:
                            // WillRenew is the state of an auto-renewable subscription
                            // NonRenewable is the state of consumable/non-consumable IAPs that could unlock lifetime access
                            break;
                        case BillingIssue:
                            // Prompt the user to update the payment method.
                            break;
                        case Canceled:
                            // The user has turned off auto-renewal for the subscription, but the subscription has not expired yet.
                            // Prompt the user to resubscribe with a special offer.
                            break;
                        default: break;
                }
            }

            @Override
            public void onError(@NotNull QonversionError error) {
                // handle error here
            }
});
Qonversion.checkPermissions(object: QonversionPermissionsCallback {
            override fun onSuccess(permissions: Map<String, QPermission>) {
                val premiumPermission = permissions["premium"]
                if (premiumPermission != null && premiumPermission.isActive()) {
                    // handle active permission here

                    // also you can check renew state if needed
                    // for example to check if user has canceled subscription and offer him a discount
                    when (premiumPermission.renewState) {
                        QProductRenewState.NonRenewable,
                        QProductRenewState.WillRenew ->
                            // WillRenew is the state of an auto-renewable subscription
                            // NonRenewable is the state of consumable/non-consumable IAPs that could unlock lifetime access
                        QProductRenewState.BillingIssue ->
                        // Prompt the user to update the payment method.
                        QProductRenewState.Canceled ->
                        // The user has turned off auto-renewal for the subscription, but the subscription has not expired yet.
                        // Prompt the user to resubscribe with a special offer.
                    }
                }
            }

            override fun onError(error: QonversionError) {
                // handle error here
            }
})
try {
  final Map<String, QPermission> permissions = await Qonversion.checkPermissions();
  final main = permissions['main'];
  if (main != null && main.isActive) {
    switch (main.renewState) {
      case QProductRenewState.willRenew:
      case QProductRenewState.nonRenewable:
        // .willRenew is the state of an auto-renewable subscription
        // .nonRenewable is the state of consumable/non-consumable IAPs that could unlock lifetime access
        break;
      case QProductRenewState.billingIssue:
        // Grace period: permission is active, but there was some billing issue.
        // Prompt the user to update the payment method.
        break;
      case QProductRenewState.canceled:
        // The user has turned off auto-renewal for the subscription, but the subscription has not expired yet.
        // Prompt the user to resubscribe with a special offer.
        break;
      default:
        break;
    }
  }
} catch (e) {
  print(e);
}
try {
  const permissions: Map<string, Permission> = await Qonversion.checkPermissions(); } catch (e) {
  console.log(e);
}
Qonversion.CheckPermissions((permissions, error) =>
{
      if (error == null)
      {
         // Handle permissions here
      }
      else
      {
        // Handle the error  
        Debug.Log("Error" + error.ToString());
      }
});

5. Restore purchases

Restoring purchases restores users purchases in your app, to maintain access to purchased content. Users sometimes need to restore purchased content, such as when they upgrade to a new phone.

Call the restore() method to restore purchase:

Qonversion.restore { [weak self] (permissions, error) in
  if let error = error {
    // Handle error
  }
  
  if let permission: Qonversion.Permission = permissions["plus"], permission.isActive {
    // Restored and permission is active 
  }
}
[Qonversion restoreWithCompletion:^(NSDictionary<NSString *,QNPermission *> * _Nonnull result, NSError * _Nullable error) {
  if (error) {
    // Handle error
  }
  QNPermission *permission = result[@"active"];
  if (permission && permission.isActive) {
    // Restored and permission is active
  }
}];
Qonversion.restore(new QonversionPermissionsCallback() {
            @Override
            public void onSuccess(@NotNull Map<String, QPermission> permissions) {
                QPermission premiumPermission = permissions.get("premium");

                if (premiumPermission != null && premiumPermission.isActive()) {
                    // handle active permission here
                }
            }

            @Override
            public void onError(@NotNull QonversionError error) {
                // handle error here
            }
});
Qonversion.restore(object : QonversionPermissionsCallback {
            override fun onSuccess(permissions: Map<String, QPermission>) {
                val premiumPermission = permissions["premium"]
                if (premiumPermission != null && premiumPermission.isActive()) {
                    // handle active permission here
                }
            }

            override fun onError(error: QonversionError) {
                // handle error here
            }
})
try {
  final Map<String, QPermission> permissions = await Qonversion.restore();
} catch (e) {
  print(e);
}
try {
  const permissions: Map<string, Permission> = await Qonversion.restore();
 } catch (e) {
  console.log(e);
}
Qonversion.Restore((permissions, error) =>
{
      if (error == null)
      {
         // Handle permissions here
      }
      else
      {
        // Handle the error  
        Debug.Log("Error" + error.ToString());
      }
});

Did this page help you?