Ungiven Item Receipts
Sending items is occasionally failed or cancelled after purchase. To prevent this situation, request receipt information of items not given by calling restore()
method of IAPV4 class.
- If
SUCCESS
is returned and ReceiptList is sent after callingrestore()
, items needed restore exist. Send the ungiven items and complete the restore process. - If
SUCCESS
is not returned after callingrestore()
, no more process is required for game studio. - If calling
restore()
method occurs errors, notify only some errors required to recognize and skip others for user to keep playing your game. - When using the
GOOGLE_PLAYSTORE
market in Windows apps for Google Play (Hive SDK v4 Unity Windows 23.0.0 or higher), if the authentication information for the Google account used for payments expires at the time of calling therestore()
method, the Hive SDK automatically initiates the re-authentication process.
Followings are sample codes to request receipt information of items not given.
API Reference: hive .IAPV4.restore
1 2 3 4 5 6 7 8 9 10 11 |
using hive; IAPV4.restore((ResultAPI result, List receiptList) => { if (result.isSuccess()) { if (result.errorCode = ResultAPI.ErrorCode.SUCCESS) { // TODO: Request receipt verification using the received receiptList } else if (result.errorCode = ResultAPI.ErrorCode.NOT_OWNED) { // No unpaid items } } } |
API Reference: IAPV4 ::restore
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <HIVE_SDK_Plugin/HIVE_CPP.h> using namespace std; using namespace hive; IAPV4::restore([=](ResultAPI const & result, vector<reference_wrapper<IAPV4Receipt>> receiptList) { if (result.isSuccess()) { if (result.errorCode == ResultAPI::ErrorCode::SUCCESS) { // TODO: Request receipt verification using the received receiptList } else if (result.errorCode == ResultAPI::ErrorCode::RESTORE_NOT_OWNED) { // No unpaid items } } }); |
API Reference: IAPV4.restore
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import com.hive.IAPV4 import com.hive.ResultAPI IAPV4.restore(object : IAPV4.IAPV4RestoreListener { override fun onIAPV4Restore(result: ResultAPI, iapv4ReceiptList: ArrayList<IAPV4.IAPV4Receipt>?) { if (result.isSuccess) { if (result.errorCode == ResultAPI.SUCCESS) { // TODO: Request receipt verification using the received iapv4ReceiptList } else if (result.errorCode == ResultAPI.RESTORE_NOT_OWNED) { // No unpaid items } } } }) |
API Reference: com.hive.IAPV4.restore
1 2 3 4 5 6 7 8 9 10 11 12 |
import com.hive.IAPV4; import com.hive.ResultAPI; IAPV4.INSTANCE.restore((result, iapv4ReceiptList) -> { if (result.isSuccess()) { if (result.getErrorCode() == ResultAPI.Companion.getSUCCESS()) { // TODO: Request receipt verification using the received iapv4ReceiptList } else if (result.getErrorCode() == ResultAPI.Companion.getRESTORE_NOT_OWNED()) { // No unpaid items } } }); |
API Reference: IAPV4Interface .restore
1 2 3 4 5 6 7 8 9 10 11 |
import HIVEService IAPV4Interface.restore() { result, receiptList in if result.isSuccess() { if result.getErrorCode() == .success { // TODO: Request receipt verification using the received receiptList } else if result.getErrorCode() == .notOwned { // No unpaid items } } } |
API Reference: HIVEIAPV4::restore
1 2 3 4 5 6 7 8 9 10 11 |
#import <HIVEService/HIVEService-Swift.h> [HIVEIAPV4 restore: ^(HIVEResultAPI *result, NSArray<HIVEIAPV4Receipt *> *receiptList) { if ([result isSuccess]) { if ([result getErrorCode] == HIVEResultAPITypeSuccess) { // TODO: Request receipt verification using the received receiptList } else if ([result getErrorCode] == HIVEResultAPITypeNotOwned){ // No unpaid items } } }]; |
List of Purchase-restoring Error Codes
Error Code | Description |
NEED_INITIALIZE | Unable to initialize |
NETWORK | Network error |
NOT_SUPPORTED | Unable to restore (In-app purchase denied on device, etc.). User sets unavailable store |
INVALID_SESSION | Invalid session to restore |
IN_PROGRESS | Restore API in progress |
RESTORE_NOT_OWNED | No item to restore |
NOT_OWNED | No item to restore |
RESPONSE_FAIL | Hive IAP Server error |
Verifying Purchase Receipt
Before sending items from game server, verification API from Hive IAP should confirm whether the receipt is valid.
hiveiap_transaction_id
in verification API is a unique ID issued by receipt. Thus, save the ID on game server to check duplicated receipts.
If you use verification API and then send all data from Request parameter, Hive IAP Server forwards game data to analyze sales status. Just utilize APIs to search payment on Hive One > Search All as well.
For more details, refer to Hive IAP Receipt Verification API.
Completion to Give Purchased or Ungiven Items
If the game server sends items after purchase, make sure to call transactionFinish()
method of IAPV4 class to complete the purchase.
Followings are sample codes which complete a request for item sending.
API Reference: hive .IAPV4.transactionFinish
1 2 3 4 5 6 7 8 9 |
using hive; String marketPid = "{YOUR_PRODUCT_MARKET_PID}"; IAPV4.transactionFinish(marketPid, (ResultAPI result, String marketPid) => { if (result.isSuccess()) { // call successful } }); |
API Reference: IAPV4 ::transactionFinish
1 2 3 4 5 6 7 8 9 10 11 |
#include <HIVE_SDK_Plugin/HIVE_CPP.h> using namespace std; using namespace hive; string marketPid = "{YOUR_PRODUCT_MARKET_PID}"; IAPV4::transactionFinish(marketPid, [=](ResultAPI const & result, string marketPid) { if (result.isSuccess()) { // call successful } }); |
API Reference: IAPV4.transactionFinish
1 2 3 4 5 6 7 8 9 10 11 12 |
import com.hive.IAPV4 import com.hive.ResultAPI val marketPid = "{YOUR_PRODUCT_MARKET_PID}" IAPV4.transactionFinish(marketPid, object : IAPV4.IAPV4TransactionFinishListener { override fun onIAPV4TransactionFinish(result: ResultAPI, marketPid: String) { if (result.isSuccess) { // call successful } } }) |
API Reference: com.hive.IAPV4.transactionFinish
1 2 3 4 5 6 7 8 9 10 |
import com.hive.IAPV4; import com.hive.ResultAPI; String pid = "{YOUR_PRODUCT_MARKET_PID}"; IAPV4.INSTANCE.transactionFinish(pid, (result, marketPid) -> { if (result.isSuccess()) { // call successful } }); |
API Reference: IAPV4Interface.transactionFinish
1 2 3 4 5 6 7 8 9 |
import HIVEService let marketPid = "{YOUR_PRODUCT_MARKET_PID}" IAPV4Interface.transactionFinish() { result, marketPid in if result.isSuccess() { // call successful } } |
API Reference: HIVEIAPV4::transactionFinish:handler:
1 2 3 4 5 6 7 8 9 |
#import <HIVEService/HIVEService-Swift.h> NSString *marketPid = @"{YOUR_PRODUCT_MARKET_PID}"; [HIVEIAPV4 transactionFinish: marketPid handler: ^(HIVEResultAPI *result, NSString *marketPid) { if ([result isSuccess]) { // call successful } }]; |
Followings are sample codes to request to send several items.
API Reference: hive .IAPV4.transactionMultiFinish
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
using hive; List marketPidList = new List(); marketPidList.Add("{YOUR_PRODUCT_MARKET_PID_01}"); marketPidList.Add("{YOUR_PRODUCT_MARKET_PID_02}"); marketPidList.Add("{YOUR_PRODUCT_MARKET_PID_03}"); IAPV4.transactionMultiFinish((List<ResultAPI> resultList, List<String> marketPidList) => { for (ResultAPI result in resultList) { if (result.isSuccess()) { // call successful } } }); |
API Reference: IAPV4 ::transactionMultiFinish
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <HIVE_SDK_Plugin/HIVE_CPP.h> using namespace std; using namespace hive; vector<string> marketPidList; marketPidList.push_back("{YOUR_PRODUCT_MARKET_PID_01}"); marketPidList.push_back("{YOUR_PRODUCT_MARKET_PID_02}"); marketPidList.push_back("{YOUR_PRODUCT_MARKET_PID_03}"); IAPV4::transactionMultiFinish(marketPidList, [=](vector<ResultAPI> const & resultList, vector<string> const & marketPidList) { for (ResultAPI result : resultList) { if (result.isSuccess()) { // call successful } } }); |
API Reference: IAPV4.transactionMultiFinish
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import com.hive.IAPV4 import com.hive.ResultAPI val marketPidList = arrayListOf( "{YOUR_PRODUCT_MARKET_PID_01}", "{YOUR_PRODUCT_MARKET_PID_02}", "{YOUR_PRODUCT_MARKET_PID_03}" ) IAPV4.transactionMultiFinish(marketPidList, object : IAPV4.IAPV4TransactionMultiFinishListener { override fun onIAPV4TransactionMultiFinish(resultList: ArrayList<ResultAPI>, marketPidList: ArrayList<String>) { for (i in 0 until resultList.size) { if (resultList[i].isSuccess) { // call successful } } } }) |
API Reference: com.hive.IAPV4.transactionMultiFinish
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import com.hive.IAPV4; import com.hive.ResultAPI; ArrayList<String> marketPidList = new ArrayList<>(Arrays.asList( "{YOUR_PRODUCT_MARKET_PID_01}", "{YOUR_PRODUCT_MARKET_PID_02}", "{YOUR_PRODUCT_MARKET_PID_03}" )); IAPV4.INSTANCE.transactionMultiFinish(marketPidList, (resultList, marketPidList1) -> { for (ResultAPI result : resultList) { if (result.isSuccess()) { // call successful } } }); |
API Reference: IAPV4Interface.transactionMultiFinish
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import HIVEService var marketPidList = [String]() marketPidList.append("{YOUR_PRODUCT_MARKET_PID_01}") marketPidList.append("{YOUR_PRODUCT_MARKET_PID_02}") marketPidList.append("{YOUR_PRODUCT_MARKET_PID_03}") IAPV4Interface.transactionMultiFinish(marketPidList) { resultList, marketPidList in for result in resultList { if result.isSuccess() { // call successful } } } |
API Reference: HIVEIAPV4::transactionMultiFinish
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#import <HIVEService/HIVEService-Swift.h> NSMutableArray<NSString *> *maketPidList = [NSMutableArray array]; [maketPidList addObject:@"{YOUR_PRODUCT_MARKET_PID_01}"]; [maketPidList addObject:@"{YOUR_PRODUCT_MARKET_PID_02}"]; [maketPidList addObject:@"{YOUR_PRODUCT_MARKET_PID_03}"]; [HIVEIAPV4 transactionMultiFinish: maketPidList handler: ^(NSArray<HIVEResultAPI *> *resultList, NSArray<NSString *> *marketPidList) { for (HIVEResultAPI *result in resultList) { if ([result isSuccess]) { // call successful } } }]; |
Get user purchase activity information: using AccountUuid
There may be users who abuse the payment system, such as a single game account using multiple app store accounts to make payments. On the game studio side, you can obtain and analyze specific user behavior by comparing payment user information (AccountUuid).
The method below returns AccountUuid
, which is the hash value of PlayerId in UUID v3 format that Hive SDK passes to the app store.
API Reference: IAPV4.getAccountUuid
1 2 3 |
using hive; String accountUuid = IAPV4.getAccountUuid(); |
API Reference: IAPV4 ::getAccountUuid
1 2 3 4 5 |
#include <HIVE_SDK_Plugin/HIVE_CPP.h> using namespace std; using namespace hive; string accountUuid = IAPV4::getAccountUuid(); |
API Reference: IAPV4.getAccountUuid
1 2 3 |
import com.hive.IAPV4 val accountUuid = IAPV4.getAccountUuid() |
API Reference: IAPV4.INSTANCE .getAccountUuid
1 2 3 |
import com.hive.IAPV4; String accountUuid = IAPV4.INSTANCE.getAccountUuid(); |
API Reference: IAPV4Interface.getAccountUuid
1 2 3 |
import HIVEService let accountUuid = IAPV4Interface.getAccountUuid() |
API Reference: [HIVEIAPV4 getAccountUuid ]
1 2 3 |
#import <HIVEService/HIVEService-Swift.h> NSString *accountUuid = [HIVEIAPV4 getAccountUuid]; |
The game studio can use this hash value with the purchase receipt information to analyze a user’s purchases. The example below shows analyzing the purchase activity of a game account with a specific PlayerId via AccountUuid
when there are multiple in-game characters in this game account. This example is only for development reference and does not guarantee the actual operation.
Store Purchase Meta Info in Game Server In Advance
Before a request to purchase occurs, save the purchase meta information (AccountUuid
and character information) to the game server.
1 2 3 4 5 6 7 8 9 10 |
/* The game client pass the info to the game server before the purchase occurs. * * @param purchaseTime: purchase time. The receipts are usually based on UTC. since the epoch (Jan 1, 1970). * @param productId: purchase product ID. * @param accountUuId: hashed PlayerId. It is included in the receipt and can be obtained with IAPV4.getAccountUuid(). * @param characterId: the character identifier within PlayerId. */ game.sendPurchaseGameData(purchaseTime, productId, accountUuid, characterId) |
Send bypassInfo
When a purchase request occurs, send the bypassInfo
data to the game server. The code below is pseudo code for development reference.
1 2 3 4 5 |
IAPV4.purchaseproductId) { iapv4Receipt -> game.sendReceipt(iapv4Receipt.purchase_bypass_info) } |
Request for Receipt Verification
The game server passes the bypassInfo
data to the Hive IAP v4 server and requests validating the receipt. For details of requesting receipt verification, see here.
The AccountUuid
included in the hiveiap_receipt
, which is the original receipt of app market/store received within the response value.
1 2 3 4 5 6 |
# Apple # Purchase time: purchase_date_ms # Purchased products: product_id # AccountUuid: app_account_token |
1 2 3 4 5 6 |
# Google # Purchase time: purchaseTime # Purchased products: productId # AccountUuid: obfuscatedAccountId |
Analyze by matching AccountUuid
of the purchase meta information with AccountUuid
of the hiveiap_receipt
Find the user information necessary for analysis, such as the game character information, by matching the AccountUuid
previously stored in the purchase meta information with the AccountUuid
obtained from the result of the receipt verification. You can analyze the purchase activity of the corresponding game account by matching the purchase meta information with the receipt information.
If a user has purchased multiple items, each purchase can be identified by matching the purchase meta information with the purchaseTime
of hiveiap_receipt
. For details on hiveiap_receipt
, see Verify Receipt and check the API response by market.
Get user purchase activity information: using iadPayload
When requesting a purchase with Purchase() if your game company also provides the predefined data to analyze user purchase activity, the iapPayload
, the Hive server matches the purchase receipt corresponding to iapPayload
and sends this to the game server. The game company can use the information in the receipt and the information in iadPayload
together to analyze user purchase activity.
Define iapPayload
and execute Purchase()
When executing each product purchase request, define desired fields and values in iapPayload
and use it as an argument. The process is similar to defining purchase metadata.
Request the receipt verification, and receive the iapPayload
and the corresponding receipt.
When a payment was completed and the receipt verification is requested, the Hive server matches the iapPayload
with its corresponding receipt by purchase and delivered them to the game server. The game studios can use the information in the iapPayload
and the receipt to analyze user purchase activity.