This episode is for members only

Sign up to access "Build a File Marketplace with Laravel" right now.

Get started
Already a member? Sign in to continue
Playing
27. Handling Stripe webhooks

Episodes

0%
Your progress
  • Total: 3h 32m
  • Played: 0m
  • Remaining: 3h 32m
Join or sign in to track your progress

Transcript

00:00
We've been through the checkout flow, now we need to actually handle the fact that the sale took place over on Stripe, and we're going to do that with a Stripe webhook. For this episode, if you're following along, you're going to need some way to expose your local development server to the world so we can hook this up within Stripe.
00:20
Now, I use expose, but you can use something like ngrok, anything that allows you to run a command and then have your local machine available to the world. So I'm going to show you how to use expose here. We have this downloaded, you can follow the instructions over on the documentation,
00:38
but feel free to use any other solution like ngrok. It's going to work in exactly the same way. Okay, so the first thing that we need to do is go ahead and set up a webhook over on Stripe that when a sale happens, it goes ahead and pings our app.
00:54
So we're going to head over to the developer section while we're under test mode here, and we're going to head over to this webhook section just here. Now, let's go ahead and add an endpoint, and we're going to go and choose the endpoint URL. Now, we don't have any route set up for this yet, but let's go ahead and grab our main app URL
01:13
and then figure out what this should be in here. So this is typically under some sort of webhooks endpoint, and then we're just going to go ahead and say Stripe. So this is the endpoint URL that we're choosing here.
01:26
We can go ahead and set this to HTTPS as well, if the solution that you're using to share your local machine supports HTTPS. So we can tweak this endpoint URL if we need to, but the most important part of setting up a webhook
01:41
when we're working with Stripe Connect is events on connected accounts. The reason for this is that when we make a sale, this is technically happening over on a Stripe Connect account for another user that we've already set up.
01:55
So it's not something that we are taking the money for. It's something that our users are taking the money for, and we're just taking a cut of that. So we need to make sure that we select this event on connected accounts for this to work.
02:08
The next thing we need to do is select the events that we want to happen here. So we're going to go ahead and search in here for checkout, and the two that we want to enable are async payment succeeded and session completed. Now, we're going to listen for session completed and log a sale,
02:26
but you might have an asynchronous payment for different payment types like backs or any kind of slower payment method. We'll talk about them later, but we're going to handle this anyway, just in case. OK, so let's go ahead and add these events, and we're pretty much done.
02:40
We can click add endpoint here, and now any time a customer of ours makes a sale, this is going to go ahead and ping our app at this URL. So to get this working, we're, of course, going to need a root to handle this webhook,
02:53
and then we can run expose or whatever software you're using to test this out. So we're going to go ahead and make out a controller here, and I'm just going to call this stripe webhook controller. By the end of this episode, we'll have this set up.
03:07
So this pings this and just log something to our Laravel log file. Let's head over to our web routes, and we're going to go ahead and register a route for this. We can put this pretty much wherever we want to. Let's just add this in here.
03:20
This responds to a post route, so make sure you set it up as post, and we know this is webhooks slash stripe, and we're going to go ahead and reference that stripe webhook controller that we've just created.
03:30
Now, really importantly, we're going to head over to our middleware section within our app under HTTP, and we're going to go over to the verify cross site request forgery token section, and we're going to go ahead and exclude anything under webhooks because we don't need cross site requests forgery protection,
03:49
but webhooks because it's not a form that we're submitting within our application. OK, so now that we've done that, we're going to go over to the stripe webhook controller, and we're going to roughly fill this out within an invoke magic method.
04:02
The first thing that we really want to do is just verify that our stripe app can actually hit this controller and this route within our app. So we're going to go ahead and grab a payload that we get back from stripe. To do this, we can use the request object in Laravel,
04:19
and we can go ahead and grab the content from that request. What we can then do is go ahead and JSON decode this because we're going to get this through as JSON, and we're going to go ahead and set true in here.
04:32
So this gives us an object back. Now, with this, what we can do is just go ahead and log the contents of the payload out to our Laravel log file. So when we eventually hit this, we'll see this in our log file.
04:43
We're going to head over to Laravel.log under storage and logs and clear everything out in here just so we've got this nice and fresh, ready to see this working. So we're going to go ahead and open up the terminal,
04:54
open up a new tab, and we're going to run expose, assuming you're using this and you have installed. You can see this is running on HTTPS under laravelfarmmarketplace.sharedwithexposed.com.
05:05
So we actually need to adjust our webhook here to account for that because obviously this is not a public URL. So let's go ahead and update the details for this, and we'll change the URL here to that public URL now.
05:19
You'll be able to verify that this is public, of course, by just heading over to your browser and just going ahead and putting that in there, and you should see your app in here.
05:28
OK, so now that we've updated the URL for this, we're going to go ahead and process a sale. So we're going to go through and purchase this product, and we should see that fire over to our app and log that stuff out.
05:40
So let's go ahead and hit pay here, wait for this to go through, and then we'll check our logs. OK, so that looks like it's gone through. The first place that we can check is the actual Stripe webhook page here.
05:51
If we just give this a refresh, we should see that we get a successful webhook sent over to our app. If you are using Expose, you'll also see this in the terminal just here. And sure enough, if we head over to our Laravel log file,
06:05
you can see that the object back from Stripe has been logged to our log file, which is great. So we've got all of this information now that we can use to create a sale within our database
06:16
and maybe notify the user, send an email, all of the stuff that we need to do. Now, ideally, what we want to do is handle the methods separately. So each of the events that get fired within our webhook over on Stripe,
06:31
we probably want a separate method inside of our controller to handle each of them scenarios. Chances are that as your app grows, you're going to add more. So we want to go ahead and add these to separate them out
06:43
and do one thing every time. Otherwise, we're going to end up with a bunch of if statements in here, which is not great. So let's go ahead and just say handle.
06:52
And then we're going to give the full name of the webhook that we get back from Stripe. So this is checkout session completed. So notice that that matches up with the name that we have in Stripe here.
07:06
Checkout session completed. The only thing we need to do is go ahead and replace the dots here and we need to camel case this so it matches our method name and then prefix it with handle.
07:17
That sounds a little bit more complicated than it is. We just need to use Laravel string helpers to build this up. So let's go ahead and create out a method variable here. We know that we want to prefix any event that we get through
07:28
within this payload with handle because that's the name of our method. And then we want to go ahead and take the payload type. And remember, we can reference this over in our Laravel log.
07:39
So if we search for type here, you can see that we've got checkout session completed. And we want to go ahead and remove them dots and replace them out completely
07:49
and then use either camel case or studley case in this case. So we're going to go ahead and use the standard string replace within PHP. And we're going to replace a dot here with an underscore. What we can then do is use Laravel string helper
08:07
and we can use the studley case to get this to work. So just to give you an example of this, let's go ahead and pull the illuminate support string helper in here. If we just take this and go ahead and die dump,
08:21
or we could do this over our home controller or in a tinker session, wherever really. Let's die dump on this and then just add into here in this payload type, checkout dot session dot completed.
08:34
And we know that we're prefixing that with handle. So if we just die dump on handle, like so, we should see this if we just head over to our home controller over here. And that will build up the method name that we expect.
08:49
So you can see that we've got handle checkout session completed. That's the name of our method. So that is what we can call for each of these events that roll in. OK, let's get rid of this from our home controller
09:01
and let's head over to here and start to call this method now that we've built it up from the payload type. So the first thing to do is check if the method actually exists. Let's say method exists.
09:12
And we're going to say this because we are referencing this current controller and we're going to pass in that method. If it does exist, we're going to go ahead and we are going to call this. So we're going to get a response back in here
09:24
and that's going to be calling this. And then we can go ahead and bind in the method that we want to call and we can invoke that by passing in the payload that we get here. So within these methods, we can now accept a payload in
09:40
and do something with the rest of the data. Then we can go ahead and just return that response and we should be good to go. It's a good idea in these cases to if this doesn't exist, just return a empty response. So we're just going to return a new response down here
09:55
and that just comes from eliminate HTTP response. So now what we should do is only when the checkout session completed event gets fired, should we call this method and then do something in here. So this is a little bit boring, but once again, we can go ahead and log called something like that.
10:14
Go ahead over to our Laravel log, clear this out and we'll just quickly go through the checkout process again. So let's go back here and this is expired. So let's go back again and let's go ahead and buy this again.
10:27
So I filled in all them details. Let's go ahead and hit pay and we're redirected back over to our app. Again, if we head over to the Stripe dashboard here, we should see that that was successful. And if we come over to our Laravel log, sure enough, this has been called.
10:41
So now we are only responding to this particular event, which is great. Now, we also chose to handle another event type in here, and that is checkout if we just double check the name of this and we head over to our details. This is checkout async payment succeeded.
10:59
So let's head over here, checkout async and let's just get the casing of that right. Payment succeeded. So the difference between our checkout session completed is this happens when the checkout session has actually completed and the payment has been received,
11:18
which will always be called. But if we use a payment method where the payment hasn't quite been completed, then we are going to get this called at a later date. Now, we're not going to handle that.
11:29
I'm not going to set my Stripe account up to accept any payment methods that are not instant, because ideally we want the payment immediately. But you can use this later to update the sale if the payment does take a little bit of time. This is all in the Stripe documentation as well.
11:46
So if you do want to implement payment methods that take days or weeks, then feel free to go ahead and fill this in. OK, so our webhook handling is now completed, which means that at a later date, we can log a sale in here once someone has successfully gone through checkout.
34 episodes3 hrs 32 mins

Overview

Build a marketplace where sellers can list and sell files, while we take a cut of each sale using Stripe Connect.

We'll cover onboarding users with Stripe Connect, creating products and uploading files, payments, and delivering purchased files to your customers.

Here's everything we'll cover:

  • The Stripe Connect onboarding flow
  • Effortlessly creating products (and uploading files) with Livewire forms
  • Subdomains for your user's marketplace
  • Stripe Checkout for a beautiful, secure payment flow
  • Securely delivering files with Signed URLs in Laravel
  • Showing sales stats on a dashboard
Alex Garrett-Smith
Alex Garrett-Smith
Hey, I'm the founder of Codecourse!

Episode discussion

No comments, yet. Be the first!