BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles In-App Subscriptions Made Easy

In-App Subscriptions Made Easy

Bookmarks

 

Today, when millions of people around the world are searching for their past, MyHeritage has become a leading destination to discover, share and preserve family history. The company’s rich knowledge base includes 2.5 billion family tree profiles along with 4.5 billion historical records, and managed entirely via a comprehensive subscription model. Members with subscriptions can access our research platform, and can find accurate information instantly about their relatives and ancestors.

Until recently, the experience wasn’t complete - our mobile users could not make a purchase through the app, which is a standard when purchasing applications or media. Instead of using their iTunes account, users were required to enter payment details via our online web pages, which were then non-responsive. Subscriptions could only be purchased online, via the company’s web-based billing system.

These days, when 60% of all online traffic comes from mobile devices, implementing In-App purchases was essential to leverage the success and take our business to the next level. As mobile traffic to MyHeritage increased, we decided to provide users with a mobile-friendly checkout process, giving priority for implementing purchases on iOS devices. This project produced an increase of 300% in mobile purchases within one year.

As a billing team member, I thought I’d seen it all. We have multiple types of subscriptions: recurring, non-recurring, free-trial periods, various billing cycles and any possible billing variation one can imagine. But with lack of information online (mainly on the server side), we discovered that mobile subscriptions behave differently from what we expected. This article will share what we have learned, and will make your life somewhat easier when addressing In-App subscriptions implementation.

The Basics

The first and most important thing to clarify: In-App subscriptions cannot be compared to purchases made with any other payment processor. In most processors, a purchase is handled by making an API request to the processor’s server, providing the payment details. Upon a successful transaction, a subscription is granted for the user.

With mobile payments in Apple, a change of mindset is necessary:

The mobile user is paying directly to iTunes. As a result, the backend server will understand that a payment event occurred only in retrospect.

First, the product needs to be defined at iTunes Connect, where your app is managed. The basic definitions contains an identifier for the product, its name and description in some 30 languages (no, it’s not dynamic), and various billing aspects - price tier across different currencies, plan duration, recurring basis, cycle type and free-trial period.

Second, it is necessary to understand the basic flow for making a subscription purchase. In a nutshell, here’s how it goes:

  1. The mobile app requests the available products a user can purchase. Our backend server receives the request, and returns a list of available subscriptions that were predefined in iTunes with their product IDs.
  2. The app queries Apple for the localized products and prices. Apple responds with purchase offers, in the appropriate language, currency and price.
  3. The user confirms a purchase with his iTunes account. In a successful transaction, the StoreKit notifies the app and provides the purchase token.
  4. The app informs our server about a successful subscription purchase, and sends the confirmation token. The server’s responsibility is to handle the relevant payment actions, such as providing the subscription for the user and saving the token for the next phase.
  5. On a regular basis, web servers query the StoreKit for all active Apple subscriptions, and monitor the subscription status, along with other important billing events such as recurring payments, cancellations and refunds.

Now let’s get into the details on how it works.

Providing a clean RESTful API

We had a great opportunity to build an API for submitting payments. The API had to be thin and abstract, to make it reusable for making payments in several flows, with different payment processors.

We kept in mind the idea of creating an easy-to-expand billing infrastructure, which would work with multiple processors simultaneously, as well as allowing our partners to make payments via our API.

We turned to Family Graph - a secured, OAuth based API we expose both internally and to our partners, along with our developers community. Family Graph API provides uniform representation to the core features of MyHeritage, so all we had to do is enhance it to support billing objects and actions:

(Click on the image to enlarge it)

We provided three main RESTful services:

Providing a list of the available products for a user

GET /user-123/products

This is a significant part with In-App subscriptions, when we filter only the specific products the user is allowed to purchase. This may vary due to the current context, the user’s existing subscriptions and other user characteristics. We may offer several Apple subscriptions, with different cycles (monthly, annual, etc) and free-trial periods – each representing a different iTunes product. After determining the current applicable subscriptions, we hand the mobile device the iTunes product IDs. Saving these static IDs in the server is highly recommended, as it gives you more flexibility than storing them at the app itself.

(Click on the image to enlarge it)

Creating an order and adding items

POST /user-123/orders
POST /user-123/order-1/orderItems

At this stage, all you know is the product’s list price. As you will remember, the product was defined with a pricing tier, as Apple may change final prices from time to time. Now you have to fetch the updated subscription details from iTunes, including a local description, price and relevant currency. Apple applies the local taxes and provides an updated price to the user, summed with its 30% rev-share. The user now sees the final price, with a subsequent amount for recurring subscriptions. After the user selects a specific subscription, they add it to the cart, in addition to the other products in which they’re interested.

Submitting a payment

POST /user-123/order-1/payment

The last step is submitting the actual payment. This is done in the app, and confirmed with the user’s unique Apple ID. After a payment is made, the app receives a confirmation token, which is 64-based encoded binary data. The app passes the token and the rest of the payment details to the server. The server then validates the token’s authenticity with the StoreKit “verifyReceipt” API. Once the token is determined to be valid, we’ll make all purchase arrangements and grant the subscription’s privileges to the user, which allows the user to access all data through both his device and the web. Lastly, the token is stored along with Apple’s transaction ID. The importance of this part is seen in the next section.

Monitoring Apple subscriptions

We just completed a purchase and - here’s where the fun begins - it’s time to monitor the various subscription events throughout its lifetime.

In a MyHeritage user case, it is crucial to understand that an In-App purchase is just another way for acquiring an online subscription. Making a mobile purchase grants full access to our online family history services, and vice versa with online purchase. Hence, even when a user removes the app from a device, s/he will still enjoy all subscription benefits on the next online login.

We were looking for server-to-server instant payment notifications (IPNs), to receive immediate information about payment events. As expected, a notification is sent to the mobile app when such event occurs. But what happens if the application is offline at the moment? What if the user has turned off his phone or uninstalled the app?
We have to be sure we’re not missing important actions such as a user opting-out of the next renewal or a refund issued by Apple. Moreover, as a recurring payment is expected after the current period ends, we must identify the renewal immediately to infer that extra money was transferred and extend subscription privileges.

With our needs, and with minimal documentation found online, we conducted our own research and came up with a server-to-server query solution. To be perfectly aligned with the subscription status at all times, we chose to do it the hard way - pull information on every single subscription as often as possible. We didn’t want to provide free service to a refunded subscription, and had to know as quickly as possible if an automatic renewal occurred. So let’s dive into the implementation details.

The subscriptions daemon

We decided that the server will pull subscription information from Apple on a daily basis, under the assumption that we may give the user up to one day of free subscription.

Here’s how payment events are monitored by our servers:

Basically, we have a queue of subscriptions, waiting to be monitored. Every day we iterate through them all, build the relevant request and invoke Apple’s “verifyReciept” API for each subscription. Now comes the analysis of payment events, which will be explained later in detail. After deducing that a payment event has occurred, an event is sent to the proper payment system for further handling. For instance, the subscription is extended on a recurring payment, and cancelled following a refund.

Analyzing the receipt

As mentioned above, the lack of information online made it difficult to understand the behavior of Apple subscriptions. Let’s start with a few basic terms:

  • Token – represents iTunes payment details. When a user purchases a subscription, the token is returned to the device and must be stored for future queries. When pulling subscription information from iTunes, the token is the only relevant input.
  • Original_transaction_id - represents the first payment that was made for the subscription. All recurring payments will have the same value as their original transaction ID.
  • Transaction_id – represents a specific transaction, uniquely identifies the processed payment. If several recurring payments were made, multiple receipts are returned, with different transaction IDs.

Now, after we know how the flow works, this is how we analyze Apple’s response:

  • Identifying renewals:
    Apple handles renewal of subscriptions automatically, without the involvement of the merchant or the customer. The process starts 10 days prior to the renewal, when Apple begins checking various issues regarding the payment, and notifies the user if there is any problem. Technically, the “purchase_date” field of the response will be modified upon renewal, with the recurring payment date. You’re looking for the last transaction when its “original_transaction_id” is equal to the transaction received from Apple when submitting the original payment. Since the same user can purchase different subscriptions, this is a crucial part of analyzing Apple’s response. After the recurring payment is identified, we handle it internally by extending the subscription. This is done by dispatching a “subscription renewed” event and processing it in our own billing systems.
  • Identifying refunds:
    A refund can be issued to the customer by Apple’s customer service, if the user makes a strong claim about his intentions purchasing this product. The merchant is unaware of the process. By analyzing the response, we can identify a refund in the “Cancellation_date” field, which will be set with the date the refund was made.
    Apple treats a cancelled receipt as if no purchase was ever made. In this case, we'll send the “subscription refunded” event and withdraw the subscription.
  • Identifying opting-in or out:
    The user may opt-out from the next recurring payment by turning off the “auto-renew” flag in the App Store. Once doing so, the user can make the reverse opt-in action.
    We'll be able to infer about opting-out of renewal after the current period ends, by checking the “expiration_date” field. We must continue monitoring the subscription even after opting-out was selected, in case a user chooses to again opt-in and renew the subscription.
    A relevant opting-in or out event will be sent to handle the subscription accordingly.

Conclusion

As we have learned, In-App subscriptions are not intuitive and cannot be achieved with a quick win.

If your business sells subscriptions online, the importance of mobile traffic forces you to provide the complete purchase experience on mobile devices. Hopefully, this article has clarified issues somewhat, and will assist you in getting it done faster and cleaner, pushing your business forward to reach new heights.

About the author

Ofir Sharony is a senior member of the MyHeritage Back-End team with expertise in billing. He has been with MyHeritage since 2013. Ofir has a bachelor’s degree with distinctions in computer science and business administration. He acquired most of his 10 years’ experience while working in a technical unit in the army, by planning and developing scalable server-side solutions.

About the company

MyHeritage is the leading destination for discovering, preserving and sharing family history. As technology thought leaders, MyHeritage is transforming family history into an activity that’s accessible and instantly rewarding. Its global user community enjoys access to a massive library of historical records, the most internationally diverse collection of family trees and ground-breaking search and matching technologies. Trusted by millions of families, MyHeritage provides an easy way to share family stories, past and present, and treasure them for generations to come. MyHeritage is available in 42 languages.

Rate this Article

Adoption
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Community comments

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

BT