How to Integrate Stripe on the Back End
A free video tutorial from Jonas Schmedtmann
Web Developer, Designer, and Teacher
Learn more from the full course
Node.js, Express, MongoDB & More: The Complete Bootcamp 2023
Master Node by building a real-world RESTful API and web app (with authentication, Node.js security, payments & more)
42:10:51 of on-demand video • Updated November 2022
Master the entire modern back-end stack: Node, Express, MongoDB and Mongoose (MongoDB JS driver)
Build a complete, beautiful & real-world application from start to finish (API and server-side rendered website)
Build a fast, scalable, feature-rich RESTful API (includes filters, sorts, pagination, and much more)
Learn how Node really works behind the scenes: event loop, blocking vs non-blocking code, streams, modules, etc.
CRUD operations with MongoDB and Mongoose
Deep dive into mongoose (including all advanced features)
How to work with data in NoSQL databases (including geospatial data)
Advanced authentication and authorization (including password reset)
Security: encryption, sanitization, rate limiting, etc.
Server-side website rendering with Pug templates
Credit card payments with Stripe
Sending emails & uploading files
Deploy the final application to production (including a Git crash-course)
Downloadable videos, code and design assets for projects
Instructor: So in this video let's integrate Stripe into our backend by creating that API endpoint which will create and send back a Stripe checkout session. And so at this point, we're actually gonna start creating our next resource. And so that's the bookings. And I will start here with the booking routes. So booking routes.js. And we've done that so many times now. So then I'm just gonna go ahead copy all of this code and put it here in the booking routes. And then simply remove all of this. And also this one. We also don't need merge params and we will have a booking controller instead of a review controller. So booking controller, let's actually create that. So .js that looks correct and let's also integrate this right into app.js. And so let's put that right here after the review router. So here that's just again bookings and then of course down here integrate that into our API. So bookings and here bookings router. And I think that should only be booking. So let's fix that up here as well. And indeed we call it booking router. And the same here, it's not bookings but booking routes. So give it a save. Close this one and this one and this one here as well. And so now let's actually go ahead and create our first route here. So let's router.get and the route that it will create here will once again not follow the rest principle because this one is not really gonna be about creating or getting or updating any booking. Instead this route will only be for the client to get a checkout session. And so let's actually call this one checkout session. Then we need to protect this route so that only authenticated users can actually get a checkout session. So that makes sense, right? And then add booking controller. We're gonna create a route handler called get checkout session. All right. So let's copy this one and create it here at exports.getCheckoutSession then request responds next. And now let's start working. Now actually there's one more thing we need to do here in the routes which is to specify a URL parameter. And so that's going to be the tour ID. Okay, so basically we want the client to send along the ID of the tour that is currently begin booked. And that is so that we can fill up the checkout session with all the data that is necessary, such as the tour name and the tour price and all that stuff. All right, so we now have access to the tour ID in this handler function and so the first thing that we're actually gonna do is to find that tour in our database. All right, so for that we need of course the tour model. So let's come here to the tour controller and get that from there. Also we're gonna need this catchAsync and so really all of this. So I'm copying all of it and even if I don't need it right away I will probably need it a bit later anyway. All right. So let's layout our steps here again. So get the currently booked tour. Then as a second step, we create the checkout session and then finally send it to the client. All right, so the first step is really easy. So we're gonna wait. So tour.findbyId which is req.params.tourId. Right, so that was the name we gave it in the URL parameter. And of course, this is now an async function with a catchAsync besides that or around that, actually. Great, next up, let's create that session here. And for that we actually need to install this drive NPM package. So let's do that here. NPM install Stripe. And in the meantime we're gonna go to our Stripe dashboard and get our secret key from here. So just hit this button here and then go ahead and copy it. And you see that here in the keys it actually says test. And so again, these ones here are just for testing and then once you have your Stripe account active, you can then get your live API keys. Okay, now as with any other keys we will put them here in our config file. So Stripe secret key equal to this. And this is not correct here. All right, so copy this one. Back to our booking controller. Let's now actually require this drive package with has successfully installed here. And just with all the other packages before please make sure that you're actually on the same version as I am. And you see that I'm here at the brand new 7.0.0. So this is really brand new. And actually that's because a lot of stuff just changed with Stripe a couple of days ago. So I had to change a couple of these implementation. Anyway, const stripe equal require and then stripe. Now this here will then expose a function basically. And usually what we do then right away is to pass our secret key right into that. And so that will then give us a Stripe object that we can work with. So that now at process.env.STRIPE_SECRET_KEY. Okay, and so now let's use that. So we say Stripe.checkout.session.create. And then the usual object of options. All right, now there are a ton of options that we can set here. But only three of them are required. So the first one is the payment method types. So payment method types. So that is an array where we can specify multiple types and card is for credit card. And right now that's actually all the payment options that we can use for Stripe checkout. But I read that in the future they will add a lot more. So you can get informed by that. Then we need to specify the success URL. And so that is basically the URL that will get called as soon as a credit card has been successfully charged. So as soon as the purchase was successful the user will be redirected to this URL. And for now, let's simply specify that as our homepage. All right and we're gonna do that just as before with req.protocol:// and then request.get the host. So basically just our home URL. Then we also need to specify the cancel URL. So just like this. And this one is gonna be similar. And so basically it's the page where the user goes if they choose to cancel the current payment. And actually let's make them go to the tour page where they were previously. And so that is basically tour/tour.slug. Next up, we can also specify the customer email. And so that is very handy because of course we already have access to the customer's email. And so with this we can save the user one step and make the checkout experience a lot smoother. All right so remember that this is a protected route. And so as always the user is already at the request. And so we can say request.user.email. Next up, we can then also specify a custom field which is called client reference ID. And that sounds a bit weird but actually it's going to be really important for us. So this field is gonna allow us to pass in some data about the session that we are currently creating. And that's important because later once the purchase was successful, we will then get access to the session object again. And by then, we want to create a new booking in our database. So remember the diagram that I showed you in the last lecture. Basically what I'm talking about here is the last step in that diagram. And also remember how that is only going to work with deployed websites. But still, let's already prepare for that here. Okay, so to create a new booking in our database we will need the user's ID, the tour ID, and the price. Remember that? And in this session we already have access to the user's email and from that we can then recreate the user's ID because email here is unique. We will also specify the tour's price here in a second and so all that's missing is then the tour ID. And so that's what we're gonna specify here on this custom field basically. So that's called client reference ID. And all of what I just explained before actually is gonna make a lot more sense once we actually implement that last step of creating a booking in the database, right? Anyway, that tour ID is at request.params.tourId. All right, and now finally, we're gonna specify some details about the product itself. So our tour in this case. And so that's called line items which accepts an array of objects. So basically one per item and so in our case that's only gonna be one. So we're to specify the name of the product and so that's at tour.name and as always we also add the tour to that name. Then we can also specify a description. And all these field names here they really come from Stripe. So we cannot make up our own fields. So if you try to do that, you will really get some error. All right, so in the description I will put the tour summary, so that nice short phrase that will describe each tour. Then we can also specify an array of images. Now these images here they need to be live images. So basically images that are hosted on the internet because Stripe will actually upload this image to their own server. And so this is another of the things that we can only really do once the website is deployed. But for now, as a placeholder, I will basically use the ones from our hosted example website on natours.dev. So let's go to that website. So that's this one at natours.dev. And the image that I'm gonna choose is the cover image. So let's inspect that image. So this one here and copy link address here. All right. So this is an array because we can specify multiple images but we really only want one of them. And indeed we have natours.dev/images/tours and then the name of the image. And this one I will simply replace with tour.image cover. And that's gonna work because the names of the images on natours.dev are exactly the same as we have here in our project. So tour.imageCover. So this is one more thing that we actually need to change once we put our website into production. And I'm keeping actually a list of that stuff so that we don't forget anything. Anyway, next up is the amount. So basically the price of the product that is being purchased. So that is tour.price and now we need to multiply that by 100. Because this amount is expected to be in cents. And so one dollar or one Euro or really most of the currencies have 100 cents. So one dollar equals 100 cents. And so to convert it to cents, just multiply it by 100. Then we also need to specify the currency. And so that's in this case USD. But it could also be like, for Euro it's EUR and for other currencies, you should probably take a look at the documentation. So of course I cannot cover all the currencies that there are, right? Anyway, finally we also specify the quantity. And so that's just one tour in this case. So that's actually it. And so basically this part here is the information about the session itself. And then here is the information about the product that the user is about to purchase. All right, now let's actually store the session. So const session and now we to await this. So this create here basically returns a premise because setting all these options here will basically do an API call to Stripe and so then of course that's an asynchronous function that we should await here. Okay, but anyway this is now our session and so the last step is of course to send it back to the client. So as always, the status is success. And then let's simply send the session like this. All right, so that should actually be it. Our router is already configured and so I think we could actually now try this out in postman. All right, now later of course we will not allow anyone to do this using postman because that doesn't make much sense. But now since we're only testing this it actually makes a lot of sense. All right so let's head over to postman and create a brand new request. So that's gonna be at bookings/ uh, I'm not really sure. Yeah, so checkout session and then /tourId. All right, so let's get our tours here. To get the ID from there basically. So let's do the Sea Explorer. Okay, and that should actually be enough. Oh wait, we are of course not logged in. So log in here. Now we are in admin, but let's use someone else here. And I think we used Leo before so let's now use that user. Now we have an incorrect password. All right so let's see what else we have. So what other users we could use. And actually let's use Monica here. Why not? So hopefully her password is correct. Well, let's actually try to replace this here with test1234. Well, maybe we did change the passwords of all of these users in some other lectures before. So let's use John here. So I know that we never used John so now it has to work. Oh, I actually see the error that I just did before. So here it's not natours, it must be example.com. So let's try that again with Monica here. Or really just with John. This is more difficult than I expected it to be. But now finally we are logged in. All right, and so with that, let's try to get our checkout session. We are missing the authorization from here. One more time, and now we get some real error here. So something that is actually really coming from the code that we just wrote. All right. So let's check that out. And the problem is that here it's actually sessions. So stripe.checkout.sessions. One more time. This time it's taking a lot longer which is a good sign. And we have another error. So line 15 cannot read slug of node. All right, well that sure is weird because there should be a slug on this tour. So uh yeah you see that here it actually is. So maybe something went wrong with actually reading this tour. Which I cannot really understand why that would be. But let's just try to log the tour to the console. All right, and actually we get null. Which probably means that there's a tour ID not correctly defined. Oh, here is the problem. So I have it, ID all uppercase, but then here in the controller I have the D in lowercase. So like this. And so that's the small type of bugs that happen all the time obviously. So let's see what's the next one. Oh and actually this time we got it right. So you see that is the session that we just created. And it edits some more other stuff here but that doesn't really matter for us right now. What's really interesting to see though is that we now can actually already kind of see this payment, or at least this payment request, let's say in our drive dashboards. So if we go there and go to payments and then to all, you will see that this last one here actually just happened right now. So if we click that, then you will see some data about it. So you see for example that it is actually about the Sea Explorer Tour. You also have the price, you also have the image. Probably also some data about the user. And actually no, not really. But what matters here is that it says incomplete. And that's because we only created the checkout session on the server. And so we're missing the second step where we then actually charge the credit card on the client side. So since we're missing that, let's actually do it right in the next video.