Reputation: 165
I am currently in the process of creating the billing system for my first SaaS. A simple tool to generate videos. There will be a free, mid, and pro tier. The main difference will be the number of minutes you can generate per month. I created 3 Stripe products for the tiers. The free product consists of one price ($0) with a monthly charge interval. The mid and pro tier consists of 2 prices, a monthly and annual charge interval.
When a user signs up for an account, my backend automatically creates a Stripe customer and subscribe it to a free plan. A user can upgrade their account to a mid or pro tier. The plan will be downgraded to a free tier when the user cancels or if the payment failed.
I reset the number of available render minutes after each successful payment, at the start of the billing month. I do this by listening to the successful payment Stripe webhooks. Even when the user is on the free tier, the webhook still gets fired since it is a plan.
The problem is that this method would not work for annual plans. Which made me think that the method that I went for may not be the correct one. Do you know if this is a good method if there is a better one and if there is a workaround for annual subscriptions?
Thank you very much for your time.
Upvotes: 0
Views: 373
Reputation: 333
I'm trying to implement the following solution.
As per stripe documentation, suppose the billing anchor day is 31, for february use the last day of month (28 or 29). https://stripe.com/docs/billing/subscriptions/billing-cycle
So, an algorithm like this: (not tested if it works yet)
$today = Carbon::now()->day;
$lastDay = Carbon::now()->endOf('month')->day;
$anchorDays = [$today];
if ($lastDay === $today) {
for ($i = 1; $i <= 31 - $today; $i++) {
$anchorDays[] = $today + $i;
}
}
$subscriptions = Subscription::where('subscription_interval', 'year')
->whereIn('refresh_day', $anchorDays)
->get();
// reset $subscriptions
So, if you run that on a daily batch (with cron or something), you can check if today is the last day of the month, and in that case, if the day is less than 31 add the days to refresh. Lets say its february 29, you want to reset for 29, 30 and 31. If september 30, you want to reset for 30 and 31. If january 31, you just want to reset for 31.
You still need to figure if the subscription month/year matches to the stripe period_end, in that case you should leave the work to the webhook, but thats just a simple check in the logic.
Upvotes: 0
Reputation: 8747
I think for the annual billing you'll likely want to just set up a cron job or similar that runs daily, and that looks at which annual subscriptions' 'billing day anniversary' (i.e., billing date is Aug 7, so billing day anniversary is the 7th of each month) and resets the counts - unless it is the billing date, in which case leave it to your webhook.
Upvotes: 1