Payments Module for Unity

With the now.gg Payments module for Unity, you can implement in-app purchases within your game on Unity.

To implement in-app purchases using the now.gg Payments module:

  1. Download and Import the now.gg Payments Unity Module.
  2. Add required dependencies.
  3. Implement now.gg Payments to your project.

Download and Import the Module

The now.gg Payments Unity module is included as a Unity package file nowgg-payments-login.unitypackage.

Add the module to your Unity project:

  1. Download the package containing the latest version of now.gg Payments module for Unity.
  2. After you have downloaded the module, import it into your Unity project. To do this:
    • Click on Assets > Import Package > Custom Package, as shown below:
    • Select nowgg-payments-login.unitypackage that you previously downloaded.
    • Select all the listed files and click on Import.

Once all the module files have been imported, a folder named ‘NowGGSdk‘ will be added to your project. You can find this folder at the root of the Assets folder.

Note: Please do not modify the NowGGSdk folder, as it contains all the assets related to now.gg Payments.

Add Required Dependencies

This operation will download and add all the required dependencies to the Assets/Plugins/Android directory of your project using the Unity External Dependency Manager.

To add the required dependencies:

  • Click on Assets > External Dependency Manager > Android Resolver > Resolve.

Implement now.gg Payments

Once the now.gg Payments module has been imported, and the dependencies have been added; you can follow this section to implement now.gg Payments with your app/game.

Add Platform check to your Unity IAP implementation

To run the now.gg IAP service, the now.gg platform is required. The Unity IAP (or any other IAP services) should only be initialized when you are not running on the now.gg platform.

To check the platform, you should add the following code to your implementation so that Unity IAP is not activated when your app runs on the now.gg platform:

public void Start()
 {
 	 if (NowGG.Sdk.NowGGPaymentsSdkManager.IsNowGGIapAvailable())
            return;

	 // Your Unity IAP code here...
 }

Implement now.gg IAP in Unity

The following sections illustrate the implementation of the now.gg IAP functions, which you can call from your app/game in Unity.

Start by creating a class that contains the now.gg IAP implementation and attach it to a game object that you can use to initialize the in-app purchases.

1. Add Products and Initialize SDK

This step will allow you to add the in-app purchase products in your app/game and initialize the SDK. For example, we have added two IAP consumable products with productId ‘coin1’ and ‘coin2’ and a subscription with productId ‘monthlyPack’ in the following code.

Similarly, you can add other products and subscriptions with the corresponding productId that you have added within nowStudio.

now.gg Payments module requires a unique userID to identify the user and initiate a transaction. Optionally, the user can choose to save the payment information, so they are not required to enter these details for future transactions in your app.

You must pass the user’s unique userID (IN_GAME_ID) to now.gg Payments module while initializing payments, as illustrated in the following sample code:

public void Start()
  {
	 // Only initialize Now.gg IAP if running on Now.gg platform
	 if (!NowGG.Sdk.NowGGPaymentsSdkManager.IsNowGGIapAvailable())
		 return;

     // for consumable products
	 NowGGProductBuilder.Instance.AddProduct("coin1", ProductType.Consumable);
	 NowGGProductBuilder.Instance.AddProduct("coin2", ProductType.Consumable);

     // for subscriptions
     NowGGProductBuilder.Instance.AddProduct("monthlyPack", ProductType.Subscription);

     NowGGPaymentsSdkManager.Instance.OnInitSuccess += OnInitSuccess;
	 NowGGPaymentsSdkManager.Instance.OnInitFailed += OnInitFailed;
	 NowGGPaymentsSdkManager.Instance.OnPurchaseCompleted += OnPurchaseProduct;
     NowGGPaymentsSdkManager.Instance.OnPurchaseFailed += OnPurchaseFailed;

	 NowGGPaymentsSdkManager.Instance.InitializeIap(PAYMENT_ID, IN_GAME_ID);
 }

Explanation:

  • An initial check is performed to ensure that you are initializing the now.gg Payments service on the now.gg platform.
  • The in-app products and subscriptions are added to the NowGGProductBuilder class.
  • InitializeIap function of the NowGGPaymentsSdkManager Class is called to initialize the Payments module using the PAYMENT_ID.
  • The SDK responses are recorded using the callback functions, as illustrated above.
  • Reference – NowGGPaymentsSdkManager

Important Information:

  • IN_GAME_ID is a unique identifier for your user.
    • Please ensure that your IN_GAME_ID is unique for every user.
      • It’s vital that the IN_GAME_ID is unique because if the user decides to store payment-related information during a purchase, it will be linked to that specific IN_GAME_ID.
      • Testing Payments Integration: If you want to test payments using a specific IN_GAME_ID please add it as an internal tester within nowStudio.
  • PAYMENT_ID is a unique identifier for your app.
    • Each app that you add to nowStudio generates a unique PAYMENT_ID.
    • The corresponding PAYMENT_ID can be found within the App Details section of nowStudio – more information.
  • Refund Processing – The refund process associated with now.gg Payments is illustrated here.

2. Get Product Details

After successful initialization, you can get the product details in your app using the productId.

To get product details, refer to the following implementation:

private void OnInitSuccess()
 {
    Debug.Log($"IAP init success");
    Product coin1 = NowGGPaymentsSdkManager.Instance.GetProductWithID("coin1");

    // now you can get product details using productId
    // consumable
    string price = coin1.price;
    string currencyCode = coin1.priceCurrencyCode;

    // subscription
    Product monthlyPack = NowGGPaymentsSdkManager.Instance.GetProductWithID("monthlyPack");
    string monthlyPackSubscriptionPeriod = monthlyPack.subscriptionPeriod;
 }

 private void OnInitFailed(string reason)
 {
   Debug.Log($"IAP init failed {reason}");
 }

Reference:


3. Initiate purchase

After you have the product details, you can initiate a product purchase. To do so, you have to call the PurchaseProduct() function as illustrated below:

public void PurchaseProduct(string productId, string developerPayload=null)
 {
     NowGGPaymentsSdkManager.Instance.PurchaseProduct(productId, developerPayload);
 }

Reference:

Important Information

  • developerPayload is an optional param.
  • ProductId is a unique identifier for the in-app product(s) and Subscriptionsyou have defined within nowStudio for your specific App (App Id).
  • Product prices are fetched from the price template you created within the nowStudio.

4. Assigning Purchase Entitlement

After a successful purchase, you can assign the purchase entitlement to the user.

The following methods illustrate how to assign purchase entitlement to the user:

1. Consumable Products

We have provided two methods that you can use to consume a purchase:

2. Subscriptions

We have provided two methods that you can use to acknowledge a purchase:


4.1 Using PurchaseProcessingResult

private PurchaseProcessingResult OnPurchaseProduct(PurchasedProduct purchasedProduct)
 {
     string orderId = purchasedProduct.orderId;
     string purchaseToken = purchasedProduct.purchaseToken;
     string developerPayload = purchasedProduct.developerPayload;

     // A consumable product has been purchased by this user.
     if (String.Equals(purchasedProduct.productId, "coin1", StringComparison.Ordinal))
     {
         Debug.Log(string.Format("OnPurchaseProduct: PASS. Product: '{0}'", purchasedProduct.productId));
         // The consumable item has been successfully purchased, add 100 coins to the player's in-game currency.
         // coin += 100;
     }
     else if (String.Equals(purchasedProduct.productId, "coin2", StringComparison.Ordinal))
     {
         Debug.Log(string.Format("OnPurchaseProduct: PASS. Product: '{0}'", purchasedProduct.productId));
         // The consumable item has been successfully purchased, add 200 coins to the player's in-game currency.
         // coin += 200;
     }
     else if (String.Equals(purchasedProduct.productId, "monthlyPack", StringComparison.Ordinal))
     {
         Debug.Log(string.Format("OnPurchaseProduct: PASS. Product: '{0}'", purchasedProduct.productId));
         Debug.Log("Subscription: " + purchasedProduct.subscriptionStatus + " " + purchasedProduct.subscriptionPeriod + " " + purchasedProduct.expiryTimeMillis + " " + purchasedProduct.subscriptionPurchaseDateMillis);
     
         if (purchasedProduct.subscriptionStatus == "ACTIVE" && purchaseProduct.isAcknowledged == false)
         {
            // The subscription has been successfully purchased. Please pass the benefits of the subscription to the player.
            // Update the UI to reflect the status of the purchased subscription, billing period, and expiry.
            // Return PurchaseProcessingResult.Complete to acknowledge that the purchase has been acknowledged (subscriptions)
         }
     }
     else
     {
         Debug.Log(string.Format("OnPurchaseProduct: FAIL. Unrecognized product: '{0}'", purchasedProduct.productId));
     }

     // Return a flag indicating whether this product has been received or if the application needs to be reminded of this purchase at the next app launch.
     // Return PurchaseProcessingResult.Pending if you want to be reminded of this purchase on the next launch of your app/game.
     // Return PurchaseProcessingResult.Complete to acknowledge that the purchase has been consumed (consumable products) or acknowledged (subscriptions)
     // Make sure that you have passed the benefits of the purchase to the user.

     return PurchaseProcessingResult.Complete;
 }

Note:

  • If you wish to process the purchase on your backend server or need to complete the purchase using another method based on your implementation, your app should return PurchaseProcessingResult.Pending from OnPurchaseProduct.
    • If there are any pending purchases, they will be reminded on the next launch of your app/game.
  • To confirm a pending purchase and grant entitlement – Refer to this section.

Reference:

Important Information

  • A purchaseToken is generated after a successful purchase and is a unique identifier.
  • An orderId is also generated for every order.
    • A copy of every purchase with the order id and other relevant information is also emailed to the user.

4.2 Using consumePurchase – For Consumable Products

The consumePurchase API should be used for server-side purchase consumption for apps with a backend server.

After you have verified the purchase, you should mark it as consumed.

Purchase consumption involves:

Assigning the purchased product to the user.

Notifying now.gg that the product has been consumed.

Sample Consume Purchase Code

The following sample code illustrates the associated request using the consumePurchase API.

import requests

  url = "https://cloud-api.bluestacks.cn/v2/order/consumePurchase"

  payload = 'purchaseToken=nowgg-_purchase_token'
  headers = {
    'Authorization': 'payment_api_key_here',
    'Content-Type': 'application/x-www-form-urlencoded'
  }

  response = requests.request("POST", url, headers=headers, data=payload)

  print(response.text)

Reference

Important Information

  • Please ensure to assign the purchased product to the user before calling the consumePurchase API.
  • API Key – The Payments API Key can be found within the credentials section of nowStudio. More information.
  • The purchaseToken is returned after a successful purchase. You can refer to the following reference documents for more information:
  • If the entitlement isn’t granted within 3 days of purchase, the transaction will be cancelled, and a refund will be initiated for the user.

4.3 Using acknowledgePurchase – For Subscriptions

The acknowledgePurchase API should be used for server-side purchase acknowledgement for apps with a backend server.

After you have verified the purchase, you should mark it as acknowledged.

Sample Acknowledge Purchase Code

The following sample code illustrates the associated request using the acknowledgePurchase API.

import requests

  url = "https://cloud-api.bluestacks.cn/v2/seller/order/acknowledgepurchase"

  payload = 'purchaseToken=nowgg-_purchase_token'
  headers = {
    'Authorization': 'payment_api_key_here',
    'Content-Type': 'application/x-www-form-urlencoded'
  }

  response = requests.request("POST", url, headers=headers, data=payload)

  print(response.text)

Reference:

Important Information

  • API Key – The Payments API Key can be found within the credentials section of nowStudio. More information.
  • The purchaseToken is returned after a successful purchase. You can refer to the following reference documents for more information:
  • If the entitlement isn’t granted within 3 days of purchase, the transaction will be cancelled, and a refund will be initiated for the user.

5. Confirm Pending Purchase

If you wish to process the purchase on your backend server or need to complete the purchase using another method based on your implementation, your app should return PurchaseProcessingResult.Pending from OnPurchaseProduct.

Client-side

To complete the purchase flow, you can use the ConfirmPendingPurchase method to inform the now.gg IAP service, the app has made a record of the purchase.

public void ConfirmPendingPurchase(string purchasetoken, ProductType productType) {
   if (productType == ProductType.Consumable) {
       ConsumeProduct(purchasetoken);
   } else {
       AcknowledgePurchase(purchasetoken);
   }
 }

Reference:

Server-Side

To complete the purchase flow and grant the entitlement of a purchase using your app backend server, call the:

Important Information

  • Once the pending purchase is confirmed, the now.gg IAP service will not notify the app about the said purchase.
    • If there are any pending purchases, they will be reminded on the next launch of your app/game.
  • The subscription period commences from the date of acknowledgement.
  • If the entitlement isn’t granted within 3 days of purchase, the transaction will be cancelled, and a refund will be initiated for the user.

6. Query Pending Purchases

If you need to query for pending purchases, you can call the QueryPendingPurchases function of the NowGGPaymentsSdkManager class. This function will query all the pending purchases and call the OnPurchaseProduct callback along with the pending purchases.

NowGGPaymentsSdkManager.Instance.QueryPendingPurchases();

Reference: OnPurchaseProduct.


7. Fetch Additional Products

If you wish to fetch additional products for purchase or refresh the details/metadata associated with the existing products, you can use the FetchAdditionalProducts function as illustrated below.

var newProducts = new System.Collections.Generic.Dictionary<string, ProductType>();
 newProducts.Add("coin2", ProductType.Consumable);
 newProducts.Add("coin3", ProductType.Consumable);

 NowGGPaymentsSdkManager.Instance.FetchAdditionalProducts(newProducts,
       () =>
       {
           //Additional products fetched can now be purchased.
           Debug.Log($"Successfully fetched additional products");
           Product coin1 = NowGGPaymentsSdkManager.Instance.GetProductWithID("coin1");
           string price = coin1.price;
           string currencyCode = coin1.priceCurrencyCode;
       },
      reason =>
      {
          Debug.Log($"Fetching additional products failed: {reason}");
      });

8. Handling Failed Purchases

Purchases may fail due to any number of reasons, including:

  • Network/connectivity issues
  • Payment failure
  • Configuration issues.

You may investigate and handle failed purchases by referring to the following implementation:

public void OnPurchaseFailed(int errorCode, string errorMessage)
 {
    Debug.Log($"OnPurchaseFailed: errorCode: {errorCode} and msg: {errorMessage}");
 }

Note:

  • The response codes related to OnPurchaseFailed function are referenced here.

9. Subscription Status Callback API

(Developer Provided)

This section illustrates the API specs for you to provide us with a SubscriptionStatusCallback API to send subscription status updates.

The following is the associated workflow:

  • nowStudio will use this API to send the request data to your game backend.
  • Your game backend can authenticate the request using the API key provided by us (Webhook API Key).
  • You can assign the purchase entitlement to the user based on the subscription’s current status. (Defined here).
  • After we send the request data using the callback URL you have provided, we will wait for a response from your API.
    • If we do not get a response with status code 200 with success as true, we will keep retrying for some time.

Refer: Subscription Status Callback API section.



Purchase Verification

Verifying the purchase enables you to establish the authenticity of a purchase. The best practice for reducing fraud is to authenticate every purchase before assigning the product to the user.

You can verify the purchases using either of the following two methods:

  • Using Verify Purchase API.
  • Using a Public key.

1. Using VerifyPurchase API

The first method to verify the purchase is using verifyPurchase API. You can use this API to verify the purchases with our backend server.

To verify the purchase, call the verifyPurchase API from your app backend server with purchaseToken, as illustrated in the following sample request code:

curl --location 'https://cloud-api.bluestacks.cn/v2/seller/order/verifyPurchase' \
 --header 'Authorization: <payment_api_key_here>' \
 --header 'Content-Type: application/x-www-form-urlencoded' \
 --data-urlencode 'purchaseToken=<nowgg_purchase_token>'
import requests

  url = "https://cloud-api.bluestacks.cn/v2/seller/order/verifyPurchase"

  payload = 'purchaseToken=<nowgg_purchase_token>'
  headers = {
  'Authorization': '<payment_api_key_here>',
  'Content-Type': 'application/x-www-form-urlencoded'
  }

  response = requests.request("POST", url, headers=headers, data=payload)

  print(response.text)

Important Information

  • The verifyPurchase API must be called from your app backend server.
  • The purchaseToken is returned after a successful purchase. You can refer to the following document for more information:

2. Verify the purchases with your Public Key

You can either verify purchase(s) locally or use a backend server. However, we recommend using your backend server to verify a purchase.

You can generate your public key by following the steps listed here.

The following code segment illustrates the verification of purchase(s) locally and using a backend server. You can refer to the Demo project for more details.

private PurchaseProcessingResult OnPurchaseProduct(PurchasedProduct purchasedProduct) {
    // If you want to do local verification, use this sample code
    bool isValidPurchase = PurchaseVerification.Instance.VerifyPurchaseLocally(
        BASE_64_ENCODED_PUBLIC_KEY,
        purchasedProduct.originalJson,
        purchasedProduct.signature); 

    // We recommend you to verify purchases on your backend server.
    // You need to send signature and original data to your backend server for verification.
    PurchaseVerification.Instance.VerifyValidSignatureOnBackend(
        purchasedProduct.originalJson,
        purchasedProduct.signature);

    // A consumable product has been purchased by this user.
    if (String.Equals(purchasedProduct.productId, "coin1", StringComparison.Ordinal))
    {
        Debug.Log(string.Format("OnPurchaseProduct: PASS. Product: '{0}'", purchasedProduct.productId));
        // The consumable item has been successfully purchased, add 100 coins to the player's in-game currency.
        // coin += 100;
    } 
    else if (String.Equals(purchasedProduct.productId, "coin2", StringComparison.Ordinal)) 
    {
        Debug.Log(string.Format("OnPurchaseProduct: PASS. Product: '{0}'", purchasedProduct.productId));
        // The consumable item has been successfully purchased, add 200 coins to the player's in-game currency.
        // coin += 200;
    } 
    else 
    {
        Debug.Log(string.Format("OnPurchaseProduct: FAIL. Unrecognized product: '{0}'", purchasedProduct.productId));
    }

    return PurchaseProcessingResult.Complete;
}
Server Verification

The download package contains a sample implementation to verify a purchase using a backend server which you can use to write your own implementation.

The sample implementation includes:

  • PurchaseVerification class: Located in the Demo Project, it contains Unity-specific code to send purchase data and signature to the backend server.
  • Server.py: Located separately within the download package, it includes sample Python code to run a local server and perform backend verification.
Local Verification

We have provided a sample implementation within the download package for local verification of purchase. You can use the provided sample to write your own implementation.

In the sample implementation:

  • You can refer to the VerifyPurchaseLocally function of the PurchaseVerification class.

Important Information

×
Text copied to clipboard
Link copied to clipbord
Questions? Please reach out to us at dev-support@now.gg