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

knached99's avatar

Stripe Webhooks not working

I'm implementing a stripe checkout for my client who's a limousine booking company. I need to insert data into the database after a successful Stripe transaction but it appears that my webhook is not being called at all. I've been trying to figure this out for 5 hours but couldn't. Any help is much appreciated! As far as code, here is my endpoint in web.php:

Route::post('/stripe/webhook', [StripeWebHookHandler::class, 'handleWebhook']);

Here's my function in my BookingController:

  public function bookRide(Request $request)
{

    /*
    These prices are for if the user selects point-to-point 
    the prices are:
    sedan  add that to the price of the sedan per mile + 20% 
    mini suv: , 
    suv: 0,  
    For the van, no matter what service, the customer needs to call you email notification 

    */
    $admin = User::find(1); 
    $data = $request->only([
        'first_name', 'last_name', 'email', 'phone_number', 'service_type',
        'pickup_date_time', 'pickup_location', 'dropoff_location',
        'num_passengers', 'num_luggage', 'vehicle', 'calculated_distance', 
        'calculated_duration',
        'booster_seat_addon',
    ]);

    $validate = $this->validateBooking($data);

    if ($validate->fails()) {
        return redirect()->route('reservation')->withErrors($validate);
    }

    $product = $this->stripe->products->retrieve($request->vehicle);
    $prices = $this->stripe->prices->all(['product' => $product->id]);
    $price = $prices->data[0]->unit_amount;
    $distance = floatval($request->calculated_distance);
    $totalPrice = 0;
    $surCharge = 0.20; // 20% surcharge 
    // Calculate pricing based on requested pricing model 
    $basePrice = 0; // initialize to 
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Stripe\Stripe;
use Stripe\Webhook;
use Stripe\StripeClient;
use Stripe\Event;

class StripeWebhookHandler extends Controller
{
    protected $stripe; 
    public function __construct(){
        Stripe::setApiKey(env('STRIPE_SECRET_KEY'));
        $this->stripe = new StripeClient(env('STRIPE_SECRET_KEY'));
    }

    public function handleWebhook(Request $request){
        $payload = $request->getContent();
        $event = null;
        try{
            $event = Event::constructFrom(
                json_decode($payload, true)
            );
        }
        catch(\UnexpectedValueException $e){
            return redirect('reservation')->with('EXCEPTION_CAUGHT', 'Unexpected error occurred while checking out');
        }

        // Handle events 

        switch($event->type){
            case 'payment_intent.succeeded':
                return 'PAYMENT_INTENT_SUCCESS';
                break;

            case 'payment_intent.failed':
                return 'PAYMENT_INTENT_FAILED';
                break;
            case 'payment_intent.created':
                return 'PAYMENT_INTENT_CREATED';
                break;
            
            case 'checkout.session.completed':
                return 'CHECKOUT_SESSION_COMPLETED';
                break;
            case 'charge.succeeded':
               return 'CHARGE_SUCCEEDED';
                break;
            case 'charge.failed':
                return 'CHARGE_FAILED';
                break;
 
        }
    }
}
by default switch($product->name){ case 'Sedan': $basePrice = 8000; // 8000 cents is break; case 'Mini Suv': $basePrice = 9000; // 9000 cents is break; case 'Suv': $basePrice = 10000; // 10000 cents is 0 break; } if ($request->service_type == 'Hourly') { if ($request->num_hours < 4 || $product->name !== 'Hourly Service') { return redirect()->back()->withInput()->with('INVALID_HOURLY_SELECTION', "Minimum hours for hourly service must be at least 4, or you have chosen a vehicle other than 'Hourly Service' "); } $totalPrice = $price * $request->num_hours; } else { $mileageCost = $price * $distance; $totalPrice = $basePrice + $mileageCost; $totalPrice +=$totalPrice * $surCharge; } if ($request->booster_seat_addon == 1) { $totalPrice += 2000; // Add for the booster seat addon } $encryptedPrice = Crypt::encryptString($totalPrice); $basePath = config('app.url'); $checkoutSessionId = null; if($product->name === 'Van'){ $data = [ 'bookingID'=>$this->bookingID, 'checkout_session_id' => null, 'name'=>$data['first_name']. ' '.$data['last_name'], 'email'=>$data['email'], 'phone_number'=>$data['phone_number'], 'service_type'=>$data['service_type'], 'pickup_date_time'=>date('F jS, Y \a\t g:i A', strtotime($data['pickup_date_time'])), 'pickup_location'=>$data['pickup_location'], 'dropoff_location'=>$data['dropoff_location'], 'num_passengers'=>$data['num_passengers'], 'num_luggage'=>$data['num_luggage'], 'calculated_distance'=>$distance, 'calculated_duration'=>$request->calculated_duration, 'booster_seat_addon'=>$data['booster_seat_addon'] ? TRUE : FALSE, 'total_price'=>0.00, 'vehicle'=>$data['vehicle'] ]; Notification::route('mail', env('MAIL_FROM_ADDRESS'))->notify(new VanBooked($this->bookingID, $data)); Notification::route('mail', $request->email)->notify(new QuoteRequired($this->bookingID, $data)); Bookings::create($data); return redirect('limo-booked?name='.$data['name'].'&email='.$data['email'].''); } $checkout_session = $this->stripe->checkout->sessions->create([ 'payment_method_types' => ['card'], 'line_items' => [[ 'price_data' => [ 'currency' => 'usd', 'product_data' => [ 'name' => $product->name, 'images'=>[$product->images[0]], 'description' => $product->description, ], 'unit_amount' => intval($totalPrice), ], 'quantity' => 1, ]], 'mode' => 'payment', 'success_url' => $basePath . ':8000/booking-success?name='.$request->first_name.$request->last_name.'&email=' . $data['email'] . '&price=' . $encryptedPrice.'&reference_id='.uniqid().'', 'cancel_url' => route('reservation'), ]); $data = [ 'bookingID'=>$this->bookingID, 'checkout_session_id' => $checkout_session->id, // Use the ternary operator to set the value 'name'=>$data['first_name']. ' '.$data['last_name'], 'email'=>$data['email'], 'phone_number'=>$data['phone_number'], 'service_type'=>$data['service_type'], 'pickup_date_time'=>date('F jS, Y \a\t g:i A', strtotime($data['pickup_date_time'])), 'pickup_location'=>$data['pickup_location'], 'dropoff_location'=>$data['dropoff_location'], 'num_passengers'=>$data['num_passengers'], 'num_luggage'=>$data['num_luggage'], 'calculated_distance'=>$distance, 'calculated_duration'=>$request->calculated_duration, 'booster_seat_addon'=>$data['booster_seat_addon'] ? TRUE : FALSE, 'total_price'=>$totalPrice, 'vehicle'=>$data['vehicle'] ]; return redirect()->away($checkout_session->url); $webhookEventType = $webhookHandler->handleWebhook($request); switch($webhookEventType){ case 'PAYMENT_INTENT_SUCCESS': case 'PAYMENT_INTENT_CREATED': case 'CHECKOUT_SESSION_COMPLETED': case 'CHARGE_SUCCEEDED': Bookings::create($data); Notification::route('mail', $data['email'])->notify(new ServiceBooked($data)); $admin->notify(new LimoBooked($data, $admin->name)); break; case 'PAYMENT_INTENT_FAILED': case 'CHARGE_FAILED': return redirect('reservation')->with('EXCEPTION_CAUGHT', 'Something went wrong while processing your transaction'); break; } }

I have also imported the stripe webhook controller into my BookingController class like so: use App\Http\Controllers\StripeWebhookHandler;

Here is my stripe webhook handler class:

LARACASTS_SNIPPET_PLACEHOLDER
0 likes
32 replies
Snapey's avatar
Snapey
Best Answer
Level 122

is your webhook publicly accessible?

have you added it to the except array in verifycsrf middleware?

is the route permitted for guest access?

Does the stripe console show that they tried to send a webhook?

knached99's avatar

@Snapey I have a publicly accessible stripe web hook however I’m testing first locally so I installed the stripe CLI and followed this documentation here https://stripe.com/docs/webhooks

After stripe checkout, I get a successful 200 response code in the stripe CLI but it doesn’t seem to hit the endpoint. The endpoint I’ve forwarded to is localhost:8000/stripe/webhook

knached99's avatar

@snapey

The route in my web.php file that is hitting the stripe webhook endpoint is this:

Route::post('/stripe/webhook', [StripeWebHookHandler::class, 'handleWebhook']);

For my Stripe CLI, I am running it locally by having it listen to port 8000 like so:

stripe listen --forward-to localhost:8000/stripe/webhook 

After I made a successful transaction (locally), I got this response in the STRIPE CLI:

2023-09-26 13:45:41   --> charge.succeeded [evt_3NufKID5FPRVfdY01BkpQ3Hp]
2023-09-26 13:45:41   --> payment_intent.succeeded [evt_3NufKID5FPRVfdY01NA4vMjn]
2023-09-26 13:45:41   --> payment_intent.created [evt_3NufKID5FPRVfdY017gJA0oT]
2023-09-26 13:45:41   --> checkout.session.completed [evt_1NufKKD5FPRVfdY0w8u16A80]
2023-09-26 13:45:41  <--  [200] POST http://localhost:8000/stripe/webhook [evt_3NufKID5FPRVfdY01BkpQ3Hp]
2023-09-26 13:45:41  <--  [200] POST http://localhost:8000/stripe/webhook [evt_3NufKID5FPRVfdY01NA4vMjn]
2023-09-26 13:45:41  <--  [200] POST http://localhost:8000/stripe/webhook [evt_3NufKID5FPRVfdY017gJA0oT]
2023-09-26 13:45:42  <--  [200] POST http://localhost:8000/stripe/webhook [evt_1NufKKD5FPRVfdY0w8u16A80]

For some reason it is not hitting this part of the code after the redirect. I need to have the return redirect above the other code because I need to know what event was returned from the stripe transaction.

Here's the code:

return redirect()->away($checkout_session->url);
    $webhookEventType = $webhookHandler->handleWebhook($request);
    switch($webhookEventType){
        case 'PAYMENT_INTENT_SUCCESS':
        case 'PAYMENT_INTENT_CREATED':
        case 'CHECKOUT_SESSION_COMPLETED':
        case 'CHARGE_SUCCEEDED':
            Bookings::create($data);

            Notification::route('mail', $data['email'])->notify(new ServiceBooked($data));
        
            $admin->notify(new LimoBooked($data, $admin->name));
        break;
    
       case 'PAYMENT_INTENT_FAILED':
       case 'CHARGE_FAILED':
         return redirect('reservation')->with('EXCEPTION_CAUGHT', 'Something went wrong while processing your transaction');
       break;
martinbean's avatar

@knached99 You do realise that if you return, that ends processing in that method, right? No code after that is going to be executed.

You also don’t want webhook handling logic in a controller because the user could close their browser, lost network connectivity, have a power cut, etc after paying but before the controller finishes processing, meaning you’ll have taken their money but not fulfilled their order, and leave you with a—rightfully so—very angry customer.

knached99's avatar

@martinbean You're right, rookie mistake -_- So how would you advise I handle this? I need a way to find out what the event returned was.

knached99's avatar

@martinbean Thank you for that suggestion, would it work even if I'm not using the Laravel Cashier package to handle payments? I am handling one time payments and did everything using the Stripe API

martinbean's avatar

@knached99 With or without Cashier, the process is still the same: you gave Stripe a URL to send webhooks to, and you handle the webhook event in there.

knached99's avatar

@martinbean So basically the workflow is, after the stripe checkout handles everything and the payment processes successfully, it should create a booking in the system DB and send the notifications to both admin and customer.

knached99's avatar

@martinbean I cannot install laravel cashier, I'm getting this error:

PS C:\xampp\htdocs\nanislimo> composer require laravel/cashier
>> 
./composer.json has been updated
Running composer update laravel/cashier
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - laravel/cashier[v1.0.0, v2.0.0, ..., v2.0.8] require illuminate/filesystem ~4.1 -> found illuminate/filesystem[v4.1.0, ..., v4.2.17] but these were not loaded, likely because it conflicts with another require.
    - laravel/cashier[v3.0.0, ..., v3.0.5, v4.0.0, ..., v4.0.3, v5.0.0, ..., v5.0.15] require illuminate/filesystem ~5.0 -> found illuminate/filesystem[v5.0.0, ..., v5.8.36] but these were not loaded, likely because it conflicts with another require.
    - laravel/cashier[v6.0.0, ..., v6.0.20] require illuminate/database ~5.1 -> found illuminate/database[v5.1.1, ..., v5.8.36] but these were not loaded, likely because it conflicts with another require.
    - laravel/cashier[v7.0.0, ..., v7.2.2, v8.0.0, ..., v8.0.1] require illuminate/database ~5.3 -> found illuminate/database[v5.3.0, ..., v5.8.36] but these were not loaded, likely because it conflicts with another require.
    - laravel/cashier[v9.0.0, ..., v9.3.6, v10.0.0, ..., v10.7.1] require php ^7.1.3 -> your php version (8.2.4) does not satisfy that requirement.
    - laravel/cashier[v11.0.0, ..., v11.3.1, v12.0.0, ..., v12.4.2] require php ^7.2 -> your php version (8.2.4) does not satisfy that requirement.
    - laravel/cashier[v12.5.0, ..., v12.14.1] require illuminate/contracts ^6.0|^7.0|^8.0 -> found illuminate/contracts[v6.0.0, ..., v6.20.44, v7.0.0, ..., v7.30.6, v8.0.0, ..., v8.83.27] but these were not loaded, likely because it conflicts with another require.
    - laravel/cashier v12.15.0 requires illuminate/console ^6.0|^7.0|^8.0 -> found illuminate/console[v6.0.0, ..., v6.20.44, v7.0.0, ..., v7.30.6, v8.0.0, ..., v8.83.27] but these were not loaded, likely because it conflicts with another require.
    - laravel/cashier[v12.16.0, ..., v12.17.2] require illuminate/console ^6.0|^7.0|^8.0|^9.0 -> found illuminate/console[v6.0.0, ..., v6.20.44, v7.0.0, ..., v7.30.6, v8.0.0, ..., v8.83.27, v9.0.0, ..., v9.52.15] but these were not loaded, likely because it conflicts with another require.
    - laravel/cashier[v13.0.0, ..., v13.1.0] require illuminate/contracts ^8.0 -> found illuminate/contracts[v8.0.0, ..., v8.83.27] but these were not loaded, likely because it conflicts with another require.
    - laravel/cashier[v13.2.0, ..., v13.6.1] require illuminate/console ^8.0 -> found illuminate/console[v8.0.0, ..., v8.83.27] but these were not loaded, likely because it conflicts with another require.
    - laravel/cashier[v13.7.0, ..., v13.8.3] require illuminate/console ^8.0|^9.0 -> found illuminate/console[v8.0.0, ..., v8.83.27, v9.0.0, ..., v9.52.15] but these were not loaded, likely because it conflicts with another require.
    - laravel/cashier[v13.8.4, ..., v13.16.0] require illuminate/console ^8.37|^9.0 -> found illuminate/console[v8.37.0, ..., v8.83.27, v9.0.0, ..., v9.52.15] but these were not loaded, likely because it conflicts with another require.
    - laravel/cashier v13.17.0 requires stripe/stripe-php ^7.39|^8.0|^9.0 -> found stripe/stripe-php[v7.39.0, ..., v7.128.0, v8.0.0, ..., v8.12.0, v9.0.0, ..., v9.9.0] but it conflicts with your root composer.json require (^12.0).
    - laravel/cashier[v14.0.0, ..., v14.6.0] require illuminate/console ^9.21 -> found illuminate/console[v9.21.0, ..., v9.52.15] but these were not loaded, likely because it conflicts with another require.
    - laravel/cashier[v14.7.0, ..., v14.12.7] require stripe/stripe-php ^7.39|^8.0|^9.0|^10.0 -> found stripe/stripe-php[v7.39.0, ..., v7.128.0, v8.0.0, ..., v8.12.0, v9.0.0, ..., v9.9.0, v10.0.0, ..., v10.21.0] but it conflicts with your root composer.json require (^12.0).
    - Root composer.json requires laravel/cashier * -> satisfiable by laravel/cashier[v1.0.0, v2.0.0, ..., v2.0.8, v3.0.0, ..., v3.0.5, v4.0.0, v4.0.1, v4.0.2, v4.0.3, v5.0.0, ..., v5.0.15, v6.0.0, ..., v6.0.20, v7.0.0, ..., v7.2.2, v8.0.0, v8.0.1, v9.0.0, ..., v9.3.6, v10.0.0, ..., v10.7.1, v11.0.0, ..., v11.3.1, v12.0.0, ..., v12.17.2, v13.0.0, ..., v13.17.0, v14.0.0, ..., v14.12.7].

Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.
You can also try re-running composer require with an explicit version constraint, e.g. "composer require laravel/cashier:*" to figure out if any version is installable, or "composer require laravel/cashier:^2.1" if you know which you need.

Installation failed, reverting ./composer.json and ./composer.lock to their original content.

Here's what I have in my composer.json file:

 "require": {
        "php": "^8.1",
        "guzzlehttp/guzzle": "^7.2",
        "intervention/image": "^2.7",
        "laravel/framework": "^10.10",
        "laravel/sanctum": "^3.2",
        "laravel/tinker": "^2.8",
        "livewire/livewire": "^3.0",
        "stripe/stripe-php": "^12.0"
    },
martinbean's avatar

@knached99 Well that doesn’t make sense given you have Laravel 10 in your composer.json file, but then the output is complaining about needing illuminate 9, so you seem to be trying to install an old version of Cashier for some reason.

knached99's avatar

@martinbean I literally clicked on the link you sent me and ran the composer command to install it. I didn’t specify any version, I simply ran composer require laravel/stripe

Snapey's avatar

I wouldn't install cashier unless you want stripe to manage customers and recurring payment plans.

You just need to accept the webhook, verify its signature and parse it to see what it is saying

Snapey's avatar

@knached99 you have to bear in mind that the webhook is asynchronous. It has no existing session, and you cannot send anything back to stripe, or to the user.

When the user starts a transaction, keep a record of it along with the payment intent.

When you get the webhook you can simply update the database state for the transaction with the same payment intent.

Later, you can show the user the state of the transaction.

If the payment is successful you could fire an event to cause other things to happen as a consequence, eg sending emails.

Spatie has a package to validate the payment signature which may help you

knached99's avatar

@snapey As I said before, I have a separate controller handling the Stripe webhooks. Should it not be a controller? I just need an example or let me know how I can fix my code to make it work

Snapey's avatar

@knached99 yes use a controller.

Its a http request and expects a 200 response to say it was received ok

knached99's avatar

@Snapey As mentioned before, this is my Stripe webhook handler:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Stripe\Stripe;
use Stripe\Webhook;
use Stripe\StripeClient;
use Stripe\Event;

class StripeWebhookHandler extends Controller
{
    protected $stripe; 
    public function __construct(){
        Stripe::setApiKey(env('STRIPE_SECRET_KEY'));
        $this->stripe = new StripeClient(env('STRIPE_SECRET_KEY'));
    }

    public function handleWebhook(Request $request){
        $payload = $request->getContent();
        $event = null;
        try{
            $event = Event::constructFrom(
                json_decode($payload, true)
            );
        }
        catch(\UnexpectedValueException $e){
            return redirect('reservation')->with('EXCEPTION_CAUGHT', 'Unexpected error occurred while checking out');
        }

        // Handle events 

        switch($event->type){
            case 'payment_intent.succeeded':
                return 'PAYMENT_INTENT_SUCCESS';
                break;

            case 'payment_intent.failed':
                return 'PAYMENT_INTENT_FAILED';
                break;
            case 'payment_intent.created':
                return 'PAYMENT_INTENT_CREATED';
                break;
            
            case 'checkout.session.completed':
                return 'CHECKOUT_SESSION_COMPLETED';
                break;
            case 'charge.succeeded':
               return 'CHARGE_SUCCEEDED';
                break;
            case 'charge.failed':
                return 'CHARGE_FAILED';
                break;
 
        }
    }
}
?>

In the BooingController, the stripe webhook handler is being imported at the top like so: use App\Http\Controllers\StripeWebhookHandler;

This is the bookRide function:

  public function bookRide(Request $request)
{

    /*
    These prices are for if the user selects point-to-point 
    the prices are:
    sedan  add that to the price of the sedan per mile + 20% 
    mini suv: , 
    suv: 0,  
    For the van, no matter what service, the customer needs to call you email notification 

    */
    $admin = User::find(1); 
    $data = $request->only([
        'first_name', 'last_name', 'email', 'phone_number', 'service_type',
        'pickup_date_time', 'pickup_location', 'dropoff_location',
        'num_passengers', 'num_luggage', 'vehicle', 'calculated_distance', 
        'calculated_duration',
        'booster_seat_addon',
    ]);

    $validate = $this->validateBooking($data);

    if ($validate->fails()) {
        return redirect()->route('reservation')->withErrors($validate);
    }

    $product = $this->stripe->products->retrieve($request->vehicle);
    $prices = $this->stripe->prices->all(['product' => $product->id]);
    $price = $prices->data[0]->unit_amount;
    $distance = floatval($request->calculated_distance);
    $totalPrice = 0;
    $surCharge = 0.20; // 20% surcharge 
    // Calculate pricing based on requested pricing model 
    $basePrice = 0; // initialize to LARACASTS_SNIPPET_PLACEHOLDER by default 
    switch($product->name){
        case 'Sedan':
            $basePrice = 8000; // 8000 cents is   
        break;

        case 'Mini Suv':
            $basePrice = 9000; // 9000 cents is 
        break; 
        
        case 'Suv':
            $basePrice = 10000; // 10000 cents is 0
        break;

    }
    

    if ($request->service_type == 'Hourly') {
        if ($request->num_hours < 4 || $product->name !== 'Hourly Service') {
            return redirect()->back()->withInput()->with('INVALID_HOURLY_SELECTION', "Minimum hours for hourly service must be at least 4, or you have chosen a vehicle other than 'Hourly Service' ");
        }

        $totalPrice = $price * $request->num_hours;
    } else {
        $mileageCost = $price * $distance; 
        $totalPrice = $basePrice + $mileageCost;
        $totalPrice +=$totalPrice * $surCharge;
    }

    if ($request->booster_seat_addon == 1) {
        $totalPrice += 2000; // Add  for the booster seat addon
    }

    $encryptedPrice = Crypt::encryptString($totalPrice);
    $basePath = config('app.url');
    $checkoutSessionId = null;
    

    if($product->name === 'Van'){
        $data = [
            'bookingID'=>$this->bookingID,
            'checkout_session_id' => null, 
            'name'=>$data['first_name']. ' '.$data['last_name'],
            'email'=>$data['email'],
            'phone_number'=>$data['phone_number'],
            'service_type'=>$data['service_type'],
            'pickup_date_time'=>date('F jS, Y \a\t g:i A', strtotime($data['pickup_date_time'])),
            'pickup_location'=>$data['pickup_location'],
            'dropoff_location'=>$data['dropoff_location'],
            'num_passengers'=>$data['num_passengers'],
            'num_luggage'=>$data['num_luggage'],
            'calculated_distance'=>$distance,
            'calculated_duration'=>$request->calculated_duration,
            'booster_seat_addon'=>$data['booster_seat_addon'] ? TRUE : FALSE,
            'total_price'=>0.00,
            'vehicle'=>$data['vehicle']
        ];
        Notification::route('mail', env('MAIL_FROM_ADDRESS'))->notify(new VanBooked($this->bookingID, $data));
        Notification::route('mail', $request->email)->notify(new QuoteRequired($this->bookingID, $data));
        Bookings::create($data);
        return redirect('limo-booked?name='.$data['name'].'&email='.$data['email'].'');
    }

   

    $checkout_session = $this->stripe->checkout->sessions->create([
        'payment_method_types' => ['card'],
        'line_items' => [[
            'price_data' => [
                'currency' => 'usd',
                'product_data' => [
                    'name' => $product->name,
                    'images'=>[$product->images[0]],
                    'description' => $product->description,
                ],
                'unit_amount' => intval($totalPrice),
            ],
            'quantity' => 1,
        ]],
        'mode' => 'payment',
        'success_url' => $basePath . ':8000/booking-success?name='.$request->first_name.$request->last_name.'&email=' . $data['email'] . '&price=' . $encryptedPrice.'&reference_id='.uniqid().'',
        'cancel_url' => route('reservation'),
    ]);

    $data = [
        'bookingID'=>$this->bookingID,
        'checkout_session_id' => $checkout_session->id, // Use the ternary operator to set the value
        'name'=>$data['first_name']. ' '.$data['last_name'],
        'email'=>$data['email'],
        'phone_number'=>$data['phone_number'],
        'service_type'=>$data['service_type'],
        'pickup_date_time'=>date('F jS, Y \a\t g:i A', strtotime($data['pickup_date_time'])),
        'pickup_location'=>$data['pickup_location'],
        'dropoff_location'=>$data['dropoff_location'],
        'num_passengers'=>$data['num_passengers'],
        'num_luggage'=>$data['num_luggage'],
        'calculated_distance'=>$distance,
        'calculated_duration'=>$request->calculated_duration,
        'booster_seat_addon'=>$data['booster_seat_addon'] ? TRUE : FALSE,
        'total_price'=>$totalPrice,
        'vehicle'=>$data['vehicle']
    ];
    
    return redirect()->away($checkout_session->url);
   // $webhookEventType = $webhookHandler->handleWebhook($request);
    // switch($webhookEventType){
    //     case 'PAYMENT_INTENT_SUCCESS':
    //     case 'PAYMENT_INTENT_CREATED':
    //     case 'CHECKOUT_SESSION_COMPLETED':
    //     case 'CHARGE_SUCCEEDED':
    //         Bookings::create($data);

    //         Notification::route('mail', $data['email'])->notify(new ServiceBooked($data));
        
    //         $admin->notify(new LimoBooked($data, $admin->name));
    //     break;
    
    //    case 'PAYMENT_INTENT_FAILED':
    //    case 'CHARGE_FAILED':
    //      return redirect('reservation')->with('EXCEPTION_CAUGHT', 'Something went wrong while processing your transaction');
    //    break;

    // }
  
}

How can I use it in my bookRide() function?

martinbean's avatar

How can I use it in my bookRide() function?

@knached99 YOU DON’T.

Stripe will make a POST request to your server in the background. Your server should respond to that webhook in the background. Stripe will then redirect the user to your success_url once the checkout session is complete.

I did explain all this above…

knached99's avatar

@martinbean I understand that now, thank you, however if I cannot use that function in my bookRide() function, how can I pass the data from the bookRide() function in order to insert the data into the DB and send the notification to the customer?

Snapey's avatar

@knached99 you are still missing the point

when you send

return redirect('reservation')->with('EXCEPTION_CAUGHT', 'Unexpected error occurred while checking out');

Why are you trying to send stripe to another page? They are not the user.

Your webhook handler is in no way connected to what the user is doing, so why would you need it in your booking controller?

Imagine...

The user and their booking are being managed by your right hand.

At somepoint there is a knock at the door, and your left hand goes to answer it. Its stripe. They say some random transaction was successful. Your left hand says thanks stripe, I will leave a message for my right hand. They write a note and put it in the clients file. Some time later, righthand can see the note that was left and know that the booking is fully paid for.

martinbean's avatar

if I cannot use that function in my bookRide() function, how can I pass the data from the bookRide() function in order to insert the data into the DB and send the notification to the customer?

@knached99 Again, you don’t. That’s the entire point of the webhook handler.

The webhook payload Stripe will send you will contain all the information from the checkout session: the customer, what they bought, etc. You then use that information to fulfil the purchase for the customer.

knached99's avatar

@snapey and @martinbean Thank you for the explanation. The Stripe API docs weren't clear. So the thing is I don't want to notify the customer or insert data into the DB unless the transaction was successful. How can I accomplish this?

knached99's avatar

@martinbean I get that but what I'm trying to understand is you said that I don't need to call the handleWebhook() function in my bookRide() function. How can I pass the data from the bookRide() function into the handleWebhook() function?

martinbean's avatar

How can I pass the data from the bookRide() function into the handleWebhook() function

@knached99 OMG. You don’t.

Your bookRide method redirects to Stripe checkout. When the customer submits their details, Stripe will send a webhook to your webhook handler. If your webhook handler returns a successful response (i.e. 200 OK), then Stripe will redirect the customer from the Stripe checkout to your success_url.

Your webhook handler knows nothing about controllers, and your controllers know nothing about the webhook handler. Stop conflating the two.

knached99's avatar

@martinbean I man I’m new to Stripe and this is legit my first time using them. I understand how they work now. My question is should I keep the stripe webhook controller as it is? And should I just insert the Data into the DB and send the notifications before redirecting the user?

knached99's avatar

@martinbean im not trying to redirect the user I understand stripe does clearly lol. So basically I should insert the data into the DB and notify the user before the stripe redirect? Like before this line:

return redirect()->away($checkout_session->url);

Please or to participate in this conversation.