To handle delayed Stripe subscription confirmations or declined payments effectively, you can implement a workflow that ensures users do not access premium features until their subscription is confirmed. Here’s a step-by-step solution:
-
Create a Pending State for Subscriptions: When a user initiates a subscription, mark their subscription status as "pending" in your database.
-
Use Webhooks for Real-Time Updates: Stripe provides webhooks that notify your server about events such as successful payments, failed payments, and subscription updates. Set up a webhook endpoint to listen for these events and update the subscription status accordingly.
-
Polling as a Backup: While webhooks are generally reliable, you can implement polling as a backup to periodically check the subscription status.
-
User Feedback: Provide clear feedback to the user about the subscription status. You can redirect them to a "Subscription Pending" page where you explain that their subscription is being processed and they will be notified once it is confirmed.
-
Restrict Access to Premium Features: Ensure that your application checks the subscription status before granting access to premium features.
Here’s a code example to illustrate this workflow:
Step 1: Mark Subscription as Pending
// When user initiates a subscription
$user->subscription_status = 'pending';
$user->save();
Step 2: Set Up Webhook Endpoint
// In your routes/web.php or api.php
Route::post('/stripe/webhook', 'StripeWebhookController@handleWebhook');
// In StripeWebhookController.php
public function handleWebhook(Request $request)
{
$event = $request->input('type');
$data = $request->input('data.object');
switch ($event) {
case 'invoice.payment_succeeded':
$this->handlePaymentSucceeded($data);
break;
case 'invoice.payment_failed':
$this->handlePaymentFailed($data);
break;
// Add more cases as needed
}
return response()->json(['status' => 'success']);
}
protected function handlePaymentSucceeded($data)
{
$user = User::where('stripe_id', $data['customer'])->first();
if ($user) {
$user->subscription_status = 'active';
$user->save();
}
}
protected function handlePaymentFailed($data)
{
$user = User::where('stripe_id', $data['customer'])->first();
if ($user) {
$user->subscription_status = 'failed';
$user->save();
}
}
Step 3: Implement Polling (Optional)
// In your frontend JavaScript
function checkSubscriptionStatus() {
fetch('/api/subscription-status')
.then(response => response.json())
.then(data => {
if (data.status === 'active') {
window.location.href = '/dashboard';
} else if (data.status === 'failed') {
alert('Payment failed. Please try again.');
} else {
setTimeout(checkSubscriptionStatus, 5000); // Poll every 5 seconds
}
});
}
// Call this function on the "Subscription Pending" page
checkSubscriptionStatus();
Step 4: Provide User Feedback
// In your controller
public function showSubscriptionPending()
{
return view('subscription.pending');
}
// In your subscription/pending.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<h1>Subscription Pending</h1>
<p>Your subscription is being processed. You will be notified once it is confirmed.</p>
</div>
@endsection
Step 5: Restrict Access to Premium Features
// In your middleware or controller
public function handle($request, Closure $next)
{
if (auth()->user()->subscription_status !== 'active') {
return redirect('/subscription/pending');
}
return $next($request);
}
By following these steps, you can ensure that users do not access premium features until their subscription is confirmed, while providing clear feedback on the subscription status.