Payments Module for Native Android

This section explains how to integrate the now.gg Payments module with your development environment.

This document features various code samples based on the official now.gg sample apps and games. You can check the in-line references throughout the document to better understand and implement now.gg Payments module.


Add SDK Libraries

Start by downloading the now.gg SDK package that contains the Payments libraries and add them to your development environment by following the steps below:

Note: The now.gg SDK package contains the Payments module, demo app, and sample code.

1. Extract the compressed now.gg Payments module and locate the .aar file in the package:

 Payments.aar

2. Add the following dependency to the build.gradle file of your game:

dependencies {
         implementation fileTree(dir: 'libs', include: ['*.aar'])
 }


Using the Billing Client

Purchase Lifecycle

The Purchase Lifecycle flow for now.gg Payments is as follows:

  • List the available products that the user can buy.
  • Purchase flow initiation for the user to buy the listed in-app products.
  • Processing the purchase:
    • Purchase verification.
    • Delivery of product/content to the user.
    • Marking purchase as consumed/delivered to allow re-purchase of the product.

Understanding Some Terms

now.gg Payments uses Purchase Tokens and Order IDs to track the products and transactions within your game or App.

Purchase Tokens
  • Purchase Token(s) represent the buyer’s ownership/entitlement of a product.
  • They are associated with a specific product and related product SKU.
  • Purchase Token(s) is only generated after a successful in-app purchase by the user.
  • In the case of a one-time purchase product, a new purchase token is generated for every transaction.
Order IDs
  • An Order ID is a reference to a financial transaction with the now.gg Billing Service.
  • Order IDs are used as references to track purchases, refunds, or any disputes.
  • Unique Order IDs are created for every financial transaction.
Entitlement

The term entitlement or granting of entitlement is used to signify ‘delivery of in-app product’ to the user after a product purchase.

Error Handling
The errors and responses encountered within your app/game are categorized using Billing Response codes.
Example: A SERVICE_DISCONNECTED error code suggests the connection between the now.gg Payments service, and your game is disconnected. The solution to this is to reinitialize your app/game to re-establish the connection with now.gg payments service.

1. Create and Initialize BillingClient

The BillingClient interface acts as the primary communication mechanism between the now.gg Payments module and your app/game. It is responsible for providing both synchronous and asynchronous methods for general billing operations.

BillingClient Creation                            --> Use newBuilder()

 Setup Updates of Purchase                         --> Call setListener()
 
 Receive updates throughout app/game               --> PurchasesUpdatedListener

 Set PAYMENT_ID for billing                        --> use setAppId(PAYMENT_ID)

 Set IN_GAME_ID to use existing in-game user ID    --> use setInGameId(IN_GAME_ID)

 Query unconsumed purchases after initialization   --> use queryPurchasesAsync()
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 creating and initializing the BillingClient, as illustrated in the following sample code:

private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
    @Override
    public void onPurchasesUpdated(int billingResult, List<Purchase> purchases) {
         if (billingResult == BillingResponse.OK) {
             if (purchases == null) {
                 return;
             }
             for (Purchase purchase: purchases) {
                 String payload = purchase.getDeveloperPayload(); // get developer payload
                 // handle successful purchase here
             }
         } else if (billingResult == BillingResponse.USER_CANCELED) {
            Log.i(TAG, "onPurchasesUpdated() - user cancelled the purchase flow - skipping");
         } else {
            Log.w(TAG, "onPurchasesUpdated() got unknown billingResult: " + billingResult);
         }
    }
 };

 private BillingClient billingClient = BillingClient.newBuilder(activity)
    .setListener(purchasesUpdatedListener)
    .setAppId(PAYMENT_ID)
    .setInGameId(IN_GAME_ID) // unique ID to identify the user.
    .build();
private val purchasesUpdatedListener = object : PurchasesUpdatedListener {
    override fun onPurchasesUpdated(billingResult: Int, purchases: List<Purchase>?) {
        if (billingResult == BillingResponse.OK) {
            if (purchases == null) {
                return
            }
            for (purchase in purchases) {
                val payload = purchase.developerPayload // get developer payload
                // handle successful purchase here
            }
        } else if (billingResult == BillingResponse.USER_CANCELED) {
            Log.i(TAG, "onPurchasesUpdated() - user cancelled the purchase flow - skipping")
        } else {
            Log.w(TAG, "onPurchasesUpdated() got unknown billingResult: $billingResult")
        }
    }
}

private val billingClient = BillingClient.newBuilder(activity)
    .setListener(purchasesUpdatedListener)
    .setAppId(PAYMENT_ID)
    .setInGameId(IN_GAME_ID) // unique ID to identify the user.
    .build()

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.
    • The corresponding PAYMENT_ID can be found within the App Details section of nowStudio – more information.
    • The PAYMENT_ID will be available only after you have added your app/game to nowStudio.
  • Refund Processing– The refund process associated with now.gg Payments is illustrated here.
References

2. Establish Connection

now.gg Payments service has an asynchronous connection process and requires you to implement a BillingClientStateListener to capture callback on completion of client setup.

  • To establish a connection with now.gg Payments Service, you need to call startConnection().
  • To handle lost connections, you need to define a retry logic. The retry logic implementation will require you to override the callback method. onBillingServiceDisconnected().
  • While overriding the callback method onBillingServiceDisconnected(), ensure that your BillingClient is calling the startConnection() method to re-establish connection with now.gg Payments Service.
  • Maintain the connection with the BillingClient before executing any methods.
  • Query Unconsumed Purchases: You must query for unconsumed purchases using queryPurchasesAsync() method after initialization to ensure that any unconsumed purchases from the user’s previous game session are properly allotted to the user.
    • This is especially useful in case of an app crash event just after a purchase or a loss of internet connection during the purchase process.

Note: You may choose to write your own retry logic. However, we have also provided a retry logic that you may choose to implement.

Example

billingClient.startConnection(new BillingClientStateListener() {
   @Override
   public void onBillingSetupFinished(int billingResult) {
     if (billingResult == 0) {
       // The BillingClient is ready. You can query purchases here. 
       QueryPurchasesParams params = QueryPurchasesParams.newBuilder().setProductType(BillingClient.SkuType.ALL).build();
       billingClient.queryPurchasesAsync(params, new PurchasesResponseListener() {
         @Override
         public void onQueryPurchasesResponse(BillingResult billingResult, List < Purchase > list) {
         // Allot the purchased item to the user and call consume/acknowledge.
         }
       });
     }
   }
   @Override
   public void onBillingServiceDisconnected() {
     // Try to restart the connection on the next request to 
     // Payments module by calling the startConnection() method. 
   }
 });
billingClient.startConnection(object : BillingClientStateListener {
     override fun onBillingSetupFinished(billingResult: Int) {
         if (billingResult == 0) {
             // The BillingClient is ready. You can query purchases here. 
             val params = QueryPurchasesParams.newBuilder().setProductType(BillingClient.SkuType.ALL).build()
             billingClient.queryPurchasesAsync(params, object : PurchasesResponseListener {
                 override fun onQueryPurchasesResponse(billingResult: BillingResult, list: List< Purchase >) {
                     // Allot the purchased item to the user and call consume/acknowledge.
                 }
             })
         }
     }

     override fun onBillingServiceDisconnected() {
         // Try to restart the connection on the next request to 
         // Payments module by calling the startConnection() method. 
     }
 })
References


Products and Purchases

This section walks you through the process of querying and listing the available in-app products in your app/game and handling the purchases.

The steps for this flow are:

  1. List Available Products.
  2. Purchase Flow Initiation.
  3. Processing the Purchases.

Before you begin, check that you have:

1. List Available Products

The first step here is to query for available products and list them to your users. To perform a query for in-app product details, you need to call querySkuDetailsAsync(). When you query for SKU details, the now.gg Payments module will return localized product information to be displayed to your users.

Note: Before displaying the in-app products to the user, you should query the SKU details, as it returns updated and relevant product information.

SKU Types and Order Strings

Below are the SKUType associated with now.gg Payments:

  • SkuType.SUBS – Subscriptions
  • SkuType.INAPP – in-app purchases
  • SkuType.ALL – All Skus

While you call querySkuDetailsAsync(), remember to pass an instance of SkuDetailsParams, which specifies the SKUType along with the product ID that you configured in the nowStudio.

Results

After querying for available products, you must assign a listener to capture the results of the Asynchronous operation you passed.

The following example will showcase the implementation of a SkuDetailsResponseListener interface and will allow you to override the onSkuDetailsResponse(), to notify the listener when the query is finished.

List < String > skuList = new ArrayList < > ();
 skuList.add("premium_upgrade");
 skuList.add("gas");
 SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
 params.setSkusList(skuList).setType(SkuType.ALL);
 billingClient.querySkuDetailsAsync(params.build(),
   new SkuDetailsResponseListener() {
     @Override
     public void onSkuDetailsResponse(int billingResult,
       List < SkuDetails > skuDetailsList) {
       // Process the result.
     }
   });
val skuList = mutableListOf<String>()
 skuList.add("premium_upgrade")
 skuList.add("gas")
 val params = SkuDetailsParams.newBuilder()
     .setSkusList(skuList)
     .setType(SkuType.ALL)
 billingClient.querySkuDetailsAsync(params.build(),
     object : SkuDetailsResponseListener {
         override fun onSkuDetailsResponse(billingResult: Int, skuDetailsList: List<SkuDetails>) {
             // Process the result.
         }
     })

More Information

  • A user can re-purchase a consumable item only after the first purchase order has been completed and the product is delivered to the user.
  • The SkuDetails object can be called using various methods to list information about the in-app products.
  • now.gg Payments module stores all the query results in a list of SkuDetails object.
References

2. Purchase Flow Initiation

After you have listed the available products for the user to buy, you must initiate the purchase flow from the app/game.

To start the purchase flow, you will need to call the launchBillingFlow() method from the App’s main thread.

Here, the BillingFlowParams object is called for a reference, as it contains relevant details stored within the SkuDetails object. The SkuDetails object is obtained by calling querySkuDetailsAsync().

Creating the BillingFlowParams object

To start the purchase flow, you need to create the BillingFlowParams object using the BillingFlowParams.Builder class. Use the following code snippets as reference:

// An activity reference for billing flow initiation 
 Activity activity = ...; 
      
 // Call querySkuDetailsAsync() to retrieve a value for 'skuDetails'. 
 BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() 
    .setSkuDetails(skuDetails) 
    .setDeveloperPayload("optional developer payload")
    .build(); 
 billingClient.launchBillingFlow(activity, billingFlowParams); 
      
     //Result
// An activity reference for billing flow initiation 
 val activity : Activity = ...; 
  
 // Call querySkuDetailsAsync() to retrive a value for 'skuDetails'. 
 val flowParams = BillingFlowParams.newBuilder() 
         .setSkuDetails(skuDetails) 
         .setDeveloperPayload("optional developer payload")
         .build() 
 billingClient.launchBillingFlow(activity, flowParams)
 //Result
References:

Result Assessment

You can use BillingClient.BillingResponse as a reference for the return response codes.

  • A response code OK (0) indicates a successful launch.
  • A Purchase Screen is displayed by the system after a successful call to launchBillingFlow().
  • now.gg Payments module calls onPurchasesUpdated() to communicate the purchase result to a listener that implements the PurchasesUpdatedListener interface.
  • This listener is specified while you initialize the billing client using the setListener() method.

The following example outlines the process to override the onPurchasesUpdated() method:

@Override 
 void onPurchasesUpdated(int billingResult, List<Purchase> purchases) { 
     if (billingResult == 0 && purchases != null) { 
         for (Purchase purchase : purchases) { 
             String payload = purchase.getDeveloperPayload(); // Get Developer Payload
             handlePurchase(purchase); 
         } 
     } else if (billingResult == 1) { 
             // Error Handling - Caused due to user terminating the purchase flow 
     } else { 
             // Error Handling - Any other causes (based on error code) 
     } 
 }
override fun onPurchasesUpdated(billingResult: int, purchases: List<Purchase>?) { 
     if (billingResult == 0 && purchases != null) { 
         for (purchase in purchases) { 
                 val payload: String = purchase.developerPayload // Get Developer Payload
                 handlePurchase(purchase)
         } 
     } else if (billingResult == 1) { 
             // Error Handling - Caused due to the user terminating the purchase flow. 
     } else { 
             // Error Handling - Any other causes (based on error code) 
     } 
 }

Note: The onPurchasesUpdated() method should be implemented to handle possible response codes.

More Information

  • A Purchase Token is generated after a successful purchase.
    • The purchase token is also a Unique Identifier representing the in-app purchased product and the corresponding user who made the purchase.
  • An order ID is generated for every subsequent order and can be used for any disputes or refund references with the now.gg Payments Service.
  • A copy of every purchase with the order id and other relevant information is also emailed to the user.
References:

3. Processing the Purchases

This section focuses on processing the purchases. After you have started the purchase flow, you are required to process the purchases in the following manner:

  1. Purchase Verification
  2. Granting Entitlement
  3. Purchase Results
  4. Get Unconsumed Purchases and Subscriptions

3.1 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.
3.1.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 reference documents for more information:

3.1.2 Using Your Public Key

The second method to verify the purchase is using a public key. An implementation for verifying purchases using the public key has been illustrated in the demo’s billingManager.java.

  • Open billingManager.java
  • Locate the verifyValidSignature function and then locate verifyPurchase.

By referring to the implementation using the above-mentioned functions in our demo’s billingManager.java, you can implement the purchase verification in your App.

Note:

  • You can generate your public key by following the steps listed here.
  • If your app has a backend server, we recommend that you validate the purchase on your backend server.
  • It is recommended to authenticate every purchase before granting the entitlement of the product to the user.

3.2 Granting Entitlement

After you have verified the purchase, your App can grant the entitlement of the purchased product to the user and mark the product as consumed (consumable products) or Acknowledged (Subscriptions)
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:


3.2.1 Consumable Products

We have provided two methods to consume a purchase:

A. Client Side – Using consumeAsync
The following flow is used to consume the purchase items on client-side.

Note: If your app is client-only without a backend server, you should use this method.

To grant the entitlement:

  • Call the consumeAsync() method.
    • This method will grant the entitlement of a product to the user and make the product available for re-purchase once it has been consumed.
  • Include the purchase token with consumeAsync() to update the status of the purchased product to Consumed, allowing the now.gg billing service to make it available for re-purchase.
  • To update the result of the consumption operation, you should pass an object that implements the ConsumeResponseListener interface.
  • When the consumption operation is complete, now.gg Billing Service calls onConsumeResponse(), which you can override.

Important Information:

  • You should keep a check on multiple entitlement grants for the same purchase using purchase tokens.
  • This may occur if the consumption request fails and the object that updates the ConsumeResponseListener interface is not updated.
  • 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.

The following code snippet demonstrates purchase verification and consume operation:

void handlePurchase(Purchase purchase) {
    // Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
    Purchase purchase = ...;

    // Verify the purchase.
    // Ensure entitlement was not already granted for this purchaseToken.
    // Grant the entitlement to the user.

    // Consume Purchase
    ConsumeResponseListener listener = new ConsumeResponseListener() {
        @Override
        public void onConsumeResponse(int billingResult, String purchaseToken) {
            if (billingResult == 0) {
                // Handle the success of the consume operation.
            }
        }
    };

    billingClient.consumeAsync(purchase.getPurchaseToken(), listener);
}
fun handlePurchase(purchase: Purchase) {
    // Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
    val purchase: Purchase = ...;

    // Verify the purchase.
    // Ensure entitlement was not already granted for this purchaseToken.
    // Grant the entitlement to the user.

    // Consume Purchase
    billingClient.consumeAsync(purchase.getPurchaseToken(), {
        billingResult,
        outToken - >
        if (billingResult == 0) {
            // Handle the success of the consume operation.
        }
    })
}
References:

B. Server side – Using consumePurchase API – 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 Payment 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:


3.2.2 Subscriptions

Important Information

  • Acknowledging the subscription purchase is an essential step because it grants the purchase entitlement to the user.
  • The subscription period commences from the date of acknowledgement.
  • If the purchase is not acknowledged within 3 days from the date of purchase, it will be cancelled, and a refund will be initiated for the user.

We have provided two methods for subscription acknowledgement:

A. Client Side – Using acknowledgePurchase
The following flow is used to acknowledge the purchase items on client-side.

Note: If your app is client-only without a backend server, you should use this method.

To grant the entitlement:

  • Call theacknowledgePurchase() method.
    • This method will grant the entitlement of a product to the user and make the product available for re-purchase once it has been acknowledged.
  • Include the purchase token with acknowledgePurchase() to update the status of the purchased product to acknowledged, allowing the now.gg billing service to make it available for re-purchase.
  • To update the result of the acknowledgement operation, you should pass an object that implements the AcknowledgePurchaseResponseListener interface.
  • When the acknowledgement operation is complete, now.gg Billing Service calls onAcknowledgePurchaseResponse(), which you can override.

Important Information:

  • You should keep a check on multiple entitlement grants for the same purchase using purchase tokens.
    • This may occur if the acknowledgment request fails and the object that updates the AcknowledgePurchaseResponseListener interface is not updated.

The following code snippet demonstrates purchase verification and acknowledge operation:

void handlePurchase(Purchase purchase) {
    // Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
    Purchase purchase = ...;

    // Verify the purchase.
    // Ensure entitlement was not already granted for this purchaseToken.
    // Grant the entitlement to the user.
   
    // Acknowledge Subscription
    final AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = new AcknowledgePurchaseResponseListener() {
          @Override
          public void onAcknowledgePurchaseResponse(@BillingResponse int responseCode) {
              if (responseCode == 0) {
                       // Handle the success of the acknowledgement operation.
                   }

          }
    };


   AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
          .setPurchaseToken(purchaseToken)
          .build();
   BillingClient.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
}
fun handlePurchase(purchase: Purchase) {
    // Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
    val purchase: Purchase = ...;

    // Verify the purchase.
    // Ensure entitlement was not already granted for this purchaseToken.
    // Grant the entitlement to the user.

   // Acknowledge Subscription 
   val acknowledgePurchaseResponseListener = object : AcknowledgePurchaseResponseListener {
    override fun onAcknowledgePurchaseResponse(@BillingResponse responseCode: Int) {
        if (responseCode == 0) {
            // Handle the success of the acknowledgement operation.
        }
    }


   val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
       .setPurchaseToken(purchaseToken)
       .build()
   BillingClient.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener)
}
References:

B. Server side – Using acknowledgePurchase API

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 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 Payment 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:


3.3 Purchase Results

The PurchasesUpdatedListener provides you with the purchase results. However, in some scenarios, your app/game might not be updated with all the successful purchases a user has made.

Some of these scenarios include:

  • Multiple devices
    In this scenario, the user purchased an item on one device and wants to use it on another device where the purchased product is not updated.
  • Connectivity/Network loss
    The app/game may fail to receive a successful purchase notification from PurchasesUpdatedListener, due to connectivity/network loss.
  • Purchases made outside the App
    In this scenario, the purchases made outside your app/game need to be handled for the user to be able to use them.

To successfully process purchases related to the scenarios listed above:

  • In your onResume() and onCreate() methods, make sure that your app calls BillingClient.queryPurchasesAsync(SkuType.ALL).

4. Handling Unconsumed Purchases

The following section illustrates the process of checking and alloting unconsumed in-app purchases and subscriptions.

You can use the queryPurchasesAsync method to return the list of unconsumed purchases for a user, as illustrated below:

QueryPurchasesParams params = QueryPurchasesParams.newBuilder().setProductType(BillingClient.SkuType.ALL).build();
 billingClient.queryPurchasesAsync(params, new PurchasesResponseListener() {
   @Override
   public void onQueryPurchasesResponse(BillingResult billingResult, List < Purchase > list) {
        // Allot the purchased item to the user and call consume/acknowledge
   }
 });
val params = QueryPurchasesParams.newBuilder()
    .setProductType(BillingClient.SkuType.ALL)
    .build()

billingClient.queryPurchasesAsync(params, object : PurchasesResponseListener {
    override fun onQueryPurchasesResponse(billingResult: BillingResult, list: List) {
       // Allot the purchased item to the user and call consume/acknowledge
    }
})

Important Information

  • You must query for unconsumed purchases using queryPurchasesAsync() method after initialization to ensure that any unconsumed purchases from the user’s previous game session are properly allotted to the user.
    • This is especially useful in case of an app crash event just after a purchase or a loss of internet connection during the purchase process.
  • For more information, please refer to the Establish Connection section.

5. 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.


Important Information

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