Setting up subscriptions with Spike
One of the available ways to get paid for your product is recurring subscriptions. Your users will be charged automatically every month or year, giving you a more predictable and stable income, while providing your users with continuous usage.
Once set up, your users will be able to easily subscribe, upgrade, switch to yearly/monthly, cancel and resume subscriptions - all from the Spike billing dashboard.
Now let's cover the basics of configuring your subscription plans.
Displaying the subscription view
The subscription view will show up automatically once there is at least one subscription plan set up. You can either add it via config/spike.php
configuration file, or by providing a custom subscription resolver.
Hiding the subscriptions view
If you would like to hide the subscriptions page completely, set the 'subscriptions'
to an empty array:
'subscriptions' => [],
Paid subscription plans
To set up a paid plan, just add the configuration for the plan to the config/spike.php
file within the subscriptions
key. You can add as many paid plans as you wish.
use Opcodes\Spike\CreditAmount;
'subscriptions' => [
[
'id' => 'standard',
'name' => 'Standard',
'short_description' => 'Great for small businesses',
'payment_provider_price_id_monthly' => 'price_xxxxxx1',
'payment_provider_price_id_yearly' => 'price_xxxxxx2',
'price_in_cents_monthly' => 1000,
'price_in_cents_yearly' => 10000,
'provides_monthly' => [
CreditAmount::make(5000),
],
'options' => [
'bonus_features' => true,
],
],
// other plans...
],
Attribute | Required | Description |
---|---|---|
id | yes | Identifier of the subscription plan. Must be unique and not 'free'. |
name | yes | Name of the plan, which will be visible to the user. |
payment_provider_price_id_monthly | yes | Stripe's or Paddle's price_id for the monthly plan. Learn how to set up Stripe products. |
payment_provider_price_id_yearly | yes | Stripe's or Paddle's price_id for the yearly plan.Learn how to set up Stripe products. |
price_in_cents_monthly | yes | Price of the monthly plan in cents. This will be displayed to the user |
price_in_cents_yearly | yes | Price of the yearly plan in cents. This will be displayed to the user |
short_description | no | A short description of the plan, which will be visible to the user |
provides_monthly | no | Array of providables offered by this subscription plan |
options | no | An optional, free-form array that will be accessible when retrieving the user's current plan. Useful for checking whether the user's plan has certain features/options available. |
You might find it helpful to use underscores in numbers as thousands/hundreds separators to make them more visually understanding.
E.g. 10000
credits could become 10_000
which much more clear it is ten thousand.
And 1000
cents could become 10_00
to indicate 10 dollars.
Free subscription plans
Free subscriptions are included automatically, and they are the default for every user. There are no credit usage limitations on free plans by default, but you can customize that easily.
In order to customize the free plan, include the configuration of the free plan in config/spike.php
file with the 'id' => 'free',
like so:
'subscriptions' => [
[
'id' => 'free',
'name' => 'Free',
'short_description' => 'Small amount of credits to try out our product',
'provides_monthly' => [
CreditAmount::make(200),
],
],
],
Archiving old plans
You should not remove any plan configurations that have subscribers already.
Instead, if you would like to remove a particular plan from being available, you can archive it by setting the archived
flag to true
.
'subscriptions' => [
[
'id' => 'standard',
'name' => 'Standard',
'archived' => true, // <== add this line
// other attributes...
],
],
Thank you page
When a user subscribes for the first time, they will be redirected back to the subscription page in Spike. You can redirect from that page to a different page of your choice after any duration of your choice. This will only work on the user's first subscription - switching plans or canceling/resuming subscriptions will not utilise custom redirects.
You can do so by adding this line to your AppServiceProvider::boot()
method:
// Will redirect the user to "/custom-thank-you-page" after 5 seconds.
// Setting the second parameter to zero will redirect instantly without displaying the subscriptions page.
Spike::redirectAfterSubscriptionTo('/custom-thank-you-page', 5);
The first parameter even accepts a callback which will receive the Opcodes\Spike\SubscriptionPlan
instance for the plan the user has chosen, if you need that to build the final redirect URL.
use Opcodes\Spike\SubscriptionPlan;
Spike::redirectAfterProductPurchaseTo(function (SubscriptionPlan $plan) {
if ($plan->isYearly()) {
return "/special-subscriber-thank-you";
}
return null; // `null` value will not redirect anywhere.
}, 5);
Credit distribution with subscriptions
The credits are automatically added to the user's balance whenever the subscription is activated for the first time. On subsequent renewals, and especially for yearly plans, the credits have to be added in the background.
For this reason, you should schedule the spike:renew-subscription-providables
Artisan command to be run at least once a day. Ideally, it would go into your App\Console\Kernel
class:
class Kernel extends ConsoleKernel
{
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('spike:renew-subscription-providables')->everySixHours();
}
When Negative credit balances are allowed, and using Stripe payment provider, this command will also charge for any negative balances. Please run php artisan spike:verify
first to ensure your credit type configuration matches the requirements for doing so.
How Spike handles subscriptions
Below is a short summary of what will happen in various scenarios when handling subscriptions.
New subscriptions
Spike will set up a new subscription and immediately give the user the credits and other providables as configured within provides_monthly
.
It will fire a SubscriptionActivated
event with the new plan.
Switching from monthly to yearly
Switching from a monthly to a yearly (or vice versa) is considered a new subscription. The existing subscription will be replaced with the new one, and both the price paid and the credits given will be prorated.
It will fire a SubscriptionDeactivated
event with the old plan and a SubscriptionActivated
event with the new plan.
An example of prorating:
A user has subscribed to a $30 monthly plan and was given 3,000 credits per month, which is ~100 credits per day prorated. 10 days after being on a monthly plan, the user decides to upgrade to a yearly plan for $300.
The user is charged immediately for the full year ($300) minus a refund for any unused time from the monthly plan ($20). The 3,000 credits they were given are also prorated to 1,000 and expired immediately (they belonged to an old subscription that is no longer active). Because a new, yearly subscription is set up, the user is immediately provided with the configured 3,000 credits again.
Switching from one plan to another
If you have multiple subscription plans with different amount of monthly credits available, then switching between these plans will work exactly like switching between time periods. The existing cost & credits will be prorated and the user will be put on the new plan and charged immediately.
See above for an example of how prorating works in Spike.
It will fire a SubscriptionDeactivated
event with the old plan and a SubscriptionActivated
event with the new plan.
Cancellations
When a user cancels the subscription, it enters the "grace period" - the user can continue using the benefits of the plan, including the allocated credits, until the end of the billing period. At the end of billing period, the user's subscription will no longer renew and the credits will not be renewed.
It will fire a SubscriptionCancelled
event with the paid plan that's being cancelled.
Resuming subscriptions
When users are on the "grace period" of their subscription, they can easily resume those subscriptions, and they will be automatically renewed on their next billing cycle.
It will fire a SubscriptionResumed
event with the paid plan that's being resumed.