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' => [],

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...
],
AttributeRequiredDescription
idyesIdentifier of the subscription plan. Must be unique and not 'free'.
nameyesName of the plan, which will be visible to the user.
payment_provider_price_id_monthlyyesStripe's or Paddle's price_id for the monthly plan. Learn how to set up Stripe products.
payment_provider_price_id_yearlyyesStripe's or Paddle's price_id for the yearly plan.Learn how to set up Stripe products.
price_in_cents_monthlyyesPrice of the monthly plan in cents. This will be displayed to the user
price_in_cents_yearlyyesPrice of the yearly plan in cents. This will be displayed to the user
short_descriptionnoA short description of the plan, which will be visible to the user
provides_monthlynoArray of providables offered by this subscription plan
optionsnoAn 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.

Support

If you have any questions, feedback, or need any help setting up Spike within your project, feel free to reach out to me.