Currently seeking new career opportunities in web development, particularly with Laravel, Hire Me

Stripe API save and process incoming web hooks

David Carr

Stripe API Tutorials Nova Framework

Webhooks are Stripe’s way of informing your application of an event such as a payment has failed or a change.

I’m using Nova Framework not setup with Nova? please read Getting Stripe API setup with Nova Framework

To use webhooks you first need to register your endpoint in Stripe’s Dashboard by going to Once you’ve setup the location to where webhooks will be posted you’ll have access to a signing secret token add that to app/Config/Stripe.php. It will be used to validate incoming requests to ensure the request originated from Stripe.

When using hooks it’s important to validate the request which can be done by first defining your variables. The $secret is the token for webhooks, the $payload is the post request a header will exist to help authenticate the request passing these to Webhook::constructEvent allows you to only deal with valid requests.

If the request fails send back a HTTP status code for 400 otherwise save the request.

I do this by using file_put_contents and passing in a path to where I want a txt file to be created. In this case, I’ve setup a folder called Hooks/Pending located in my Users module. This is better than processing it right away also if something goes wrong you’ve got the request to look back at.

Finally sent back a HTTP status code of 200 this tells Stripe the request has been accepted.

public function webHook()
    $secret     = Config::get('stripe.webhookSecret');
    $payload    = file_get_contents("php://input");
    $sig_header = $_SERVER["HTTP_STRIPE_SIGNATURE"];
    $event      = null;

    try {
        $event = Webhook::constructEvent($payload, $sig_header, $secret);
    } catch(\UnexpectedValueException $e) {
        // Invalid payload
        http_response_code(400); // PHP 5.4 or greater
    } catch(\Stripe\Error\SignatureVerification $e) {
        // Invalid signature
        http_response_code(400); // PHP 5.4 or greater

    //store incoming hooks
    if ($event != null) {
        file_put_contents(APPDIR.'Modules/Users/Hooks/pending/payload-'.date('d-m-Y-h-i-s').'.txt', json_encode($event));

    //set response HTTP code
    http_response_code(200); // PHP 5.4 or greater

At this point every time an event in Stripe is created it will be posted and stored on your server. 

To process these requests setup a cron job that calls a method that will look at the Pending folder read the files process them and move them to a Complete folder.

I have a method called ImportHooks that using foreach and glob to scan my pending folder and read the files, then decodes the files and passed $event->type to a switch statement.

This allows you to choose how to deal with each type of event, below is not the full list of event types but a sub set that I choose to use.

For instance, a payment fails will call the invoice.payment.failed event I can then look at the event and send an email to the customer and the staff to do something about the failure.

Finally, after the switch has run I use rename to actually move the txt from the Pending folder to a Complete folder.

public function importHooks() {

    foreach(glob(APPDIR.'Modules/Users/Hooks/pending/*.txt') as $file) {

        $event = json_decode(file_get_contents($file));

        switch ($event->type) {

            case 'customer.subscription.updated':
                //code for event here 

            case 'customer.subscription.deleted':
                //code for event here 

            case 'invoice.payment_succeeded':
                //code for event here 

            case 'invoice.payment_failed':
                //code for event here 

        //move to complete folder
        $updatedfile = str_replace('pending', 'complete', $file);
        rename($file, $updatedfile);


It’s really important that these files are stored outside of the document root. This ensured only authorized people can see the events. Thankfully with Nova this the default setup only files located in the webroot or asset folders are directly available.

Laravel Modules Your Logo Your Logo Your Logo

Become a sponsor

Help support the blog so that I can continue creating new content!


My Latest Book

Modular Laravel Book - Laravel: The Modular way

Learn how to build modular applications with Laravel Find out more

Subscribe to my newsletter

Subscribe and get my books and product announcements.

Learn Laravel with Laracasts

Faster Laravel Hosting

© 2006 - 2024 DC Blog. All code MIT license. All rights reserved.