Handling Stripe webhooks in a Laravel application
In the project I'm currently working on I had to integrate Stripe webhooks. Stripe has great documentation on how to handle webhooks, but it still took a fair amount of time to get the integration just right. My solution for handling webhooks is pretty generic and reusable by others. I decided to extract it to a package called laravel-stripe-webhooks, so nobody has to code this stuff up again. In this blogpost I'd like to share how the package works.
Requests will be validated
Whenever an event occurs on Stripe, the service will notify your app by sending a http request to your app. Here's a list of all events Stripe sends out. Stripe will sign all requests it sends to your app. This package will automatically verify if the signature is valid. If it is not, the request was probably not sent be Stripe.
Webhooks are restartable
Before doing any other work, all calls will immediately be logged to the database. This is incredibly valueable when something goes wrong handling a webhook call. You can easily retry the processing of the webhook call, after you investigated and fixed the cause of failure, like this:
use Spatie\StripeWebhooks\StripeWebhookCall;
StripeWebhookCall::find($id)->process();
Handling valid requests
There are two ways this package enables you to handle webhook requests: you can opt to queue a job or listen to the events the package will fire. In both cases we highly recommend queuing the job or queueing the event listener that does some work. By doing that, you can minimize the response time of the webhook requests. This allows you to handle more stripe webhook requests and avoiding timeouts.
Let's take a look at both methods.
Using jobs
Laravel has a handy make
command to scaffold a Job.
php artisan make:job ChargeSource
After that you must let the job accept a WebhookCall
instance in it's handle method.
namespace App\Listeners;
use Illuminate\Contracts\Queue\ShouldQueue;
use Spatie\StripeWebhooks\StripeWebhookCall;
class ChargeSource implements ShouldQueue
{
public function handle(StripeWebhookCall $call)
{
// do your work here
// you can access the payload of the webhook call with `$webhookCall->payload`
}
}
After having created your job you must register it at the jobs array in the stripe-webhooks.php
config file. The key should be the name of the stripe event type where but with the .
replaced by _
. The value should be the fully qualified name of the class.
// config/stripe-webhooks.php
'jobs' => [
'source_chargeable' => \App\Jobs\StripeWebhooks\HandleChargeableSource::class,
],
And with that you job will fire when strips sends out the source.chargeable
webhook.
Using events
Instead of queueing jobs to perform some work when a webhook request comes in, you can opt to listen to the events this package will fire. Whenever a valid request hits your app the package will fire a stripe-webhooks::<name-of-the-event>
. For if a source.chargeable
event hits your app, the stripe-webhooks::source.chareable
event will fire.
Let's take a look at how you can listen for such an event. In the EventServiceProvider
you can register a listener.
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'stripe-webhooks::source.chargeable' => [
App\Listeners\ChargeSource::class,
],
];
Here's an example of such a listener:
namespace App\Listeners;
use Illuminate\Contracts\Queue\ShouldQueue;
use Spatie\StripeWebhooks\StripeWebhookCall;
class ChargeSource implements ShouldQueue
{
public function handle(StripeWebhookCall $call)
{
// do your work here
// you can access the payload of the webhook call with `$webhookCall->payload`
}
}
Like already mentioned above, we highly recommend that you make the event listener queueable.
The above example is only one way to handle events in a Laravel. To learn the other options, read the Laravel documentation on handling events.
In closing
Head over to the readme of laravel-stripe-webhooks on GitHub to learn a few more tidbits about the package. Rest assured that the package contains a suite of tests to make sure everything works correctly.
Because Stripe is quite popular, I can image that a lot of artisans already have written their own implementation for handling webhooks. In my mind it's kind of silly that everybody has to code up the same solution over and over again. If you tackle a problem concerning common stuff consider open sourcing your solution. You will benefit yourself from the public scrutinization of your code (in mean this in a positive way). Your future self will be thankful for the documentation you write for your package. The other members of the community will be saved from writing the same boring code. And we all can get to building the fun and interesting stuff.
If you're in a position in your company to advocate or to actively work on open source, I highly recommend you do so. There are only winners in this story!
That being said, be sure to take a look at the collection of Laravel, PHP and JavaScript packages our team has created:
- https://spatie.be/en/opensource/laravel
- https://spatie.be/en/opensource/php
- https://spatie.be/en/opensource/JavaScript
Pretty sure there will be something there that can be helpful in one of your future projects.
What are your thoughts on "Handling Stripe webhooks in a Laravel application"?