Blog

Latest news and updates from the PlayFab developers

by BrendanVanous 2015-02-06

Show Me the Money: Receipt Validation for iOS and Android

In theory, one of the biggest advantages to live games for your average developer should be how easy it is to set up in-app purchases. Just publish your game, link to the Apple or Google app store, and boom, done! In practice, however, receipt validation is not included in most game engines and many third-party solutions for free-to-play games aren’t cross-platform. In addition, receipt validation is just one in a series of steps needed to handle player purchases in a secure game economy.

PlayFab’s API calls make it easy to set this up for your game, giving you a reliable record of all real-money purchases and ensuring that players actually get the items they’ve bought. By including receipt validation and player inventory updates in the same server-side transactions, you can protect your virtual economy from real-world problems.

This article walks through the steps to set up receipt validation for your Android or iOS game. (PlayFab also works with many other payment providers, including Steam and PSN.)

Setting Up for Purchases

The first thing you should do is to set up your real-money in-app purchase (IAP) item in the iTunes or Google Play store:

Be sure to keep track of the following values:

Item ID: This is the unique alphanumeric identifier for the item, which well be using for the identifier in PlayFab. This is the Product ID field in iTunes Connect, and the In-app Product ID in the Google Play In-app Products UI. If you use the Google Play Web API directly, the SKU parameter is used to define the In-app Product ID.

Customer Price: The total price that the customer pays for the item, in real-world currencies. You can optionally set these up in your PlayFab catalog (in the Economy tab) with matching values, as a convenience. Note that Apple and Google do not provide us with a way to query the current prices from their catalog, so if there’s a sale on, the price won’t match unless you’ve changed the PlayFab catalog as well. It’s also worth noting that you can also set up prices in any supported currency, which we’ll talk about below.

PlayFab Catalog

Next, you’ll need to set up a Catalog entry for the item in the PlayFab service. For simplicity, I’ll use UpdateCatalogItems for this example, as that call allows you to configure an item without affecting the rest of the catalog. Now, as to the item, we'll use a Bundle that contains the in-game Virtual Currency "GC" (Gold Coins). For free-to-play games, this is one of the most common uses of real money purchases, since it provides a simple economic system - players can purchase Virtual Currencies (VC), which they can then use to purchase all the other items from the in-game economy. This allows you to adjust pricing more flexibly, and gives you more control over the game's economic structure.

Note: {{Title ID}} and {{Title Secret Key}} in these examples must be replaced with your actual Title ID and Secret Key, which you can find on your games Game Settings page in the PlayFab Game Manager.

<code class="language-json">POST https://{{Title ID}}.playfabapi.com/Admin/UpdateCatalogItems
Content-Type: application/json;
X-SecretKey: {{Title Secret Key}}
{
  "CatalogVersion": "1",
  "Catalog": [
    {
      "ItemId": "BagOfGold",
      "DisplayName": "It's a sack of gold!",
      "Description": "This is a bag of gold, which can be used to purchase upgrades for your characters."
      "Bundle": {
        "BundledVirtualCurrencies": {
          "GC": 1000
        }
      }
    }
  ]
}
</code>

Again, the ItemId (BagOfGold) must match the identifier provided to the iTunes (Product ID) or Google Play (In-app Product ID or SKU) store.

PlayFab Store

Now if you want to set the Catalog item’s real-money price to match the price of the corresponding iTunes or Google Play IAP item, you can do that in the Catalog itself, or you can set it in a Store. Stores contain a subset of items from a Catalog, and can have unique pricing. This allows you to have different sets of items, optionally with custom pricing, for different purposes. Again, well use the Update version of the call, for simplicity.

<code class="language-json">POST https://{{Title ID}}.playfabapi.com/Admin/UpdateStoreItems
Content-Type: application/json;
X-SecretKey: {{Title Secret Key}}
{
  "StoreId": "GoldStore",
  "Catalog": [
    {
      "ItemId": "BagOfGold",
      "CatalogVersion": "1",
      "VirtualCurrencyPrices": {
        "RM": 199
      },
      "RealCurrencyPrices": {
        "GBP": 149,
        "EUR": 169
      }
    }
  ]
}
</code>

The StoreId is the name of the store, and can be any string. The ItemId and CatalogVersion must match the values for the item you set up in the Catalog previously.

The VirtualCurrencyPrices object is where you can set up virtual currency prices for items, but it’s also where you can define the real-money price. Just as all virtual currencies have two-letter codes, “RM” is the two-letter code for “Real Money”. RM prices are given in USD, listed in pennies. So, in the example above, the Bag of Gold is priced at RM 199, or USD $1.99.

If you defined prices in other currencies for your item in the iTunes or Google Play store, and you want to have them also in your PlayFab catalog, you can set them up in the RealCurrencyPrices property, as shown.

Presenting to the User

Your game client can call the GetCatalogItems and GetStoreItems API calls to retrieve the information you set up in the last two steps. Note that when making a call from the client, the authentication token is the Session Ticket received from a PlayFab authentication call for the player, such as LoginWithPlayFab, LoginWithAndroidDeviceID, orLoginWithIOSDeviceID.

<code class="language-json">POST HTTPS://{{Title ID}}.playfabapi.com/Client/GetCatalogItems
X-Authentication: {{User Session Ticket}}
{
  "CatalogVersion": "1"
}
POST HTTPS://{{Title ID}}.playfabapi.com/Client/GetStoreItems
X-Authentication: {{User Session Ticket}}
{
  "StoreId": "GoldStore"
}
</code>

Your game client can then display the item to the player in your in-game store UI as available for purchase for the item’s real-money price.

Making the Sale

Once users have selected items to purchase, you need to present them with the actual purchase dialog in your game client.

iTunes

On iOS, use the Store Kit Framework. More information can be found in the Apple developer documentation, but this is the basic flow:

  1. Send the list of ItemId identifiers (the iTunes Connect Product ID) to the App Store using an instance ofSKProductsRequest.
  2. Present the in-game user interface for the store using the SKProduct instances you get back from the App Store.
  3. Request payment from the App Store by adding an SKPayment for each item purchased to the SKPaymentQueue.
  4. Check the transactionState of the purchases using an SKPaymentTransactionObserver.
  5. If the transaction is successful, retrieve the receipt via appStoreReceiptURL (use a fallback to the SKPaymentTransactions transactionReceipt, if the URL isnt available).
  6. Call the PlayFab ValidateIOSReceipt API call with the receipt you received in the previous step:
<code class="language-json">POST HTTPS://{{Title ID}}.playfabapi.com/Client/ValidateIOSReceipt
X-Authentication: {{User Session Ticket}}
{
  "ReceiptData": "{{Apple iTunes receipt}}",
  "CurrencyCode": "{{Currency code for the purchase}}",
  "PurchasePrice": {{Price of the item to be purchased}}
}
</code>

Here, you need to specify the standard currency code (“USD”, “GBP”, etc.) for the purchase made, as well as the actual price paid in PurchasePrice, using the smallest unit of the given currency, such as pennies. This is important, as it is used for the reporting in the Game Manager for your title, providing you with a convenient means to track on total revenue, top spenders, etc., across all your supported platforms.

Google Play

On Google Play (using the Version 3 API as the example), use the Google Play In-app Billing service. Again, more information can be found on the Google developer site, but the basic flow is:

  1. Make a call to isBillingSupported first, to ensure that you can proceed.
  2. Use getPurchases to retrieve the Bundle of items in the players Google Play inventory.
  3. For any items which are not consumables, the player shouldnt be able to purchase them twice, and the matching items should be in the players PlayFab inventory.
  4. For any consumable items, make a call to consumePurchase, so that the player is able to purchase the item again.
  5. (Optional) Retrieve the details of the item to be purchased with getSkuDetails, using the PlayFab ItemId of the item the player wants to purchase
  6. Begin the actual purchase request with a call to getBuyIntent, again using the PlayFab ItemId.
  7. Assuming the Bundles response is good, pass the PendingIntent it contains into startIntentSenderForResult, to present the user with the confirmation dialog.
  8. In your onActivityResult, if the purchase was successful, extract the purchaseData and signature from the returned Intent using RESPONSE_INAPP_PURCHASE_DATA and RESPONSE_INAPP_SIGNATURE, respectively.
  9. Call the PlayFab ValidateGooglePlayPurchase API call with the receipt you received in the previous step, passing in the signature and purchaseData (as the ReceiptJson).
  10. (Optional) If the item purchased is a consumable, make a call to consumePurchase
<code class="language-json">POST HTTPS://{{Title ID}}.playfabapi.com/Client/ValidateGooglePlayPurchase
X-Authentication: {{User Session Ticket}}
{
  "ReceiptJson": "{{Google Play purchaseData}}",
  "Signature": "{{Google Play signature}}",
  "CurrencyCode": "{{Currency code for the purchase}}",
  "PurchasePrice": {{Price of the item to be purchased}}
}
</code>

Of particular importance here are the CurrencyCode and PurchasePrice. They’re the same as for iOS purchases above – a standard currency code, and the actual price in that currency’s smallest unit. However, it’s worth noting that these are optional parameters on the Google receipt validation call in PlayFab. If you choose not to send these values in the call, then at a minimum, you must define an RM price for the item in your Catalog, or any attempt to purchase the item will fail as there must be a price that can be recorded. The recommendation is to always send the correct currency code and purchase price.

Preventing Cheating

As part of the receipt validation process, whatever item or items were purchased are added to the player’s inventory on the PlayFab servers. But it’s also important that those items are only added once. If players use a replay attack, they could repeatedly send the same receipt in a an effort to cheat their way to more currency, cool swords, or whatever. So PlayFab goes beyond simple validation and also checks to make sure that not only is a receipt authentic, but that it hasn’t been used yet in the game. Using PlayFab gives you secure, reliable in-app purchases, from start to finish.