This blog is about SharePoint, Office365 and Office Development

Popular Posts

Building a Multi-tenant Microsoft 365 App Part 3: Integrate with payment provider

So this is the final part of the thinking out loud type of a guide to build a multi-tenant Microsoft 365 App, if your app is not free you can provide either a one-off license , per user license or per tenant license, I'm not going to go through all the options in details.

In the old world when I used to publish apps on Office SellerDashboard now AppSource via developer dashboard then now Partner centre. There is always two types of apps or actually three, from the store perspective 2 types (paid and free). Most ISVs will use the free option on Microsoft store and they implement their own license model which allow them to decouple it from Microsoft's existing model also they can offer different types of licenses etc..

For me I used to piggyback on Microsoft's licensing model. Why ? firstly I was building mainly free apps and putting it out there for people to use and I only have a single Outlook Add-in I have made paid for just doing a simple market test back in 2015, so I used Microsoft licensing model where I rely on Microsoft licensing etc.

now with Microsoft changing the model as in my humble opinion most ISVs already using their own license model and the current model is relatively a major overhead or maybe some other reason but this is my opinion. So relying on Microsoft to handle your M365 app is not an option, so you better off listing the app as Free and have your own integration with a payment gateway.

My intention was to use a provider that fits both recurring payments (subscription based model) and one off. and most importantly because I'm a very lazy developer something that requires minimum effort.

so I decided to use Stripe and Stripe checkout for the following reasons:

  1. Easy setup , I'm not going through how to setup products and plans, there are heaps of documentation on Stripe website that could provide more detailed and better explanation 
  2. Minimum code (JS mostly, you can even copy the code from Stripe dashboard) 
in less than 10 minutes you can have a stripe checkout integrated to your application, but is it that easy ? the answer is not really when the user click checkout it doesn't guarantee that the payments is correctly processed you have two options here:

  1.  activate your premium features asap, and when the payment is not confirmed remind the user and try again later (which is great allowing user to test your app and maybe pay later)
  2. Switch off your premium features until a successful payment is being processed.
So how can I link the user M365 tenant to the newly created stripe subscription, maybe i need to know if another user within the same tenant has purchased a tenant wide subscription. Stripe checkout offers minimal functionality to customise the checkout data passed, but you can pass tenant ID or user ID if you are offering per user subscription as clientReferenceId as below

the main question is : how to make sure that you know when Stripe has processed payment or not in this scenario ?

Stripe Web-hooks to the rescue 

You can register a set of strip web-hooks to make sure that you listen to Stripe events, in my case I have created an Azure Function (Http triggered) that queue Stripe requests in a queue that have another Azure Function that process the requests, the following is a snapshot listing the events I subscribed to

You might need to subscribe to other set of events, read the documentation carefully but this is what I've selected 

Why 2 Azure Functions?
You might need to sequentially process some of the events prior to the others and because you don't control the order that stripe call your registered webhook it's better to pass them all via a single pipeline.

In my case I was storing stripe events data in a table which lists subscription status and another one for invoices, these two tables are in the "common" storage account , you can decide to move them to specific storage account but you won't be able to completely wipe storage account data without archiving these.

I got side tracked, so I needed to process the CheckoutCompleted event first as it's the only event has the "ClientReferenceID" that allows me to later locate the Tenant and enable/disable the premium features.

in this case I rely on a record of the subscription to be created if I can't find it I'll simply throw exception that makes Azure function retry for 5 times, during this time I would be hopeful that the CheckoutCompleted event is processed.

Is that the best way. Absolutely not but it works and it's super easy the code is below.

Another Thing to Consider if you decided to put these in the common area make sure that you are not breaching any data sovereignty issues.

as you can see the code above ensure that a subscription record has been created first then when invoice processed successfully you can locate your tenant/user object using the clientReferenceID and update it's subscription tier and payment status.

Another thing you need to worry about when your user choosing to change tiers and then you will have to cancel their subscription and create another one, you can choose to continue the billing cycle using the old subscription or prorate the fee to the exact day of switching.

I've been distracted for the past couple of months due to reasons we all know, I hope wherever you are to be safe and I hope we get out of this stronger.

Be Safe