The account has many subscriptions, only one of which can be the current. The subscription is linked to a plan.
When a customer upgrades, the current subscription ends, and is replaced by a new one. Tracking start and end dates helps with churn and upgrade/downgrade metrics reports, such as time on premium before downgrade etc.
I've also been stung before by checking for a specific plan, as opposed to checking for the abilities or attributes of the current plan. In your example you're checking if the plan name is "trial" to determine if they should have trial limitations put upon them. This becomes tricky if you need to introduce a new trial option, named differently in the future, that needs to co-exist with your current single trial plan set up. I'd prefer to be checking "is the current plan a trial" or ideally link them to a real plan, but check if it is "in trial" (via dates, boolean etc).
I've seen (but not done myself) products that let you move up and down between plans during trial so you can really assess the impact of not having feature available on higher plans. Doing this is impossible with a single plan called "trial".
Subscription billing, dunning, pro-rated upgrade, taxes, discounts etc is a ridiculously complex set of functionality.
Also ProfitWell plugs in to Stripe and does a pretty good job with analytics for that for free too.
Of course if you're using multiple payment providers you'll want to roll your own abstraction as the above comment describes.
Eventually you'll want to find out what your resubscribe rate is, or what the average interval between subscriptions is. Answering these types of questions via Stripe's API is no fun.
All billing dunning etc. is done by Stripe billing at this stage.
Downgrading would put them over a tier limit, so they can't be automatically downgraded unless they first delete enough stuff to be within the next tier limit down. Then I suppose they need to get a credit on their account or a refund etc. But do they get new pricing or are they still grandfathered or what?
Not to mention if they are a South African customer their invoice needs to display the VAT subtotal in Rand and Stripe etc don't cater to that. That's on you.
This stuff becomes kinda nasty when the edge cases stack up and there isn't anything in the market that handles it all beautifully.
That'd make all our lives a lot easier. SaaS billing still sucks.
It's good to see some discussion on how to handle some of this stuff. Information is really thin on the ground.
I might be wrong but paddle.com helps you solve exactly that.
They only make sense if you are small in scale. Use them when you are starting out and then build your own after you have a good number of paid users.
The bookkeeping and support for my business was much easier when I used FastSpring. I believe the higher payment processing fee to be worth it.
- By abstracting some of the most volitile aspects of an early app and business logic.. The combinations in which you sell it can greatly increase the speed of iterating through ideas and offerings.
- There is more than one valid way to implement feature flagging. It's good to start somewhere that seems familiar and grow with it.
- One way I like approaching this problem is tying feature flags into sub roles and roles, which tie into subscriptions of plans. Depending on the nature of your app, the previous sentence can be longer, or shorter to allow flexibility in abstraction.
I'd love to hear how others have seen this implemented in their worlds as well!
I've kinda struggled with this while signing up the first 20+ customers (and still am). You sorta figure it out, but it is all custom code tying into frontend and backend routines. Really does prohibit experimentation.
The blog is a way of getting knowledge out there.
Starting off, I've always done the following:
1. Free option with a limited number of queries
2. Premium option with unlimited number of queries and a few "key" features unlocked.
This simplifies development significantly, as all you have to do is track the queries (per hour, day, month, total, etc.). You can also limit routes based on the features.
This has been extremely effective on my website Easy-A.net (https://easy-a.net/), essentially people can view the grade distribution for courses and we estimate the workload.
Pricing is always difficult, and by scaling it based on API hits it's much easier to price. It's essentially pay for use.
I think (as identified in the first line of the article):
> How do you deal with what a user can do on their account in a SaaS app? Can Jane on the "Starter" plan create another widget when she is near the limit of her plan? What if she's a trial user?
If as a SaaS you're typically targeting one customer archetype starting off -- then you should only have two plans. One to get their feet wet, the other to help them dive in.
Mainly because you'll loose conversions without a high price point third plan that acts as an anchor and makes the middle plan seem like really good value.
We arrived at this after many years building multiple products. In all products we built we have just 3-4 plans. All features are included in all plans (including the trial plan). Only the usage amount differs from plan to plan. This makes it so easy to explain to end customers and leaves your engineering team with valuable time to deal with improving product. Further the number of billing related support requests decrease drastically. Your support staff also need less training.
The advantages are many to keep billing simple. This has been our experience. YMMV.
Can you think of any other small things like that that help you massively reduce complexity? I think in the beginning it seriously makes sense to go with the simplest billing possible for as long as you can.
> During our 14 day trial we do not give trial users an SSL secured public dashboard. Due to technical and abuse reasons this only kicks in when you become a paying customer.
I see "technical reasons", but it would make sense to give even trial users a LetsEncrypt certificate. I don't see how issuing TLS could be abused.
Being fairly new to Lets Encrypt and the eco system around it Checkly is mostly being cautious. Having a none SSL encrypted dash for the trial is probably fine.
If this whole process runs super smoothly, we will lift this blockade.
Also, I come from the days where I had to call Verisign in Switzerland and fax in my passport details...
Just want to give the Lets Encrypt integration a bit of a trial period before going 100% in.
However, customers want to have https://status.example.com for their status pages. This is why we need to provide custom SSL certificates using Lets Encrypt.
In fact, we do this for our own SaaS and never had a problem. Our AWS instance is protected by *.mydomain.com SSL cert but we have other servers running on digital ocean etc. that have their own subdomains and their own SSL certs.
The tricky thing for us is to filter out the subdomains that we use (e.g. [blog,status,www]), and prevent our customers from using them as their own custom subdomains with our app otherwise our whole DNS redirection doesn't work.
When I started my SaaS two years ago, I also found it hard to get concrete info about how to design my database scheme to handle multi-tenancy, plans, and billing.
In hindsight, it all seems quite straightforward, but I was sometimes quite lost at the time. Posts like yours would have helped!
It’s difficult to design, and there’s very little good information around. Open source code based like Magento are impenetrable with a ton of tech debt, or they are way too simplified for our purposes.
The model is as follows:
A user pays per site (he can add multiple) and we decided to have all features available to all plans except for pageviews (we supply a search service like Algolia, but better ;-), and a notification service (small persuasive popups) for e-commerce).
We tie a so called 'module' to a site. A module has a product, start date, end date and subscription (FK). When a user signs up he can start a trial for a specific product which in effect creates a module with a start date, end date (now() + trial_length) and an empty subscription (ie. no subscription means trial).
After the trial we redirect to a plan picker (but you can still see reports for instance) and let them choose a plan. All plan meta data comes from Stripe as single source of truth (it sits actually in our db because dj-stripe has cached that using sync and webhooks).
Choosing a plan does the whole CC flow and when we get an OK from Stripe we attach a subscription (payment tied to a plan) to the module and delete the end_date. We set the limit in pageviews and check on the usage every minute using a job. The current usage is also communicated to the customer.
The same check we did with the trial is in place to see if a customer has an active subscription (now < end_date) and if the current_usage < usage_limit.
Upgrading and downgrading is easy: tie a new plan to the subscription and Stripe handles the rest (prorate, new invoice).
Canceling is easy as well: cancel call to Stripe, get the returned end_date and set this on the module.
You also have to think about reactivating the subscription (before the cancelled subscription has ended).
A fews things to consider:
- VAT: we're based in the Netherlands, so we have 4 (2x2) cases: Individual/Company and EU/Non-EU. Based on that we have to charge or charge no VAT, you have to add that yourself in your call to Stripe.
- Expired CC, declined payments: Stripe calls a webhook and you have to handle that in a way that it will (a) change the subscription/module (b) tell the customer
Our model also allows for:
- old/defunct pricing plans by setting the subscription to an old plan
- different/special usage limits for clients using special plans
- payment without CC (e.g. bank transfer) by using out_of_band option on Stripe
I will do a write up soon too on how we deal with Stripe and EU taxes. I found it not THAT hard as people make it out to be.