Overview

The Kongregate SDK includes a receipt verification API, which is intended to be used by games that do not implement their own server based solution. Game specific server-side Receipt Verification is recommended, if possible. For iOS the SDK’s Receipt Verification API relies on the client to verify the purchase with iTunes Connect. This is less reliable than server based authentication. The Android Receipt Verification API will use Kongregate servers and simply validates the given receipt was signed with appropriate key.

Purchase Flow

This Purchase Flow Diagram outlines the basic steps of a purchase. Below is a detailed walk through, followed by some sample code for iOS, Android, and Unity. These steps should be followed whether using the Kongregate Receipt Validation API or your own solution.

If failed or cancelled, invoke finishPurchase(FAIL, transationDetails, gameFields, null). On iOS transactionDetails is the transactionId, and Android it will be the fail reason (e.g. IabResult.getMessage()). API Docs: iOS, Android, Unity.

If successful, verify the receipt using your server. If you do not have a receipt verification server, you may use the API included in our SDK (see below).

If the verification result is successful give the goods and invoke finishPurchase(SUCCESS, transactionDetails, gameFields, dataSignature), to fire the appropriate analytics events. transactionDetails should be the unfinished transactionId on iOS and the full receipt JSON on Android. dataSignature is not use on iOS. On Android it should be the signature included with the receipt.

If the verification result is failed, invoke finishPurchase(RECEIPT_FAIL, transactinDetails, gameFields, null) to fire the appropriate analytics events. Again, on iOS, simply pass the transactionId.

On either success or fail, invokeSKPaymentQueue finishTransaction: (iOS) or IInAppBillingService.consumePurchase() (Android)) to complete the purchase. On Unity, invoke the method on the plugin that triggers finishTransaction or consumePurchase.

IMPORTANT: if using a Unity plugin on iOS be sure to use one that allows you to delay invokation of finishTransaction until after the receipt has been verified. (e.g. Prime31)

Receipt Validation API

The SDK provides two ways of handling the verification. The first and simplest is by using a callback, this is the prefered way. The second option is by polling for the status. Use this second option if you are on a platform where callbacks are not possible to perform.

Android Setup

The producer will need to enter the Google Public Key into game configuration form on Kongregate.com.

iOS Setup

No special setup is required to use the iOS API.

iOS Sample Code

Option 1) Using a callback:

[myPurchaseMangerpurchase:productwithPurchaseHandler:^(SKPaymentTransaction*transaction){[KongregateAPI.instance.mtxverifyTransaction:transactioncompletionHandler:^(BOOLvalid){if(valid){//Since it is valid, track the purchase and give the goods
[KongregateAPI.instance.analyticstrackPurchase:transaction.payment.productIdentifierwithQuantity:transaction.payment.quantitywithGameFields:gameFields];//give the user the goods
[myPurchaseManagerproductPurchased:product];}else{NSLog(@"Invalid transaction");}//Always finish the transaction
[[SKPaymentQueuedefaultQueue]finishTransaction:transaction];}];}];

Option 2) Polling the status:

NSString*newTransactionId=transaction.transactionId;[KongregateAPI.instance.mtxverifyTransactionId:newTransactionId];...//check the status on our transaction id
NSString*status=[KongregateAPI.instance.mtxreceiptVerificationStatus:newTransactionId];if([KONG_RECEIPT_VERIFICATION_STATUS_PROCESSINGisEqualToString:status]){//the transaction status is still processing, check again later
}else{//now that the processing is complete, we need to make sure we finish the transaction
[[SKPaymentQueuedefaultQueue]finishTransaction:transaction];if([KONG_RECEIPT_VERIFICATION_STATUS_UNKNOWNisEqualToString:status]){//the transaction is not found, this is handled the same as invalid
}if([KONG_RECEIPT_VERIFICATION_STATUS_INVALIDisEqualToString:status]){//the transaction is not valid
[KongregateAPI.instance.analyticsfinishPurchase:KONG_PURCHASE_RECEIPT_FAILwithTransactionId:transaction.transactionIdentifierwithGameFields:@{}];}if([KONG_RECEIPT_VERIFICATION_STATUS_VALIDisEqualToString:status]){//the transaction is valid
[KongregateAPI.instance.analyticsfinishPurchase:KONG_PURCHASE_SUCCESSwithTransactionId:transaction.transactionIdentifierwithGameFields:@{@"hard_currency_change":@5}];//give the user the goods
[myPurchaseManagerproductPurchased:product];}}

Android Sample Code

Option 1) Using a callback:

// purchase is a Purchase object from the Google IABHelper sample code. mAPI// is a reference to the KongregateAPI.mAPI.mtx().verifyTransaction(purchase.getOriginalJson(),purchase.getSignature(),newMicrotransactionServices.ReceiptVerificationListener(){@OverridepublicvoidreceiptVerificationComplete(booleansuccess){if(success){// The receipt is good award the goods...// notify the kong SDK to track the analyticsmAPI.analytics().finishPurchase(AnalyticsServices.IabResult.SUCCESS,purchase.getOriginalJson(),purchaseEvent,purchase.getSignature());// and consume. mHelper and mConsumeFinishedListener are also// from the Google IABHelper sample code.mHelper.consumeAsync(purchase,mConsumeFinishedListener)}else{// notify the Kong SDK the receipt validation failed.mAPI.analytics().finishPurchase(AnalyticsServices.IabResult.RECEIPT_FAIL,purchase.getOriginalJson(),purchase.getSignature());// consume the purchasemHelper.consumeAsync(purchase,mConsumeFinishedListener);}}});

Option 2) Polling the status:

When a purchase is made, schedule the receipt validation.

// maintain a map of purchases pending receipt validationprivateMap<String,Purchase>mPurchasesPendingRV=newHashMap<>();// purchase is a Purchase object from the Google IABHelper sample code.// mAPI is a reference to the KongregateAPI.mPurchasesPendingRV.put(purchase.getOrderId(),purchase);mAPI.mtx().verifyTransaction(purchase.getOriginalJson(),purchase.getSignature());

Listen and handle the receipt validation completion event.

// your method for handling Kongregate EventsprivatevoidhandleEvent(Stringevent)if(KongregateEvent.RECEIPT_VERIFICATION_COMPLETE.equals(event)){handleReceiptVerificationComplete();}else...// handle other kongregaet events}// Method checks the status of pending purchases and handle the completed ones.voidhandleReceiptVerificationComplete(){List<String>orderIdsCompleted=newLinkedList<>();for(Stringkey:mPurchasesPendingRV.keySet()){MicrotransactionServices.ReceiptVerificationStatusrvStatus=mAPI.mtx().receiptVerificationStatus(key);if(!MicrotransactionServices.ReceiptVerificationStatus.PROCESSING.equals(rvStatus)){orderIdsCompleted.add(key);Purchasepurchase=mPurchasesPendingRV.get(key);if(!MicrotransactionServices.ReceiptVerificationStatus.INVALID.equals(rvStatus)){// receipt is not invalid, go ahead and award the currency or itemsawardCurrency(purchase.getSku());}// always consume purchases once RV is complete, so uses can attempt to purchase// the items again.mHelper.consumeAsync(purchase,mConsumeFinishedListener);}}// clear out pending listfor(StringorderId:orderIdsCompleted){mPurchasesPendingRV.remove(orderId);}}

Unity Sample Code

Unity only supports the polling method. See KongregateGameObject-Example.cs included with the Kongregate unity package for sample code.