Skip to content

View product list and purchase

Searching product list

Call the Product List Search API when user enters the in-app store. If user requests a product list, return the IAPV4Product class with the product information.

Product list and details

Field Name Description
marketPid Inherent product ID registered at in-app store
currency Currency type (e.g. KRW/USD)
price Product price
title Product title
displayPrice String type of product price (e.g. $100.00) More
productDescription Product details
originalMarketJson the product information received from the market
When using Google subscription V2, the product information defined in Google Play Console can be checked with originalMarketJson
displayOriginalPrice Price string before discount
originalPrice Original price without discount
iconURL Product icon (512*512)
Available with Hive SDK v4.12.0 and later, for Google only

displayPrice

  • Send displayPrice with the combination of currency sign and price in order (e.g. $0.99). As Android or iOS has its own display type, the order of currency sign and price may show up differently in several countries depending on the OS.
  • Make sure to output the currency sign of each country as the same with its table. Refer to the Identifier Policy to confirm the table of currency sign.
  • In case of additional countries to add or change VAT, server calculates VAT of all currency and adds to displayPrice, price, displayOriginalPrice andoriginalPrice. Therefore, you have no more work relevant to VAT.
Note

Google supports to display original price when the value of price and that of originalPrice are different. If the two values are the same, the item is not on sale.
Apple does not provide an iconURL value.
originalPrice and displayOriginalPrice are only for Google (v4 12.0.0 +) and Apple (v4 24.0.0 +). If the price value and originalPrice value are the same, it means that it is not in a discount state. Conversely, if the two values ​​are different, since it is on discount, you can use it to display the discount price and the original price separately.

To search the product list, call getProductInfo() method in the IAPV4 class to receive the product information of the list and Lebi balance.
Followings are sample codes to request a search for product list.

API Reference: hive .IAPV4.getProductInfo

using hive;    
    IAPV4.getProductInfo((ResultAPI result, List<IAPV4Product> productInfoList, int balance) => {    
         if (result.isSuccess()) {    
            // call successful    
        }    
});
#include "HiveIAPV4.h"

FHiveIAPV4::GetProductInfo(FHiveIAPV4OnProductInfoDelegate::CreateLambda([this](const FHiveResultAPI& Result, const TArray<FHiveIAPV4Product>& ProductInfoList, uint32 Balance) {
        if (Result.IsSuccess()) {
                // call successful
        }
}));

API Reference: IAPV4 ::getProductInfo

#include <HIVE_SDK_Plugin/HIVE_CPP.h>    
    using namespace std;    
    using namespace hive;    
    IAPV4::getProductInfo([=](ResultAPI const & result, vector<IAPV4Product> const & productInfoList, unsigned int balance) {    
         if (result.isSuccess()) {    
         // call successful    
         }    
});

API Reference: IAPV4.getProductInfo

import com.hive.IAPV4    
    import com.hive.ResultAPI    
    IAPV4.getProductInfo(object : IAPV4.IAPV4ProductInfoListener {    
         override fun onIAPV4ProductInfo(result: ResultAPI, iapV4ProductList: ArrayList<IAPV4.IAPV4Product>?, balance: Int) {    
             if (result.isSuccess) {    
                 // call successful    
             }    
         }    
})

API Reference: com .hive.IAPV4.getProductInfo

import com.hive.IAPV4    
    import com.hive.ResultAPI    
    IAPV4.INSTANCE.getProductInfo((result, iapV4ProductList, balance) -> {    
         if (result.isSuccess()) {    
             // call successful    
         }    
});

API Reference: IAPV4Interface .getProductInfo

import HIVEService    
    IAPV4Interface.getProductInfo() { result, productInfoList, balance in    
        if result.isSuccess() {    
            // call successful    
        }    
}

API Reference: HIVEIAPV4::getProductInfo

#import <HIVEService/HIVEService-Swift.h>    
    [HIVEIAPV4 getProductInfo: ^(HIVEResultAPI *result, NSArray<HIVEIAPV4Product *> *productInfoList, NSUInteger balance) {    
         if ([result isSuccess]) {    
            // call successful    
         }    
}];
Warning

Failing to call getProductInfo() method enables not to take advantage of the consumable products information when implementing the product list.

It requires the game client to directly implement the responses for returning failure of Result API, such as retry until getting a success callback or expose an error popup (e.g., market unavailable) to the user.

For details of Result API code, see Result API Code - IAP v4.

Note

When using the GOOGLE\_PLAYSTORE market in Windows apps for Google Play (Hive SDK v4 Unity Windows 23.0.0 or higher), the first time IAPV4.getProductInfo is called, a Google account login screen for selecting the account to pay for the products appears to the app user. This login process is not a feature that would be implemented by the app developer; it is automatically performed by the Hive SDK.
If the authentication information of the Google account used for payment expires, the Hive SDK automatically executes the re-authentication process.

Product purchase

Call purchase() method in the IAPV4 class with Market PID, a parameter registered on Apple App Store and Google Play Store, to request product purchase on IAP v4.

Followings are sample codes to request product purchase.

API Reference: hive .IAPV4.purchase

using hive;    
    String marketPid = "{YOUR_PRODUCT_MARKET_PID}";    
    String iapPayload = "{YOUR_CUSTOM_PAYLOAD}"    

    IAPV4.purchase(marketPid, iapPayload, (ResultAPI result, IAPV4Receipt receipt) => {    
    if (result.isSuccess()) {    
             // TODO: Request verification of receipt with received receipt    
         }    
});
#include "HiveIAPV4.h"

FString MarketPid = TEXT("YOUR_PRODUCT_MARKET_PID");
FString IapPayload = TEXT("YOUR_CUSTOM_PAYLOAD");

FHiveIAPV4::Purchase(MarketPid, IapPayload, FHiveIAPV4OnPurchaseDelegate::CreateLambda([this](const FHiveResultAPI& Result, const FHiveIAPV4Receipt& Receipt) {
        if (Result.IsSuccess()) {
                //TODO: Request verification of receipt with received receipt
        }
}));

API Reference: IAPV4 ::purchase

#include <HIVE_SDK_Plugin/HIVE_CPP.h>    
    using namespace std;    
    using namespace hive;    
    string marketPid = "{YOUR_PRODUCT_MARKET_PID}";    
    string iapPayload = "{YOUR_CUSTOM_PAYLOAD}";    
    IAPV4::purchase(marketPid, iapPayload, [=](ResultAPI const & result, IAPV4Receipt const & receipt) {    
         if (result.isSuccess()) {    
             // TODO: Request verification of receipt with received receipt    
         }    
});

API Reference: com.hive.IAPV4.purchase

import com.hive.IAPV4    
    import com.hive.ResultAPI    
    val marketPid = "{YOUR_PRODUCT_MARKET_PID}"    
    val iapPayload = "{YOUR_CUSTOM_PAYLOAD}"    
    IAPV4.purchase(marketPid, iapPayload, object : IAPV4.IAPV4PurchaseListener {    
         override fun onIAPV4Purchase(result: ResultAPI, iapV4Receipt: IAPV4.IAPV4Receipt?) {    
             if (result.isSuccess) {    
                 // call successful    
             }    
         }    
})

API Reference: com .hive.IAPV4.purchase

import com.hive.IAPV4;    
    import com.hive.ResultAPI;    
    String marketPid = "{YOUR_PRODUCT_MARKET_PID}";    
    String iapPayload = "{YOUR_CUSTOM_PAYLOAD}";    
    IAPV4.INSTANCE.purchase(marketPid, iapPayload, (result, iapV4Receipt) -> {    
         if (result.isSuccess()) {    
             // call successful    
         }    
});

API Reference: HIVEIAPV4::purchase:additionalInfo:handler:

import HIVEService    
    let marketPid = "{YOUR_PRODUCT_MARKET_PID}"    
    let iapPayload = "{YOUR_CUSTOM_PAYLOAD}"    

    HIVEIAPV4.purchase(marketPid, iapPayload: iapPayload) { result, receipt in    
         if result.isSuccess() {    
             // TODO: Request verification of receipt with received receipt    
         }    
}

API Reference: HIVEIAPV4::purchase:additionalInfo:handler:

#import <HIVEService/HIVEService-Swift.h>

NSString *marketPid = @"{YOUR_PRODUCT_MARKET_PID}";
NSString *iapPayload = @"{YOUR_CUSTOM_PAYLOAD}";

[HIVEIAPV4 purchase: marketPid iapPayload: iapPayload handler: ^(HIVEResultAPI *result, HIVEIAPV4Receipt *receipt) {
    if ([result isSuccess]) {
        // TODO: Request verification of receipt with received receipt
    }
}];
Note

The supported features may differ by operating system/market. For more details, see the status of supported features.

Use iapPayload

When executing the purchase (purchase()) or subscription (purchaseSubscription) method, game companies can pass iapPayload as an argument. iapPayload is purchase metadata defined by the game company. For example, when a user purchases a product, it may include the purchase time, purchase user information, purchased game character information, purchased quantity (consumable item), purchase token, etc.

If iapPayload is passed as an argument, the IAP server will verify the purchase receipt, matches this iapPayload value to which the purchase receipt it corresponds to and informs the game server. Specifically, the iapPayload value and the hiveiap_transaction_id value corresponding to the unique receipt key are matched and transmitted to the game server.

Utilizing the purchase receipt and iapPayload pair can solve many problems. For example, there may be a situation where an error occurred when a user purchased an item, and the payment was completed but the item was not delivered. At this time, if restore() method is executed, you can get the purchase receipt for that item. But, as this receipt does not contain information about what type of the item, what time the item was purchased, and what character purchased this item, so it is difficult to know exactly which item the game company should restore for the user. However, this information can be known through the iapPayload paired with the purchase receipt, so that the user can be provided with the item.

Note

Utilizing iapPayload, you can analyze user information that abuses the payment system.

iapPayload can be 20KB at maximum (UTF-8).

The supported features may differ by operating system/market. For more details, see the status of supported features.

Warning

When passing iapPayload, it is recommended to encrypt it. Unlike receipts, iapPayload is vulnerable to forgery and tampering.

Set purchase quantity of consumable items

The Google Play Store allows users to purchase two or more of the same in-app products in a single transaction by specifying the quantity in the shopping cart. If your Google Play Console product settings allow multi-quantity purchases, your app should handle multi-quantity purchases and deliver items based on the specified purchase quantity. However, multi-quantity purchases are for consumable in-app products, which are the products that can be purchased again after consumption. Do not enable this feature for the products that cannot be purchased repeatedly.

Note

If you apply multi-quantity purchase for an item, you can check the purchase quantity at the hiveiap_quantity in the receipt verification response.

Precautions before calling purchase() method

  • If RESPONSE_FAIL or CANCELED error is sent while calling purchase() method due to market issues, notify the problems to users that purchase process occurs errors.
  • If users are notified of the purchase problems due to market issues, call restore() method to restore the purchase.
  • If NEED_RESTORE error is sent while calling purchase() method, purchase is cancelled. To restore the purchase, call restore() method.
  • In case the billing system attempts to pay offline or a child asks his or her parents to pay on behalf of him/her while calling purchase() method, ITEM_PENDING error is sent and the item becomes pending state. The proxy purchase of the parents is supported for the Google Play Store, Amazon and Apple App Store market.
  • If succeeded in offline payment or parents' payment instead of their child is made, IAP_UPDATED event is sent through UserEngagement. When the parameter is returned via the UserEngagement eventEnd callback, call restoreSubscription() if the type is "subscription," or call restore() if the type is empty. The completed receipt is available to check by calling these methods.
  • To troubleshoot the NOT_SUPPORTED error which notifies unavailable purchase, refer to the Guide for Phrases to Restrict In-app Purchase.
  • When purchasing through HIVESTORE in a desktop environment, the payment request screen is displayed in a new window.

Calling hive.IAPV4.purchase(marketPid, null, onIAPV4PurchaseCB); will immediately return a response with ErrorCode:IAPSUCCESS=90 and Code:IAPV4HiveStoreSuccess=-6110000 without receipt information, through onIAPV4PurchaseCB. Based on the ErrorCode (or Code), it is possible to display a guidance message about the state of item distribution eligibility.

  • For Windows apps on Google Play (Hive SDK v4 Unity Windows 23.0.0 or higher) using the GOOGLE\_PLAYSTORE market, if the authentication information of the Google account used for payment expires, Hive SDK automatically executes the re-authentication process.
  • For Windows apps on Google Play (Hive SDK v4 Unity Windows 23.0.0 or higher) using the GOOGLE\_PLAYSTORE market, when a user presses the confirm button on the payment waiting popup displayed in the app, and the completion of payment is unconfirmed, a response with ErrorCode:IAPSUCCESS=90 and Code:IAPV4PendingPurchase=-6100013 is returned via onIAPV4PurchaseCB. This response does not indicate a failed payment, but rather that the completion of payment could not be confirmed due to an internal error, or the user just did not make a payment. In this case, no receipt is returned, and if the user has completed the payment in the payment browser window, the receipt can be obtained through IAPV4.restore.

Purchase error codes

Error Code Description
NEED_INITIALIZE Unable to initialize
NETWORK Network error
NOT_SUPPORTED Unable to purchase (In-app purchase denied on device, etc.). User sets unavailable store
INVALID_SESSION Invalid session to purchase
INVALID_PARAM Invalid parameter
IN_PROGRESS Purchase API in progress
ITEM_PENDING Prompt to pay offline or a child requested his or her parents to pay on be half of him/her
CANCELED User cancelled
NEED_RESTORE Need Restore API
RESPONSE_FAIL IAP Server error

Phrases to restrict in-app purchase

Korean 앱 내 구입 기능이 차단이 되어 구매가 불가합니다.
해제 후 다시 시도해 주세요.
(설정 > 스크린 타임 > 콘텐츠 및 개인 정보 보호 제한 > iTunes 및 App Store 구입 > 앱 내 구입)
English You can't make a purchase because the in-app purchase feature has been blocked.
Please unblock the feature and try again.
(Settings > Screen Time > Content & Privacy Restrictions > iTunes & App Store Purchases > In-app Purchases)
French u ne peux pas effectuer l'achat car la fonction d'achat in-app a été bloquée.
Débloque d'abord la fonction et essaie de nouveau.
(Réglages > Temps d’écran > Restrictions relatives au contenu et à la confidentialité > Achats dans l’iTunes et l’App Store > Achats intégrés)
German Kauf nicht möglich, weil das In-App-Kauf-Feature gesperrt ist.
Bitte entsperre es und versuche es erneut.
(Einstellungen > Bildschirmzeit > Beschränkungen > Käufe im iTunes & App Store > In-App-Käufe)
Japanese App内の購入機能が制限されており、購入できません。
解除した後、再度お試しください。
(設定 > スクリーンタイム > コンテンツとプライバシーの制限 > iTunesおよびApp Storeでの購入 > App内課金)
Chinese Simplified 因App内购功能已关闭,无法进行购买。
请开启后再试。
(设置 > 屏幕使用时间 > 内容和隐私访问限制 > iTunes Store 与 App Store 购买项目 > App 内购买项目)
Chinese Traditional 因App內購功能已關閉, 無法進行購買.
請開啟後重新再試
(設定 > 螢幕使用時間 > 內容與隱私權限制 > iTunes 與 App Store 購買 > App 內購買)
Russian Покупка недоступна, т.к. на устройстве отключены встроенные покупки.
Активируйте данную функцию и повторите попытку.
(Настройки > Экранное время > Контент и конфиденциальность > Покупки в iTunes Store и App Store > Встроенные покупки)
Spanish No se puede realizar la compra porque la función de Compras en la app ha sido bloqueada.
Favor de desbloquear la función y volver a intentar.
(Ajustes > Tiempo de uso > Restricciones de contenido y privacidad > Compras en iTunes y App Store > Compras dentro de la app)
Portuguese Você não pode efetuar uma compra porque a função de compra do app foi bloqueada.
Por favor, desbloqueie a função e tente novamente.
(Definições > Tempo de ecrã > Conteúdo e privacidade > Compras na iTunes e App Store > Compras integradas)
Indonesian Pembelian tidak bisa dilakukan karena fitur pembelian In-App telah dibatasi.
Silakan matikan pembatasan dan coba lagi.
(Pengaturan > Durasi Layar > Pembatasan Konten & Privasi > Pembelian iTunes & App Store > Pembelian In-app)
Turkish Uygulama içi satın alma özelliği bloke edildiği için satın almayı yapamazsınız.
Lütfen özelliğin blokajını kaldırıp tekrar deneyiniz.
(Ayarlar > Ekran Süresi > İçerik ve Gizlilik Sınırlamaları > iTunes ve App Store Satın Alımları > Uygulama İçi Satın Alım)
Vietnamese Bạn không thể thực hiện giao dịch do tính năng Mua In-App đang bị tắt.
Vui lòng bật tính năng và thử lại.
(Cài đặt > Thời gian sử dụng > Bật giới hạn > Mua hàng iTunes & App Store > Mua In-app)
Thai คุณไม่สามารถซื้อได้เนื่องจากเมนูการซื้อของในแอพพลิเคชั่นถูกบล็อคอยู่
กรุณาปลดล็อคแล้วลองอีกครั้ง
(การตั้งค่า > เวลาหน้าจอ > จำกัดเนื้อหาและความเป็นส่วนตัว > สินค้าที่ซื้อใน iTunes & App Store > การซื้อภายในแอพ)
Italian Non puoi effettuare l'acquisto perché la funzione di acquisti in-app è bloccata.
Preghiamo di sbloccare la funzione e riprovare. (Impostazioni > Tempo di utilizzo > Contenuti e privacy > Acquisti su iTunes e App Store > Acquisti in-app)
Arabic .لا يمكنك إجراء عملية شراء لأن ميزة الشراء داخل التطبيق قد تم حظرها .الرجاء إلغاء حظر الميزة والمحاولة مرة أخرى (الإعدادات > مدة استخدام الجهاز > قيود المحتوى والخصوصية > الشراء من iTunes Store و App Store > الشراء من داخل التطبيق)

Phrases to notify purchase withdrawal policy

In accordance with the Content Industry Promotion Act, please expose the notices about withdrawal of purchase and a link to your purchase withdrawal policy on your game stores. For iOS, if the notices about purchase withdrawal were exposed during Apple's inspection process on your app, it could be a reason for the rejection of reviewing your game.