Hitting the limits of Stripe
If you have a website that accepts payments, chances are you've heard of Stripe.
If you haven't heard of it, Stripe is the $9 billion company that provides a suite of business APIs with a focus on handling payments. Basically if you want to securely accept credit cards on your website, Stripe can help you do that.
I decided to write this post as we recently hit the limits of what Stripe can handle. What we thought was a simple task, quickly turned into something more complicated.
Thus I thought it would be helpful to share our experience.
Our initial setup
When we first started Big Picture, we had a pretty simple system. Our website is a SASS based product where we charge users a monthly fee to use the service.
We wanted to have a free plan and a few paid plans, with a 14 day free trial for each paid plan.
What this looks like in Stripe
Each plan below is setup on a monthly billing period. Every plan except Idea has a free trial.
When a user signs up, a subscription is created with the plan they chose. Each user's subscription independently handles their monthly billing, trial periods, etc.
Next steps
Our initial setup worked pretty well. Then late last year we launched our new product, Big Picture Intel.
Intel is a service that analyzes your website traffic and is able to identify companies visiting your website in real-time.
Billing is based on how much traffic you want analyzed (sessions per month).
After we released the service, we started off by manually handling signups. Obviously this is not scalable, so after we started to get serious traffic, we decided it was time to integrate Stripe and automate the signup flow.
And this is where things got complicated...
The initial plan
The plan was pretty straightforward. Users already have a base subscription, so Intel would be an add-on feature.
Next, we mapped out some predefined plans based on how much traffic a user wants analyzed.
Users select a plan and get a 14 day free trial. Then at the end of the month we want to send one, simple invoice like this.
Translating to Stripe
With a seemingly simple plan, the next step was to translate this into Stripe's subscription system.
Attempt #1: Add another subscription
After a bit of research, our initial idea was to create a new subscription for the user.
Technically this would work, but we discovered that subscriptions in Stripe are independently managed.
That means if there are two subscriptions, users will get two separate invoices every month. Not ideal...
Attempt #2: Add a subscription item
With the goal being one, simple invoice, I contacted Stripe support as I could not find an answer in their documentation.
Marty from Stripe was happy to help.
When the customer wants to add the new plan, rather than creating a new subscription for the customer, you can add the plan to the current subscription and add a new trial period to it.
You would use the create a subscription item call...
Basically he explained that the Intel plan could just be added to the existing subscription as a subscription item.
Perfect!
This will ensure there's only one invoice as both plans are on the same subscription. Then we can define the trial period for Intel and that seemingly will all be handled accordingly.
With a plan in place, we got to work. A few days later, we had a working system. A user could add the Intel plan to their subscription, a free trial was initiated, and there was one invoice.
If it were only that easy...
Up to this point, we had been using a test account on the Idea plan (free), then tested adding Intel.
Everything was working as expected.
Then as a last test, we tested using an account on the Launch plan (paid with a free trial).
We expected it to work the same.
Instead, the subscription completely ignored the trial period for Intel and the user was billed immediately.
The problem
We had no idea what was happening here, so I emailed the Stripe team again.
The plan has a 14 day trial configured, yet it's billing immediately....
Stripe's response:
Unfortunately... we don't support having a plan's trial period days apply to only that subscription item rather than the subscription as a whole.
Great...
Basically this means that a subscription can only have one trial defined.
So in our last test, the user already had a free trial for their core plan. Then when we tried to add Intel, the system went,
"Oh you already had a trial, now we're going to bill you immediately."
Attempt 3: $0.01-off forever coupon
Finally support has an idea:
I actually worked out a workaround (albeit slightly complicated)
Here's what they suggested:
- User creates account with you
- Create Subscription to $0.01/month plan with a $0.01-off forever coupon 1
- Going forward, at any point during the billing cycle if a user decides to add a new plan, create a Subscription item to the new plan
- Set the desired trial at the level of the Subscription
We do this to prevent an immediate charge when a Subscription goes from an "unpaid" set-up to a "paying" set-up ↩
Wait, what? A $0.01/month plan?
This is getting so confusing.
After more back-and-forth, it seems this idea won't work either.
We come to learn that a subscription is either in a "trial" state or it isn't.
When "trialling" it won't charge the user for either plan during that period - even if they were already paying for a plan.
Of course we'd love to give our customers an extra free two weeks, but we have bills to pay...
Attempt #4: Dynamic subscriptions
It seems that to have two plans with independently managed trial periods all on the same invoice, the only way to do it is to have two separate subscriptions.
One core subscription for the main user plan (Idea, Launch, etc), and then a "temporary" subscription to manage the Intel free trial.
Once the free trial for Intel ends, we cancel the Intel subscription and then add the plan as a subscription item to the core subscription.
That way, the trials for both plans are handled independently, but everything is on the same invoice at the end of the month.
Okay, let's try it...
After a day or so, we get this to work. But now we have a new problem.
Strangely, this design is now charging the user twice.
First when the Intel subscription was canceled at the end of the free trial, and again when switched over to a subscription item.
Attempt #5: The WTF Coupon
At this stage we're desperate. It's now been about 2 1/2 weeks, and we still don't have a working system.
Finally, I remember Stripe's $0.01/month plan with a $0.01-off forever coupon.
I realize they were probably referring to this scenario we're now experiencing. So I create a coupon called WTF. WTF is 100% free forever.
Can you sense my sarcasm here?
Yet, it finally works!
By adding a coupon during the trial period, this prevents Stripe from billing the user at the end of the trial.
Our billing system summary
User signs up for Big Picture and chooses a plan. A core subscription is created.
User signs up for a trial of Intel. We create a new subscription with the Intel plan they chose, then apply the WTF coupon.
When the trial is over, if the user does not have billing set up, we cancel the subscription.
If the user has billing setup, we will cancel the subscription, then create a new subscription item on the core subscription. This ensures there is one invoice at the end of the month.
Lastly, for some reason Stripe automatically creates a $0 invoice during the trial period... So to avoid having any users see our WTF coupon magic, we have to filter that out before returning those invoices to the user.
Closing
If you made it this far, I'm honestly surprised.
Billing is boring to begin with. Then the challenges we faced made things exponentially worse.
With so many other high-priority items to work on, it was exasperating to spend three weeks on a seemingly simple issue.
I really appreciate the help from Stripe in helping us figure this out, but a $0.01/month plan? Really?
I thought the whole point of Stripe was to keep billing simple.
I can't imagine I'm the only one to experience a scenario like this?
All we wanted was one invoice...