Streaming is available in most browsers,
and in the Developer app.
-
Support customers with StoreKit 2 and App Store Server API
Discover how you can use StoreKit 2, App Store Server API, and App Store Server Notifications to create great in-app purchase experiences for your customers and offer support and refunds. We'll explore implementation approaches, provide best practices and take you through customer management and managing refunds.
Resources
- App Store Server API
- Auto-renewable subscriptions overview
- Enabling App Store Server Notifications
- Handling refund notifications
- In-App Purchase
- In-app purchase overview
- Introducing StoreKit 2
Related Videos
WWDC22
-
Download
David Wendland: Hi everyone, I'm David Wendland, a commerce technical advocate for the App Store.
I'm excited to be here today, virtually, to share what our whole team has been working on.
Before I begin, I'd like my Cupertino-based colleagues to introduce themselves.
Manjeet Chawla: Hi, my name is Manjeet Chawla, and I'm a technical program manager for the App Store.
Joe Mani: Hi, I'm Joe.
I'm a program manager for the App Store.
David: The three of us today are presenting you a three-part series titled "Support Customers with StoreKit 2 and App Store Server API." We will focus on how the StoreKit 2 framework and the abilities of the App Store Server API can improve in-app purchase, customer support, and handling refunds.
These three parts we hope will give you insights, approaches, and benefits to consider when planning your app and customer experience enhancements.
I'll get going with in-app purchases by starting with an overview of our Fall launch, and what's new from client to server to sandbox.
And then I'll cover some implementation approaches to consider to help you strategize and prioritize your roadmap when looking to integrate these updates.
Let's get started with what's new.
With iOS 15, we went back to the start and created an all-new and improved framework to simplify the client implementation with StoreKit 2.
This brought more on-device functionality, improved status information, and now transactions use the JWS format for added security.
In addition, we introduced three standalone features to provide more services to the customers directly within your app.
From the server side, we made a significant update to the existing App Store Server Notifications with the launch of Version 2.
This greatly expanded the number of supported purchase events and also uses the new JWS format.
Lastly, we released a suite of features with our App Store Server API.
It has an array of endpoints to support different abilities, from retrieving a customer's purchase history or providing you a subscriber's current subscription status.
The other abilities cover a variety of customer management scenarios which my colleagues, Manjeet and Joe, will be covering shortly.
This year's extensive list of updates illustrates our continued investment in in-app purchase with StoreKit.
Overall, these improve security, reduce complexity, and make it easier to test in-app purchases in Sandbox and Xcode.
When we look at our platform, with features like Touch ID and Face ID, we use secure biometrics and frictionless authentication to allow customers to purchase securely and conveniently on more than 1.5 billion devices.
The App Store now has 600 million weekly visitors across 175 storefronts, in over 40 languages.
You can adjust price tiers per territory and next year we'll be expanding the number of supported price tiers to over 500, giving you more pricing options and providing tailored price points for each currency and market.
With 45 supported currencies across 195 payment methods, we work to make it more convenient for our customers to use their preferred payment method and the ability to stack them.
While we continue these platform improvements, I'd now like to dig in to StoreKit 2 and highlight its benefits and key enhancements over original StoreKit for you to consider.
When we look at a key feature of StoreKit 2, it synchronizes new in-app purchase transactions automatically across all the customer's devices.
This enables you to provide a consistent and reliable experience in your app.
This framework supports on-device purchase validation and is streamlined compared to the earlier framework, so you do not have to entirely depend on server-side purchase validation.
All transactions are signed using JWS, so that you can verify the authenticity of each transaction.
And the framework provides entitlement status information on-device, which reduces complexity so you can ensure proper entitlement access.
And new with iOS 15 is appAccountToken, which allows you to set the in-app account that initiated the purchase and have it returned with completed transactions.
Additionally, there are some unique standalone StoreKit 2 features that can work alongside the original StoreKit framework.
So your app today using original StoreKit with iOS 15 could also add these independent StoreKit 2 features to offer in-app experiences that typically would occur outside of your app.
The first is showManageSubscriptions.
This allows subscribers to manage their subscription without leaving your app.
Then we have beginRefundRequest, where you can present transactions to a customer for which they can initiate a refund request from within your app.
And with this, in Sandbox, this allows you to test and simulate a refund from pending to approved or declined.
We've also introduced an ability to make it easier to check a customer's introductory offer eligibility.
This is important as you want to ensure when merchandising an offer, like a free trial, that when they complete the purchase, they are in fact given the offer.
With StoreKit 2, this check can quickly be done with isEligibleForIntroOffer method, and passing in a subscription group ID.
This checks if they have ever consumed any type of introductory offer for any subscription within that subscription group.
In addition, you should also be merchandising the introductory offer only if it was returned by StoreKit.
That would come from Product.SubscriptionOffer, where it will return the introductory offer details if available.
If it is not, then it will not be returned by StoreKit, thus preventing you from merchandising an offer that isn't available.
So it's important that this is not hardcoded and instead, your app leverages StoreKit, which uses the start and end dates configured in App Store Connect.
Now I want to move server side and discuss features of the App Store Server API, where requests are made server-to-server without any customer interaction.
We'll start with subscription status.
This provides the state of the customer's subscription with your app.
And if you have multiple subscription offerings, then you will have an entitlement state per subscription, each represented by a unique original transaction ID.
A great part of subscription status is it only returns the current JWS signed transaction for each subscription, so no need for logic on your server to parse through a customer's transaction history, trying to determine their current transaction or which product to entitle.
Now if you are a multiplatform service provider, you can use this service to get the current status at any time, server-to-server, without your app running, and all you need is the customer's original transaction ID; no more app receipt.
Here are some best practices we recommend.
It is important you always store the unique original transaction IDs in your database after every purchase or restored transaction.
This value represents each subscription offering, which is critical to track the subscription lifecycle from initial purchase to renewals, to a billing issue and recovery, or upgrades and downgrades.
This ID is used with the client and the server API, along with server notifications.
Lastly, subscription status should only be used server-to-server as a security best practice.
If you need to check the status directly from your app, then the StoreKit 2 framework has your solution.
The next feature with the server API is in-app purchase history, where you can retrieve, server-to-server, the complete and latest history of transactions for a customer.
The history will include all nonconsumables, nonrenewing subscriptions, autorenewable subscriptions, and any unfinished consumable purchases, and all will be secure, JWS signed transactions.
Now, having a history of transactions and all original transaction IDs will help when implementing the beginRefundRequest API, as you will need to surface transactions for the customer to choose from in order to initiate the refund request.
For nonsubscription in-app purchases in apps using the original StoreKit, you can move away from verifyReceipt and use this API to validate successful purchases or check for updates in case of an outage.
For its best practices, some customers may have many purchases, so the response will contain up to 20 transactions at a time.
When there are additional transactions, be sure to use the hasMore field.
When true, use the revision token in that response and your subsequent request to get that next page of transactions.
Repeat until the hasMore field returns false and save that revision token for the future.
That will help you quickly retrieve the latest transactions of a customer, using that recorded revision token so that you do not have to paginate again.
Another important best practice is using finishTransaction after products or services have been delivered.
Unfinished transactions will remain in the queue and help your app to keep track of purchases that need to be delivered to your customers.
This is critical in case there was any interruption on-device.
A final recommendation regarding refunded or revoked transactions is if you want to receive updates on these as quickly and efficiently as possible, then look to Version 2 server notifications.
These are much more efficient than polling any of our APIs.
Now look at our server notifications.
These are sent in near real-time directly to your server for key purchase events and status changes.
This year we dramatically refined this feature with Version 2 to make them more effective, easier to use, and provide more granularity.
We doubled the number of supported events, bringing that total to 28 unique events! With Version 2 we only send a single notification per event, so you can take specific actions when received.
And these notifications also apply to family members who have access through Family Sharing for in-app purchases.
And for any failed notification deliveries, we will retry up to five times over a period of seven days, to account for any outages.
And of course, Version 2 is available in Sandbox, so you can develop safely in our test environment.
For some best practices, when receiving these notifications, it is important to respond with an HTTP 200 Response Code when it was successfully received.
This indicates to us that you have received the notification and that you do not need us to resend.
If your servers return an error or don't respond, the App Store will resend the same notification payload.
Within each notification is the signedDate; you can know exactly when that original notification was sent.
And you can validate the authenticity of received notifications using the JWS signed transaction info, so you can have confidence that these were signed by the App Store.
And be sure to take advantage of the new ability to provide unique server URLs for sandbox and production events.
And as a final best practice, apply the notification updates immediately.
Some events are time-sensitive, such as upgrades or refunds.
Therefore, processing these in near real-time can be beneficial.
And our last update to brief you on is our updates in App Store Connect to help with testing in-app purchases in Sandbox.
You will find these features accessible in the Users & Access tab under Sandbox testers.
As you may know already, in Sandbox today, subscriptions renew at an accelerated rate to support testing.
Now we've added the ability to slow down or accelerate that renewal rate per Sandbox Apple ID, just like you can with StoreKit testing in Xcode.
This should be helpful for scenarios when you need more time to perform actions between the renewals.
To help with testing across different storefronts, now you can change the storefront for a Sandbox Apple ID at any time.
And to further expand the use of a single Sandbox Apple ID, you can now clear its purchase history of autorenewable subscriptions and nonconsumables, allowing you, for example, to purchase content or redeem introductory offers repeatedly.
Now that we've covered some of the benefits and best practices of StoreKit 2 and the Server API, let's review some approaches for you to consider when preparing to integrate these features and abilities into your app or server.
When we think about in-app purchases, we primarily think about entitling customers with their purchases and handling status changes.
To do this, you have to choose to go with an on-device approach -- where you do it all locally without any server backend -- or you leverage serve-to-server APIs, where your server is the source of truth.
Let's start with on-device.
This is where the StoreKit 2 framework provides your app the ability to fully manage in-app purchases and status changes all on-device, without requiring a server.
This can be very helpful for small businesses and those without an existing server backend.
To do this, you start with these three core functional pieces of StoreKit 2 to support the purchase flow.
Your app will use Products to retrieve your available products and its details to drive the merchandising within your app.
This ensures its always accurate and in sync with the App Store.
And now with StoreKit 2, you will have VerificationResult and PurchaseResult, which together are used to validate the authenticity of the transaction after a successful purchase or restored transaction.
Another key benefit of the StoreKit 2 framework is its ability to keep your app up-to-date for any transaction.
Customers may have multiple devices, and with Transaction.updates, your app will be kept in sync no matter what device the transaction originated on.
With currentEntitlement method, your app can quickly get the immediate status for your customer's purchases, so you can immediately grant those products to the customers -- all without requiring them to login or perform a Restore Purchases, as you have the latest transaction details.
Lastly, we understand how important it is to get the autorenewable subscription information on-device, not just about the product itself but about the current subscriber's status and their upcoming renewal period.
For that we have Product.SubscriptionInfo.
So with these six core functions that I just covered, you can take advantage of StoreKit 2 on iOS 15 and reduce or eliminate your dependency on a server to deliver the best customer experience.
Now, when we think about a server-to-server architecture, this is critical for multiplatform or multiapp services where customers expect to access their services reliably, and your systems are required to keep updated on the status of their purchases at any time in real time.
Typically in this setup, you have your server as the source of truth, where it is online 24/7 to receive and check for updates with the App Store at any time.
But let's look at this flow from your app's perspective.
Here we have the customer's device, and let's assume your app is running using the original StoreKit framework to initiate purchases and using App Store verifyReceipt server for purchase validation.
This means your app sends the Base64-encoded app receipt to your server after a purchase or restore event, and then it's sent to the verifyReceipt server.
The App Store will respond with the customer's transactions, where now your server will need to parse through those transactions to evaluate and determine the status and what actions need to be taken server-side or within your app.
Now, you may have asked yourself this question.
The good news is no, the App Store Server API has no dependency on your app adopting the entire StoreKit 2 framework.
This means you can take advantage of the new functionality available with the App Store Server API right away, all while your app continues using original StoreKit.
Let's walk through how you can do this.
With that same design, you would need to make two primary changes.
First, we'll update your app to retrieve the original transaction ID.
Second, you'll update your server to use the App Store Server API.
These two changes allow your app to use original StoreKit or StoreKit 2, making it easy to support the latest app version on any iOS version.
To do that first change and start using the original_transaction_ID going forward, you will replace your logic that retrieves the Base64 app receipt.
To do this, you may have been using the app receipt URL method.
Go ahead and replace it with this property for autorenewable subscriptions.
And for other in-app purchase types, you'll use this similar property.
Now let's update your server to use the App Store Server API.
You'll change from /verifyReceipt to the /History or /SubscriptionStatus URL.
Requests will use JWT for authorization, and you'll use the original transaction ID going forward.
With these completed changes, you no longer have entitlement logic to maintain on your server and you now can use secure JWS signed transactions and have eliminated the need to store app receipts.
So if your app supports older versions of iOS, this gives you a path to take advantage of what App Store Server API has to offer.
Now earlier, we mentioned how StoreKit 2 and the server API handle determining subscription state for you.
Now as a best practice, your app should always determine the subscriber state upon app launch.
Once the state is determined, it can be stored locally and updated as needed.
I want to briefly review these five states we return and the actions you need to take for each, along with some opportunities to consider.
Now it should be noted, a new customer would not have any of these states, and that is a state your app needs to manage as well.
Starting with Active state, this means service should be provided to the customer until their expires date.
Now If you provide multiple levels of service, one opportunity could be to surface an upgrade offer in-app using promotional offers.
Note that such offers should be tailored to the customer based on their past subscription history.
Now when a subscription has fully churned, you will have the state of Expired.
No service needs to be provided and you can merchandise your current subscription offering.
Optionally, you can leverage promotional offers or subscription offer codes to present a win-back offer.
If they resubscribe within 60 days of their expires date, their existing accrued paid days of service will resume towards the 85 percent proceeds rate.
Next is billing retry period.
We all experience billing issues from time to time; credit cards can expire or store credit can be consumed.
These subscriptions were expected to autorenew, but due to their payment method issue, they fell into what we call the billing retry period.
While the subscription is expired and no service needs to be rendered, the customer also doesn't need to resubscribe; they simply need to resolve their billing issue.
We will automatically reattempt to retry and recover the subscription for up to 60 days through various customer communications without any developer action.
But with in-app messaging, you could directly alert the customer to their billing issue and provide a valuable call to action that can deep link the customer to their payment info page to resolve.
Next is grace period, which is related to billing retry but only applies to your subscribers if you have opted in to App Store Billing Grace Period in App Store Connect.
For this state, you will continue providing service with no disruption until the grace period expires date.
If we recover the subscriber during their grace period, they will retain their original billing cycle.
Therefore, they have no disruption in service and the provider avoids any lost billable days.
Now just like billing retry, you also want to provide that same in-app messaging to alert them to their billing issue.
Lastly, when you see the Revoked state, this applies to a subscription that is family shareable.
These family members are no longer entitled to that service or content, so access can be revoked and you can merchandise offers to reacquire these customers.
In my final portion, I want to dive into some implementation approaches for you to consider when using App Store Server Notifications.
When you look at all these events supported, you can see there are quite a few, and some may or not apply to your business.
Many are part of the subscription lifecycle, while others apply to all in-app purchase types.
If you are not offering a subscription, then your implementation approach is more straightforward, as subscriptions are more complex and you can avoid many of those events that simply don't apply.
But let's review these different phases of implementation for you to consider.
We broke it into three: getting started, supporting the lifecycle, and taking action on insights.
When adopting Version 2, this getting started phase applies to everyone, no matter your business model or if you have or have not already adopted Version 1 notifications.
The first step will be getting Version 2 enabled in App Store Connect.
You'll find this feature under App Information, titled "App Store Server Notifications." And with the Fall updates, now you can choose the URLs specifically for Sandbox and production.
You can add that URL and choose which version to receive.
And if you are receiving Version 1 already, we suggest to only enable Version 2 in Sandbox to allow for development before enabling in production.
Now that we've enabled Version 2, we want to look at the prioritization, so evaluate which notifications to support first based on your business model and usage.
To help, you should focus on key, high-volume events that apply the most to your business and roadmap.
One event that applies to all in-app purchase types are refunds.
You receive a single REFUND notification for each transaction that is refunded to the customer.
How you process those events will be up to your policies and business model.
Now, for subscription-based businesses, these four notifications apply to the primary events in a subscription journey, from initial purchase or resubscribe to a successful renewal, or failure, into expiration.
By prioritizing to take action on these five notification types, means you will have support for the majority of the events that you could receive.
That first phase provides a solid foundation and allowed you to maximize your return.
Now you can look to complete your support of all notification types in this next phase.
There are just a few remaining subscription-based notifications, while the others are dependent upon feature adoption.
Let's review.
These two types apply to all subscription-based apps, DID_CHANGE_RENEWAL_STATUS and preference.
These are critical for identifying a customer cancelling or changing their level of service.
When considering these remaining types, these are dependent upon your usage.
So GRACE_PERIOD_EXPIRED applied if you have enabled Billing Grace Period in App Store Connect.
RENEWAL_EXTENDED is sent if you have extended a subscriber's renewal with the App Store Server API.
And REVOKE applies if products have been enabled for Family Sharing for in-app purchases.
OFFER REDEEMED applies when using subscription offer codes or promotional offers.
And PRICE_INCREASE is sent if the price of an autorenewable subscription has been raised.
And then we have REFUND_DECLINED and CONSUMPTION_REQUEST.
Joe will be covering these in-depth in his part on handling refunds.
Lastly, we can move on to the action on insights phase.
By this point, you are now receiving and taking action on all relevant events for your business.
This ensures your service knows the current status of all customer subscriptions, or any access changes to purchased consumables, nonconsumables, or nonrenewing subscriptions.
With subscriptions, the following notifications identify customers in a very specific state, thus enabling your business to take specific proactive actions where you can identify and intelligently engage, retain, and win back subscribers.
Here are some example notification types where you can identify key events in a window of opportunity to engage with your customers, provide proactive in-app messaging, or present tailored subscription offers.
Let's look at one example: a customer cancelling their subscription.
In this scenario, let's say the subscriber purchased a monthly subscription on November 25.
Then on December 5, the subscriber has chosen to cancel with 20 days remaining in their current period.
This is our save period, from the time the subscriber cancelled to the time the subscription will expire and voluntarily churn.
Now when that cancel action occurs, the autorenew state is set to false, immediately triggering the App Store to send a DID_CHANGE_RENEWAL_STATUS notification with a subtype of AUTO_RENEW_DISABLED, alerting you in real-time to the beginning of a save period.
This window of opportunity allows your service to present tailored in-app messaging or merchandise save offers before their expiration.
It's important such offers are tailored and have eligibility criteria for each customer cohort.
This concludes my portion.
Now I'd like to introduce my colleague, Manjeet.
Manjeet: Thanks, Dave! My name is Manjeet Chawla, and I am a technical program manager at the App Store.
Now, Dave talked about how you can use StoreKit 2 and App Store Server API to improve in-app purchases.
Now, let's review those exact same APIs from a customer support perspective.
I will talk about some common support scenarios that customers face today with in-app purchases and best practices to leverage these APIs for those scenarios.
But before I talk about customer support, let's understand how providing support impacts your overall customer management.
You may be relying on various CRM tools and systems like acquisition, analysis, customer support, and various marketing communication channels.
And providing support keeps your customers happy and engaged with the product and improving your overall customer relationships and satisfaction.
Now we know customers reach out to you for help and the App Store has created tools for you to provide support and resolve issues efficiently.
And today, I will talk about five new customer support tools to assist you with inquiries across all your support channels starting with the Look up Order ID.
Today, when customers make an in-app purchase, they get a receipt sent to their Apple ID and they also can also access this receipt at any time by looking at the purchase history under Account Settings.
And now, when a customer contacts you, your support team can ask the customer for the Order ID on this receipt and call a new App Store Server API to lookup customer's in-app purchases for that receipt by using the order ID.
You can also use this API to validate the authenticity of the receipt and to associate transactions within that receipt to a customer.
Additionally, you can use this API to identify any issues within the purchase.
For example, if the transaction contains any purchases that have already been refunded or revoked by the App Store, you can look at the revocationDate and revocationReason in the response to get more details about the refund.
And once you implement this API, you will be able to look up historical purchases for an order ID when a customer contacts you for support.
For best practices, store the original_transaction_id for all in-app purchases in a customer account database.
And when a customer contacts you for support, you can easily use this API to look up and associate a customer's purchases within your account database.
You can even integrate this API with your existing customer support channels like phone, email, or web to provide a consistent support experience for your customers.
Next, let's talk about Refund Lookup.
In WWDC20, the App Store introduced refund notifications to notify your server each time a customer has been successfully refunded for an in-app purchase.
The Refund Lookup is a brand-new App Store Server API that lets you lookup all the refunded transactions for a customer.
This API enables you to handle server outages or schedule maintenance by looking up refunds at any time in a quick and easy manner.
Additionally, you can identify a customer's entire refund history across all their in-app purchase types.
You can also use this API to monitor any spikes in the refund or suspicious activity, and it can respond to content delivery issues that might be leading to refunds.
For best practices, if you are storing the original_transaction_id for each in-app purchase in a customer account database, you can use any of their original_transaction_ids to look up their past refunds.
And you can troubleshoot any content delivery issues for a customer that might be leading to refunds by using the Refund Lookup API.
Now let's shift gears to talk specifically about autorenewable subscriptions.
For example, a scenario where there was an outage or an event was canceled which might be more common for streaming-based apps such as sports, live TV, or video.
For these outages or canceled events, how can you appease customers? You can now use a new Renewal Extension Server API to extend the renewal date for a paid active subscription and give customers free service for an additional time.
You can use this API to handle temporary outages and also to provide appeasement; for example, when the customer had a bad experience with the service.
Note that you can extend the renewal date for a customer's subscription twice within a year -- each time, up to 90 days -- regardless of the actual subscription duration.
Also note, this extension period does not count towards the one year of paid service needed to receive an 85 percent proceeds rate.
For best practices, store the original_transaction_id to identify the subscriptions you wish to extend the renewal date for.
Identify the extension period that works best for your business model and show in-app messaging when you extend a customer's subscription.
And because there can only be two extensions per customer in a year, you may want to maintain an eligibility criteria for your customers who are eligible for an extension.
And always align with your business and marketing teams to provide a consistent messaging across all your communication channels.
Now let's discuss a different scenario where you may want to compensate a customer by providing a one-time discount for their subscription.
In iOS 14, the App Store introduced subscription offer codes to help you acquire, retain, and win back subscribers by providing a subscription at a discount or free for a limited time.
You can distribute these one-time, unique codes either using online or offline channels.
And for customer service issues, you can provide these one-time codes as compensation for the service issue.
You might also use this as an opportunity to suggest an alternative subscription option; for example, a longer duration plan that provides more value at a lower price.
Customers on iOS 14 and iPadOS 14 and later can redeem offer codes on the App Store through a one-time code redemption URL, or within the app if you've implemented the presentCodeRedemptionSheet API in StoreKit.
Now, for best practices, provide a redemption flow inside the app for customers to redeem the code along with customized in-app messaging and description for the offer code to help customers make an informed decision.
And use this within your existing customer support channels such as phone, email, web, or even within your app, for example, when the customer is chatting with your support team in a live chat session.
Now, if you're distributing these codes on digital marketing channels such as email, each code will have an associated redemption URL with the code prepopulated.
You will be able to use a unique URL to seamlessly deep link the customer from your email into the redemption flow which occurs on the App Store.
This URL is comprised of two values: the ID, which represents your application's ID, so it will be static for each of your applications; and the second value is the code, where you will dynamically populate the URL with the subscribers unique alphanumeric value.
Now, if that URL were embedded in an email, then tapping it would take the user into the App Store to complete the transaction.
Some things to note: the subscriber here never sees the code during this flow, and when completed, it would be another external transaction that your app will need to fulfill when the customer launches the application again.
Next, let's cover a scenario where the customer wants to manage their subscription.
In StoreKit 2, we launched a new manage subscriptions API that enables you to display the existing manage subscriptions right within the app.
Supporting subscription management in-app means customers can upgrade, downgrade, or cancel a subscription without ever leaving your app.
This also gives you a natural place to provide help for common subscriber issues and present alternative offers for customers to consider.
And you can use this opportunity to present a personalized save offer before they see the manage subscriptions page; for example, if their engagement has been low.
Or you can even present an exit survey if they cancel to get more details about the cancellation.
Now for best practices.
Using StoreKit APIs enables you to present a consistent experience that helps people manage or cancel their subscription without ever leaving your app.
Consider creating a branded contextual experience to complement the system-provided management UI.
For example, you might offer a popular premium tier to provide personalized suggestions or alternative plans based on customer's preferences or usage.
And review your overall subscription management experience as it relates to the customer support journey across all your different channels.
Now, let's take a look at a sample Manage Subscriptions UI in your app.
Under Account Settings, we can add an option for the user to manage their subscription.
And once the customer taps this button, the App Store will display the existing Manage Subscriptions page with the currently active subscription and the renewal options.
This is the same view customers are familiar with when they visit Manage Subscriptions under Account Settings in the App Store where they can view, upgrade, downgrade or cancel their subscription.
Now, if the customer selects to cancel their subscription, they will see a confirmation screen with the cancellation details and the service expiration date.
And for any action the user may take on this page, you will receive an App Store Server Notification and your app will be notified if you've implemented the StoreKit 2 framework.
So with the new customer support tools I covered today, let's talk about the benefits of providing support by using these APIs.
You can now improve your overall customer experience by providing contextual and seamless support for in-app purchases right within the app.
This increases overall retention and improves customer satisfaction which leads to higher engagement, and ultimately, more positive ratings and reviews for your app.
Now, I would like to invite my colleague Joe to talk about handling refunds.
Joe: Thanks, Manjeet, for providing best practices and use cases for the new customer support tools that have been launched.
Hi, everyone, my name is Joe Mani, and I'm a program manager at the App Store.
Refunds are a sensitive topic, and the App Store has created tools for you to understand the impact of refunds on your apps and how you can leverage these tools to improve your customer experience.
I would like to highlight the benefits of using these tools and provide a comprehensive message around handling refunds.
This past year, we have launched two new tools that have an impact to refunds.
First, let us discuss the beginRefundRequest API.
The App Store has Report a Problem and Apple Support has established paths for customers to request a refund.
Now in iOS 15, the App Store introduced a new beginRefundRequest API in the StoreKit 2 framework for customers to request a refund for in-app purchases.
There are multiple benefits for you to implement the beginRefundRequest API.
Most of you listening have had a customer who has requested a refund for your in-app purchase.
The new beginRefundRequest API allows you to provide the same functionality without having to redirect customers and provide assistance within the app.
If you are aware of a potential issue with your in-app purchase, you can use this API to help customers troubleshoot the issue and get a faster resolution.
In iOS 15, App Store has created two additional notifications specifically so you can be aware if the refund has been approved or denied.
If the refund is approved, your app will be notified and your server receives a REFUND notification from the App Store.
If the refund is denied, your server receives a new REFUND_DECLINED notification.
Note that customers will have to be on iOS 15 or above to use this functionality.
Let's discuss best practices.
Store the original transaction ID and note that most refund requests occur within 30 days of the purchase.
You can provide custom-built in-app messaging which creates a tailored customer experience even when you may have situations where a customer is frustrated and requesting a refund.
You have flexibility to display contextual information about past purchases to the customer.
Once the customer selects a transaction to be refunded, you can call the API which displays a refund request sheet where a customer can select from a list of reason codes, which is consistent with what they would see in Apple's Report a Problem.
For autorenewable subscriptions, you can identify retention strategies to keep your customer engaged within your app as a successful refund will cancel the subscription.
Now that we looked at the beginRefundRequest, let's talk about what occurs after and how you can be more involved.
The App Store introduced a new server API which gives you the opportunity to help inform and improve the refund process by sending consumption information to Apple about a customer's consumable in-app purchase, such as whether they consumed an item before requesting a refund.
At a high level, each refund request will go through our refund decisioning system to render a decision.
The refund decisioning system includes information about the transaction at issue and other factors such as the customer's purchase and refund history.
Prior to Apple rendering a decision, the App Store will send your server a CONSUMPTION_REQUEST notification.
Your server sends the consumption data back to the App Store in response to this notification, which can influence the refund decision.
The consumption payload consists of a handful of fields and I would like to discuss three of the key fields today.
With Consumption, you can easily tell us if an in-app purchase has been fully, partially, or not at all consumed.
For example, if your app has an exchange platform that has bartering or if an in-app that has been transferred from one account to another's account, it is considered consumed.
With delivering content, you may have experienced outages or unable to deliver in-app purchases and you may want to refund the customer.
Now you can simply provide item not delivered.
With appAccountToken, launched in StoreKit 2, we are using a standard UUID format associated with your app's user account that you create that is initiating the purchase and consuming the content for the purchase, which can help identify resellers.
For best practices, most refund requests occur within 30 days so store consumption data for your transactions accordingly.
Store the original_transaction_ID for each consumable in-app purchase so you can find the transaction for which Apple is requesting the data for.
To ensure Apple incorporates your data for decisioning, respond within 12 hours of receiving the consumption request notification.
Feel free to send an updated payload within those 12 hours if anything has changed after the initial request.
Ensure you have obtained customer consent prior to sending the requested consumption data to the App Store.
And lastly, within the consumption payload, all fields are not required, and please review Apple documentation for which fields can be marked as undeclared.
To summarize today's session, I want to provide a checklist of key actions.
For next steps to adopt and implement these features, you can start configuring and enabling your servers to receive App Store Server Notifications by entering the URL in App Store Connect and enabling Version 2 in Sandbox.
For your customer support tools, integrate within your existing support channels, either it be phone, email, web, or in-app support.
For your app, identify the client changes in iOS 15 with StoreKit 2 needed to support the new beginRefundRequest, isEligibleforIntroOffer, and showManageSubcriptions API.
Lastly, be sure to take advantage of the Sandbox testing updates to make the most of your Sandbox Apple IDs, like storefront change, clearing purchase history, testing refunds, and adjusting the subscription renewal rate.
This concludes the presentation, and thank you so much for joining us today and learning more about supporting customers with StoreKit 2 and App Store Server API.
-
-
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.