Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

dany68's avatar
Level 15

Cashier schedule downgrade

Hi,

Is it possible to use cashier with stripe to schedule downgrades ? I didn't find any such information in the doc.

I would like that when a user downgrade to a lower plan he still enjoys the pro features until the end of his cycle, and start the new plan after.

Thanks

0 likes
2 replies
LaryAI's avatar
Level 58

To handle scheduled downgrades with Laravel Cashier and Stripe, you can take advantage of Stripe's subscription scheduling features. While Cashier doesn't directly support scheduling downgrades out of the box, you can achieve this by using Stripe's API directly in combination with Cashier.

Here's a step-by-step approach to implement this:

  1. Retrieve the Current Subscription: First, get the user's current subscription using Cashier.

  2. Use Stripe's Subscription Schedule: Create a subscription schedule using Stripe's API. This allows you to specify when the downgrade should take effect.

  3. Set the End of Current Period for Downgrade: Schedule the downgrade to occur at the end of the current billing cycle.

Here's a code example to illustrate this process:

use Stripe\Stripe;
use Stripe\SubscriptionSchedule;

// Set your Stripe secret key
Stripe::setApiKey(env('STRIPE_SECRET'));

// Retrieve the current subscription
$subscription = $user->subscription('default');

// Create a subscription schedule
$schedule = SubscriptionSchedule::create([
    'customer' => $user->stripe_id,
    'start_date' => $subscription->asStripeSubscription()->current_period_end,
    'end_behavior' => 'release',
    'phases' => [
        [
            'items' => [
                [
                    'price' => 'price_id_of_new_plan', // Replace with the price ID of the lower plan
                    'quantity' => 1,
                ],
            ],
            'start_date' => $subscription->asStripeSubscription()->current_period_end,
        ],
    ],
]);

// Optionally, you can store the schedule ID in your database if you need to reference it later
$user->update(['stripe_schedule_id' => $schedule->id]);

Key Points:

  • Stripe API: You need to use Stripe's PHP library to interact with the subscription schedule API.
  • End of Current Period: The start_date for the new phase is set to the current_period_end of the existing subscription, ensuring the downgrade happens after the current billing cycle.
  • Price ID: Replace 'price_id_of_new_plan' with the actual price ID of the plan you want to downgrade to.

Additional Considerations:

  • Testing: Make sure to test this thoroughly in a test environment to ensure it behaves as expected.
  • Stripe Webhooks: Consider setting up webhooks to handle any events related to subscription changes, such as successful downgrades or errors.

By following these steps, you can effectively schedule downgrades using Stripe's capabilities alongside Laravel Cashier.

alinlinca's avatar

@dany68

I also faced this approach. Here's how I solved it. What the bot generated is not correct.

It is worth mentioning that if you don't put start_at and end_at in the second phase, the release will be made after a billing cycle passes. In this case, the release will be made immediately. You can listen to the release event and update the subscription.

	use Stripe\Stripe;
	use Stripe\StripeClient;
	use Stripe\SubscriptionSchedule;
		
	Stripe::setApiKey(env('STRIPE_SECRET'));

    $schedule = SubscriptionSchedule::create([
      'from_subscription' => 'the subscription ID you want to schedule',
    ]);
  
    $schedule = SubscriptionSchedule::update($schedule->id,
    [
      'end_behavior' => 'release',
      'phases' => [
        [
          'items' => [
            [
              'price' => $schedule->phases[0]->items[0]->price,
              'quantity' => $schedule->phases[0]->items[0]->quantity,
            ],
          ],
          'start_date' => $schedule->phases[0]->start_date,
          'end_date' => $schedule->phases[0]->end_date,
        ],
        [
          'items' => [
            [
              'price' => $newPlan,
            ],
          ],
          'start_date' => $schedule->phases[0]->end_date,
          'end_date' => $schedule->phases[0]->end_date + 3,
        ],
      ],
    ]);

First part, "Schedule create" will generate an event "subscription_schedule.created", the second part, "Schedule update" will generate another event "subscription_schedule.updated" and after schedule update it will generate another event that will update your subscription "customer.subscription.updated" where it will fill "schedule" row from payload.

Be careful if you have other limits that you grant on "subscription.update" to handle this situation so as not to reset them when you receive the event generated by the schedule

Please or to participate in this conversation.