To achieve scheduled plan downgrades (take effect at the end of the current billing cycle) with Laravel Cashier (Stripe), you'll need to work within Stripe's API limitations, as Cashier does not provide a swapNextCycle method with Stripe—the feature exists only in Cashier Mollie.
Here's how you can approach this:
1. Schedule a Downgrade Manually in Code
Cashier's swap() (with or without noProrate()) always switches right away. Since Stripe doesn’t offer a simple "change at period end" method for plan/price, you’ll need to:
- Mark the user's intent to downgrade in your database.
- When the current billing cycle ends (via Stripe's
invoice.payment_succeededWebhook or similar), perform theswap()to the new lower plan. - Notify the user that the downgrade will apply on their next renewal.
2. Example Implementation
Step A: Mark Downgrade Request
Create a column in your users table or subscriptions table (next_plan_id, for example). When the user chooses to downgrade, store the new plan’s Stripe price ID there.
// When the user requests a downgrade
$user = $request->user();
$user->next_plan = $newLowerPriceId;
$user->save();
// Optionally, notify user the downgrade is scheduled.
Step B: Listen for End of Billing Cycle
Listen for the relevant Stripe webhook (e.g., invoice.payment_succeeded or customer.subscription.updated). When the cycle ends and payment is processed:
- Check if a
next_planis set - Swap the subscription to that price
// In your webhook controller:
// Assuming you've set up Cashier's webhooks
public function handleInvoicePaymentSucceeded($payload)
{
$user = User::where('stripe_id', $payload['data']['object']['customer'])->first();
if ($user && $user->next_plan) {
$user->subscription()->swap($user->next_plan);
$user->next_plan = null;
$user->save();
// Optionally, notify the user their downgrade is now active.
}
}
3. Why Not Use Proration or Immediate Downgrade?
- Any swap using Cashier's
swap()operates immediately and, even withnoProrate(), doesn't schedule for the period end. - Stripe's official API does not support scheduling a plan/price change on Subscriptions directly for later.
4. Notes
- You may want to add logic to prevent multiple downgrade requests and to cancel scheduled changes before the invoicing.
- Provide clear UI messaging that the downgrade will occur after the current billing cycle.
Summary:
To schedule a downgrade with Laravel Cashier (Stripe), you must handle it in your own application layer by keeping track of downgrade requests and updating the subscription when the period renews, usually responding to a webhook event.
Let me know if you need help with the full webhook controller code!