Enable subscription add-ons for your app

Your Universal Windows Platform (UWP) app can offer in-app purchases of subscription add-ons to your customers. You can use subscriptions to sell digital products in your app (such as app features or digital content) with automated recurring billing periods.

Note

To enable the purchase of subscription add-ons in your app, your project must target Windows 10 Anniversary Edition (10.0; Build 14393) or a later release in Visual Studio (this corresponds to Windows 10, version 1607), and it must use the APIs in the Windows.Services.Store namespace to implement the in-app purchase experience instead of the Windows.ApplicationModel.Store namespace. For more information about the differences between these namespaces, see In-app purchases and trials.

Feature highlights

Subscription add-ons for UWP apps support the following features:

  • You can choose from subscription periods of 1 month, 3 months, 6 months, 1 year, or 2 years.
  • You can add free trial periods of 1 week or 1 month to your subscription.
  • The Windows SDK provides APIs you can use in your app to get info about available subscription add-ons for the app and enable the purchase of a subscription add-on. We also provide REST APIs you can call from your services to manage subscriptions for a user.
  • You can view analytic reports that provide the number of subscription acquisitions, active subscribers, and canceled subscriptions in a given time period.
  • Customers can manage their subscription on the https://account.microsoft.com/services page for their Microsoft account. Customers can use this page to view all of the subscriptions they have acquired, cancel a subscription, and change the form of payment that is associated with their subscription.

Steps to enable a subscription add-on for your app

To enable the purchase of subscription add-ons in your app, follow these steps.

  1. Create an add-on submission for your subscription in Partner Center and publish the submission. As you follow the add-on submission process, pay close attention to the following properties:

    • Product type: Make sure you select Subscription.

    • Subscription period: Choose the recurring billing period for your subscription. You cannot change the subscription period after you publish your add-on.

      Each subscription add-on supports a single subscription period and trial period. You must create a different subscription add-on for each type of subscription you want to offer in your app. For example, if you wanted to offer a monthly subscription with no trial, a monthly subscription with a one-month trial, an annual subscription with no trial, and an annual subscription with a one-month trial, you would need to create four subscription add-ons.

    • Trial period: Consider choosing a 1 week or 1 month trial period for your subscription to enable users to try your subscription content before they buy it. You cannot change or remove the trial period after you publish your subscription add-on.

      To acquire a free trial of your subscription, a user must purchase your subscription through the standard in-app purchase process, including a valid form of payment. They are not charged any money during the trial period. At the end of the trial period, the subscription automatically converts to the full subscription and the user's payment instrument will be charged for the first period of the paid subscription. If the user chooses to cancel their subscription during the trial period, the subscription remains active until the end of the trial period. Some trial periods are not available for all subscription periods.

      Note

      Each customer can acquire a free trial for a subscription add-on only one time. After a customer acquires a free trial for a subscription, the Store prevents the same customer from ever acquiring the same free trial subscription again.

    • Visibility: If you are creating a test add-on that you will only use to test the in-app purchase experience for your subscription, we recommend that you select one of the Hidden in the Store options. Otherwise, you can select the best visibility option for your scenario.

    • Pricing: Choose the price of your subscription in this section. You cannot raise the price of the subscription after you publish the add-on. However, you can lower the price later.

      Important

      By default, when you create any add-on the price is initially set to Free. Because you cannot raise the price of a subscription add-on after you complete the add-on submission, be sure to choose the price of your subscription here.

  2. In your app, use APIs in the Windows.Services.Store namespace to determine whether the current user has already acquired your subscription add-on and then offer it for sale to the user as an in-app purchase. See the code examples in this article for more details.

  3. Test the in-app purchase implementation of your subscription in your app. You'll need to download your app once from the Store to your development device to use its license for testing. For more information, see our testing guidance for in-app purchases.

  4. Create and publish an app submission that includes your updated app package, including your tested code. For more information, see App submissions.

Code examples

The code examples in this section demonstrate how to use the APIs in the Windows.Services.Store namespace to get info about subscription add-ons for the current app and request the purchase a subscription add-on on behalf of the current user.

These examples have the following prerequisites:

  • A Visual Studio project for a Universal Windows Platform (UWP) app that targets Windows 10 Anniversary Edition (10.0; Build 14393) or a later release.
  • You have created an app submission in Partner Center and this app is published in the Store. You can optionally configure the app so it is not discoverable in the Store while you test it. For more information, see the testing guidance.
  • You have created a subscription add-on for the app in Partner Center.

The code in these examples assumes:

  • The code file has using statements for the Windows.Services.Store and System.Threading.Tasks namespaces.
  • The app is a single-user app that runs only in the context of the user that launched the app. For more information, see In-app purchases and trials.

Note

If you have a desktop application that uses the Desktop Bridge, you may need to add additional code not shown in these examples to configure the StoreContext object. For more information, see Using the StoreContext class in a desktop application that uses the Desktop Bridge.

Purchase a subscription add-on

This example demonstrates how to request the purchase of a known subscription add-on for your app on behalf of the current customer. This example also shows how to handle the case where the subscription has a trial period.

  1. The code first determines whether the customer already has an active license for the subscription. If the customer already has an active license, your code should unlock the subscription features as necessary (because this is proprietary to your app, this is identified with a comment in the example).
  2. Next, the code gets the StoreProduct object that represents the subscription you want to purchase on behalf of the customer. The code assumes that you already know the Store ID of the subscription add-on you want to purchase, and that you have assigned this value to the subscriptionStoreId variable.
  3. The code then determines whether a trial is available for the subscription. Optionally, your app can use this information to display details about the available trial or full subscription to the customer.
  4. Finally, the code calls RequestPurchaseAsync method to request the purchase of the subscription. If a trial is available for the subscription, the trial will be offered to the customer for purchase. Otherwise, the full subscription will be offered for purchase.
private StoreContext context = null;
StoreProduct subscriptionStoreProduct;

// Assign this variable to the Store ID of your subscription add-on.
private string subscriptionStoreId = "";  

// This is the entry point method for the example.
public async Task SetupSubscriptionInfoAsync()
{
    if (context == null)
    {
        context = StoreContext.GetDefault();
        // If your app is a desktop app that uses the Desktop Bridge, you
        // may need additional code to configure the StoreContext object.
        // For more info, see https://aka.ms/storecontext-for-desktop.
    }

    bool userOwnsSubscription = await CheckIfUserHasSubscriptionAsync();
    if (userOwnsSubscription)
    {
        // Unlock all the subscription add-on features here.
        return;
    }

    // Get the StoreProduct that represents the subscription add-on.
    subscriptionStoreProduct = await GetSubscriptionProductAsync();
    if (subscriptionStoreProduct == null)
    {
        return;
    }

    // Check if the first SKU is a trial and notify the customer that a trial is available.
    // If a trial is available, the Skus array will always have 2 purchasable SKUs and the
    // first one is the trial. Otherwise, this array will only have one SKU.
    StoreSku sku = subscriptionStoreProduct.Skus[0];
    if (sku.SubscriptionInfo.HasTrialPeriod)
    {
        // You can display the subscription trial info to the customer here. You can use 
        // sku.SubscriptionInfo.TrialPeriod and sku.SubscriptionInfo.TrialPeriodUnit 
        // to get the trial details.
    }
    else
    {
        // You can display the subscription purchase info to the customer here. You can use 
        // sku.SubscriptionInfo.BillingPeriod and sku.SubscriptionInfo.BillingPeriodUnit
        // to provide the renewal details.
    }

    // Prompt the customer to purchase the subscription.
    await PromptUserToPurchaseAsync();
}

private async Task<bool> CheckIfUserHasSubscriptionAsync()
{
    StoreAppLicense appLicense = await context.GetAppLicenseAsync();

    // Check if the customer has the rights to the subscription.
    foreach (var addOnLicense in appLicense.AddOnLicenses)
    {
        StoreLicense license = addOnLicense.Value;
        if (license.SkuStoreId.StartsWith(subscriptionStoreId))
        {
            if (license.IsActive)
            {
                // The expiration date is available in the license.ExpirationDate property.
                return true;
            }
        }
    }

    // The customer does not have a license to the subscription.
    return false;
}

private async Task<StoreProduct> GetSubscriptionProductAsync()
{
    // Load the sellable add-ons for this app and check if the trial is still 
    // available for this customer. If they previously acquired a trial they won't 
    // be able to get a trial again, and the StoreProduct.Skus property will 
    // only contain one SKU.
    StoreProductQueryResult result =
        await context.GetAssociatedStoreProductsAsync(new string[] { "Durable" });

    if (result.ExtendedError != null)
    {
        System.Diagnostics.Debug.WriteLine("Something went wrong while getting the add-ons. " +
            "ExtendedError:" + result.ExtendedError);
        return null;
    }

    // Look for the product that represents the subscription.
    foreach (var item in result.Products)
    {
        StoreProduct product = item.Value;
        if (product.StoreId == subscriptionStoreId)
        {
            return product;
        }
    }

    System.Diagnostics.Debug.WriteLine("The subscription was not found.");
    return null;
}

private async Task PromptUserToPurchaseAsync()
{
    // Request a purchase of the subscription product. If a trial is available it will be offered 
    // to the customer. Otherwise, the non-trial SKU will be offered.
    StorePurchaseResult result = await subscriptionStoreProduct.RequestPurchaseAsync();

    // Capture the error message for the operation, if any.
    string extendedError = string.Empty;
    if (result.ExtendedError != null)
    {
        extendedError = result.ExtendedError.Message;
    }

    switch (result.Status)
    {
        case StorePurchaseStatus.Succeeded:
            // Show a UI to acknowledge that the customer has purchased your subscription 
            // and unlock the features of the subscription. 
            break;

        case StorePurchaseStatus.NotPurchased:
            System.Diagnostics.Debug.WriteLine("The purchase did not complete. " +
                "The customer may have cancelled the purchase. ExtendedError: " + extendedError);
            break;

        case StorePurchaseStatus.ServerError:
        case StorePurchaseStatus.NetworkError:
            System.Diagnostics.Debug.WriteLine("The purchase was unsuccessful due to a server or network error. " +
                "ExtendedError: " + extendedError);
            break;

        case StorePurchaseStatus.AlreadyPurchased:
            System.Diagnostics.Debug.WriteLine("The customer already owns this subscription." +
                    "ExtendedError: " + extendedError);
            break;
    }
}

Get info about subscription add-ons for the current app

This code example demonstrates how to get info for all the subscription add-ons that are available in your app. To get this info, first use the GetAssociatedStoreProductsAsync method to get the collection of StoreProduct objects that represent each of the available add-ons for the app. Then, get the StoreSku for each product and use the IsSubscription and SubscriptionInfo properties to access the subscription info.

private StoreContext context = null;

public async Task GetSubscriptionsInfo()
{
    if (context == null)
    {
        context = StoreContext.GetDefault();
        // If your app is a desktop app that uses the Desktop Bridge, you
        // may need additional code to configure the StoreContext object.
        // For more info, see https://aka.ms/storecontext-for-desktop.
    }

    // Subscription add-ons are Durable products.
    string[] productKinds = { "Durable" };
    List<String> filterList = new List<string>(productKinds);

    StoreProductQueryResult queryResult =
        await context.GetAssociatedStoreProductsAsync(productKinds);

    if (queryResult.ExtendedError != null)
    {
        // The user may be offline or there might be some other server failure.
        System.Diagnostics.Debug.WriteLine($"ExtendedError: {queryResult.ExtendedError.Message}");
        return;
    }

    foreach (KeyValuePair<string, StoreProduct> item in queryResult.Products)
    {
        // Access the Store product info for the add-on.
        StoreProduct product = item.Value;

        // For each add-on, the subscription info is available in the SKU objects in the add-on. 
        foreach (StoreSku sku in product.Skus)
        {
            if (sku.IsSubscription)
            {
                // Use the sku.SubscriptionInfo property to get info about the subscription. 
                // For example, the following code gets the units and duration of the 
                // subscription billing period.
                StoreDurationUnit billingPeriodUnit = sku.SubscriptionInfo.BillingPeriodUnit;
                uint billingPeriod = sku.SubscriptionInfo.BillingPeriod;
            }
        }
    }
}

Manage subscriptions from your services

After your updated app is in the Store and customers can buy your subscription add-on, you may have scenarios where you need to manage the subscription for a customer. We provide REST APIs you can call from your services to perform the following subscription management tasks:

Cancellations

Customers can use the https://account.microsoft.com/services page for their Microsoft account to view all of the subscriptions they have acquired, cancel a subscription, and change the form of payment that is associated with their subscription. When a customer cancels a subscription using this page, they continue to have access to the subscription for the duration of the current billing period. They do not get a refund for any part of the current billing period. At the end of the current billing period, their subscription is deactivated.

You can also cancel a subscription on behalf of a user by using our REST API to change the billing state of a subscription for a given user.

Subscription renewals and grace periods

At some point during each billing period, we will attempt to charge the customer's credit card for the next billing period. If the charge fails, the customer's subscription enters the dunning state. This means that their subscription is still active for the remainder of the current billing period, but we will periodically try to charge their credit card to automatically renew the subscription. This state can last up to two weeks, until the end of the current billing period and the renew date for the next billing period.

We do not offer grace periods for subscription billing. If we are unable to successfully charge the customer's credit card by the end of the current billing period, the subscription will be canceled and the customer will no longer have access to the subscription after the current billing period.

Unsupported scenarios

The following scenarios are not currently supported for subscription add-ons.

  • Selling subscriptions to customers directly via the Store is not supported at this time. Subscriptions are available for in-app purchases of digital products only.
  • Customers cannot switch subscription periods using the https://account.microsoft.com/services page for their Microsoft account. To switch to a different subscription period, customers must cancel their current subscription and then purchase a subscription with a different subscription period from your app.
  • Tier switching is currently not supported for subscription add-ons (for example, switching a customer from a basic subscription to a premium subscription with more features).
  • Sales and promotional codes are currently not supported for subscription add-ons.
  • Renewing existing subscriptions after setting the visibility of your subscription add-on to Stop acquisition. See Set add-on pricing and availability for more details.