In-App Purchase API overview for Windows Phone 8

[ This article is for Windows Phone 8 developers. If you’re developing for Windows 10, see the latest documentation. ]

 

This topic gives an overview of the In-App Purchase API for Windows Phone 8.

This topic contains the following sections.

 

In-app purchase in your Windows Phone app

Using in-app purchase, you can create apps and games that sell virtual products for real money. Microsoft servers host the catalog of your virtual products that users can purchase using in-app purchasing, including price and description. Microsoft also provides a commerce infrastructure, including methods for users to pay in supported countries and regions around the world.

You enter a description and prices in Dev Center for each product that a user can purchase using in-app purchase, and for each region where users can make the in-app purchase. Using APIs in this document, you can list, within an app, the products that a user can purchase in that app. You don’t need to write special code for handling different types of purchase instruments. All purchase methods used to purchase apps and games in the Windows Phone Store can also be used by the In-App Purchase API. You must host and deliver any content associated with the in-app product.

Product types

Windows Phone 8 supports two types of in-app products that a user can purchase: Consumable and Durable. The following table provides details about each type of in-app product. These product types are defined in the ProductType enumeration.

In-app product type

Description

Example

Consumable

A product that is purchased, used (consumed), and can be purchased again.

1,000 units of gold

Durable

A product that is purchased and owned by the purchaser forever. It is not consumed.

A game level

API reference overview

Windows.ApplicationModel.Store

The Windows.ApplicationModel.Store namespace contains the classes you can use to implement an in-app purchase experience in your app. You can use these classes to check the license state of your app and its in-app products, and to enable in-app purchases. The Windows Phone 8 version of this API implements most, but not all, Windows 8 functionality. The following table lists the classes in Windows.ApplicationModel.Store that can be used on both Windows 8 and on Windows Phone 8.

Class

Description

CurrentApp

Defines methods and properties you can use to get license and listing info about the current app, and to perform in-app purchases.

LicenseInformation

Lists all licenses for products owned by the user.

ListingInformation

Lists Store products a user can purchase from the app in their country/region.

ProductLicense

Indicates whether the user owns a specific in-app product.

ProductListing

Describes information, including localized pricing, icon, title, and description, of an in-app product that the user can purchase in the app.

Additional in-app purchase functionality in Windows Phone 8 

The following table lists additional methods and properties we’ve added to some types in the Windows.ApplicationModel.Store namespace specifically for Windows Phone 8.

Class

Member

Description

CurrentApp

LoadListingInformationByProductIdsAsync(ListingInformation productIds)

Asynchronously loads product listing info for in-app products that match any of specified product IDs. Specifying an empty list of IDs returns product listing info for ALL in-app products.

CurrentApp

LoadListingInformationByKeywordsAsync(ListingInformation keywords)

Asynchronously loads product listing info for in-app products that match all of the specified keywords. Specifying an empty list of keywords returns the product listing info for ALL in-app products.

It is possible to load listing information for all in-app products that match one or more keywords by making separate calls to this API for each keyword.

CurrentApp

void ReportProductFulfillment(string productId)

Notifies Store that the app has delivered the purchased goods to the user. A user can’t purchase the same product again until you have confirmed its delivery using this method. This applies only to consumable products.

ProductLicense

bool IsConsumable { get; }

Gets info on whether the product with this license is a consumable.

ProductListing

string Description { get; }

Gets the description of the in-app product.

ProductListing

IEnumerable<string> Keywords {get;}

Gets the list of keywords for this in-app product. These keywords are useful for filtering product lists by keyword.

ProductListing

ProductType ProductType {get;}

Gets the type of this in-app product. This can be either ProductType.Consumable or ProductType.Durable.

ProductListing

string Tag {get;}

Gets the tag string that contains custom info about this in-app product.

ProductListing

Uri ImageUri { get; }

Gets the URI of the image associated with this in-app product.

Code examples

This section contains a set of code examples that show you how to use the new In-App Purchase API to do the following:

  • Load listing info for in-app products that have specific product IDs

  • Show the purchase screen and handle the exception case of an incomplete purchase

  • Fulfill consumable in-app products

  • Use a receipt as proof of purchase on a server

Load listing info for in-app products that have specific product IDs

async void LoadProductListingsByProductIds()
{
    // First, retrieve the list of some products by their IDs.
    ListingInformation listings = await CurrentApp.LoadListingInformationByProductIdsAsync(
                                    new string[] { "Bag of 50 gold", "Bag of 100 gold" });

    // Then, use the flat list of products as the data source for a
    // list box containing data-bound list items.
    ProductListBox.ItemsSource = listings.ProductListings.Values;
}

Show the purchase screen

async void PurchaseProduct(string productId)
{
    try
    {
        // Kick off purchase; don't ask for a receipt when it returns
        await CurrentApp.RequestProductPurchaseAsync(productId, false);

        // Now that purchase is done, give the user the goods they paid for
        // (DoFulfillment is defined later)
        DoFulfillment();
    }
    catch (Exception ex)
    {
        // When the user does not complete the purchase (e.g. cancels or navigates back from the Purchase Page), an exception with an HRESULT of E_FAIL is expected.
    }
}

Fulfill consumable in-app products

// This should be replaced in your code with a persistent storage mechanism that is tamper-resistant.
int m_goldCount = 0;
int m_silverCount = 0;

//
// Fulfillment of consumable in-app products
public void DoFulfillment()
{
    var productLicenses = CurrentApp.LicenseInformation.ProductLicenses;

    // Check fulfillment for consumable products with hard-coded asset counts
    MaybeGiveMeGold(productLicenses["Bag of 50 gold"], 50);
    MaybeGiveMeGold(productLicenses["Bag of 100 gold"], 100);

    // Check fulfillment for consumable products with variable asset counts
    MaybeGiveMeSilver(productLicenses);
}

// Count is passed in as a parameter
void MaybeGiveMeGold(ProductLicense license, int goldCount)
{
    if (license.IsConsumable && license.IsActive)
    {
        m_goldCount += goldCount;
        CurrentApp.ReportProductFulfillment(license.ProductId);
    }
}

// Count is part of the product ID
void MaybeGiveMeSilver(IReadOnlyDictionary<string, ProductLicense> productLicenses)
{
    Regex bagOfSilver = new Regex(@"Bag\.Silver\.(\d+)");

    foreach (ProductLicense license in productLicenses.Values)
    {
        if (license.IsConsumable && license.IsActive)
        {
            MatchCollection m = bagOfSilver.Matches(license.ProductId);

            if ((m.Count == 2) && (m[1].Success))
            {
                m_silverCount += int.Parse(m[1].Value);
                CurrentApp.ReportProductFulfillment(license.ProductId);
            }
        }
    }
}

Use a receipt as proof of purchase on a server

async Task<bool> LoadLevelAsync(string levelProductId)
{
    ProductLicense license = CurrentApp.LicenseInformation.ProductLicenses[levelProductId];

    if (!license.IsActive)
    {
        // User doesn't own this level
        return false;
    }

    if (!IsLevelDownloaded(levelProductId))
    {
        string receiptXml = await CurrentApp.GetProductReceiptAsync(levelProductId);

        await DownloadLevelAsync(receiptXml);
    }

    // TODO: Load the level
    return true;
}

async Task DownloadLevelAsync(string receiptXml)
{
    var webReq = (HttpWebRequest)WebRequest.Create(sc_DownloadUrl);

    webReq.Method = "POST";

    AddStringToWebRequestStream(webReq, receiptXml);

    WebResponse response = await webReq.GetResponseAsync();

    // TODO: Save the level to disk
}

See Also

Other Resources

In-app purchase for Windows Phone 8

Asynchronous programming