Dynamic stripe integration: the one where the documentation doesn’t tell you what to do (Clojure Edition)
If you have a SaaS product that needs to be put behind a paywall, Stripe is usually the most feasible solution. You simply take their APIs, send the payload in the right format, and the integration is painless. But it isn’t so easy when your product doesn’t fit the exact examples within their documentation. And real-life systems are complex. And they still need a paywall. What are we going to do in such a scenario? Well, that’s what we are going to look at in this blog.
We built one such complex product for one of our clients recently. Most simply put, the client wanted a fixed price for a threshold of usage, and a metered unit price for anything beyond that. And they wanted to provide the user with the freedom to choose among a wide range of options to pick a plan based on their budget and requirement. Furthermore, they wanted the flexibility to upgrade or downgrade in the next quarter, however, you were stuck with the existing plan for the rest of the quarter. And of course, you had the option to cancel anytime, which would mean any upgrades/downgrades you’d scheduled for the next quarter would not apply, and your plan would not continue either. Then at the end of the period, you would be billed for any excess usage accrued. The fixed price would have been paid at the beginning of the subscription.
I know, I know. It’s not the easiest thing to explain in one go. So let’s just start simply by looking at the kind of products we’d have on stripe. We’re going to have a much better idea of the use case after this.
The following is an example of a product in the simplest terms. I’ll explain the details later on.
Hey, don’t try to calculate the excess with respect to the fixed price, I made it up for simplicity’s sake. So, to start with, we have a product on stripe called “Plan 1K”, with two different prices, one fixed and one excess. The user has to pay the fixed price at the beginning when they want to subscribe to the product “Plan 1K”, and with this, they get 1000 units of usage for your SaaS product.
When they reach the 1001st usage, the second price kicks in, billing them with a 0.1 euro for every unit they use thereafter. In stripe speak, the excess price considers that the first 1000 units are free. These are billed at the end of the subscription, and sending these usage records is controlled by you, the service provider, with your own native implementation, say a cron job every 12 hours.
Now that we have an example, let’s replicate that so we have three products to switch between.
With the products in place, now we can talk about the subscriptions. Each subscription cycle lasts a quarter, i.e. 3 months, and the user is stuck with the subscription they selected until the end of it. However, they can schedule it to upgrade/downgrade it when they think their usage is going to change, or you know, just for the heck of it.
And of course, the user should be able to cancel the scheduled change at any time and continue with the current subscription. AND be able to cancel the whole subscription, in general, which would be applied at the end of the period.
Say you were in “Plan 1K” in the first quarter, used up 10 units of excess usage, and had scheduled the next plan to be upgraded to “Plan 5K”, then you’d be paying 1 euro for the excess price from the last quarter, and the 400 euros for the fixed price for the next quarter when the switch happens.
Now that we pretty much understand the need, it’s time to get into the solution!
Disclaimer: Please don’t try to run the code as-is, because application-level details have been omitted for the sake of simplicity to focus on what’s important. Use these examples as legos instead, break them apart, and put them where they fit into your needs. ;)
Creating a Subscription
The first thing that we are going to do is create a subscription. Please note that I’m going to skip over the parts regarding customer creation, billing records, etc. at the moment since our focus isn’t that — and it’s pretty much there in the stripe docs.
Since we already have a Clojure library for most things stripe, we are going to leverage that as much as we can.
Creating a subscription is the easiest as we simply send two price ids instead of one! Make sure you send them the right way in the FE as that’s trickier.
Canceling a Subscription
Canceling a subscription is also a walk in the park because it’s a simple call to stripe API saying you’d like your subscription to be canceled at the end of this period. After that, you just sit back, relax, and be sure to send the usage record before the period ends so that you get that money! ;)
I didn’t include the implementation for sending usage records because it’s already in the docs!
Updating a Subscription
This is the trickiest situation we encountered where we didn’t find anything helpful with Stripe docs. Remember that our update would need to be in the future, and we’d be changing products.
We did find this API called Subscription Schedules by Stripe, but it didn’t fully address our needs since we needed to switch between a product, and subscriptions, as a result. But you can check out its use cases to see if that might suit your needs.
Hence, we had to come up with a native solution. And it’s a bit messy, but bear with me. We decided to have an intermediate table in the database called upcoming_subscription
where we sent those new update entries to, set the existing subscription to cancel at the end of the period, and implemented a native scheduler to create a new subscription of values from that table. We, of course, took care of removing the residual values after the subscriptions are created, or not creating duplicates when the user wishes to play around with the future subscriptions for a long while.
Actually, Magnet’s sql-utils
library comes in pretty handy with its insert-or-update
method in these scenarios. And we use our scheduling.twarc
library to take care of our scheduling needs. Be sure to check them out! ;)
And that’s it, our new subscription can now be easily scheduled for the next period! However, make sure that you also send the usage records before you switch subscriptions. I didn’t actually include the usage scheduler and other application-level details here because the scheduler is almost a replica of the one we saw in cancel subscription
and the rest are well, irrelevant, at this point.
Continuing with Existing Subscription
This should be a trivial action as it simply involves telling stripe you don’t want to cancel your subscription at the end of the period anymore, and deleting the entry in the upcoming_subscription
table we made earlier while doing the updates. I wanted to show you how it’s done for completeness.
Et Voilà! There you go, with your fancy application covering all the bases to make sure your users are happy, and so are you because your stripe integration is now complete and there’s nothing between you and you getting your due payment! ;)
If you’re curious about the project structure and the framework we use, check out our Hydrogen platform.