You can 🎥 watch a video to see how this server was implemented and read the transcripts.
CJ Avilla (00:01): In this episode, we cover the basic server side implementation for accepting a one-time payment with a custom form. If you're interested in a faster integration path using Stripe hosted checkout, head over to the checkout playlist in the Stripe developers channel. The payment flow you'll see today for collecting a one-time payment has two steps. First creating the payment intent on the server, and second confirming the payment on the client, using the client secret for the payment intent. So in this episode, you're going to learn how to add an end point to your server to create a new payment intent. Then depending on whether you're using Vanilla JS or React on the web or Stripe iOS or Stripe Android on mobile, you can watch videos for those specific front-end implementation that will pair with the code we've implemented here. So rather than start from scratch, we're going to jumpstart our server implementation using the developer office hours base sample.
CJ Avilla (00:53): If you want to see how to go from zero to one, check out the starter episode, linked in the description. You might also be interested in an episode about working with the Stripe CLI. It's a handy tool for helping you build and test your Stripe integration. All right. So from the terminal, we run Stripe samples, create developer office hours, and we'll give this one an alias of tutorial. Now we can pick go HTTP and that'll download it and scaffold a bare bones project with a simple server and client HTML file for us. In this episode, we'll spend all of our time in the server directory and in future episodes, we'll implement the front end to confirm. So let's change into that server directory and open server dot go. You'll notice that it already has a route for rendering some basic HTML and a skeleton for the web hook endpoint.
CJ Avilla (01:44): So at a minimum, we need to add one new server end point to create the payment intent that we'll later confirm on the front end. Let's stick with the same naming convention as the Stripe docs and name our route create payment intent. So this problem will accept post requests. As by convention, we are creating a new resource for creating a payment intent and the logic in this route is very simple. So we're going to create a payment intent using the Stripe go client library to make an API request to Stripe. Initially we'll hard code and just pass the minimum required arguments in these parameters. So just amount and currency. This amount value is denoted in the smallest denomination for the given currency. So in this case, since finally, we need to return some Jason with only the client secret property of the newly created payment intent.
CJ Avilla (02:34): Let's jump into another terminal instance so we can start the server with go run server dot, go and experiment with the end point using curl to make a direct request to the payment intent endpoint. So this is going to be a post request to local host four, two, four, two, and we'll just pass an empty Jason object in the request body. Notices this response is well-formed Jason and includes the client secret for the newly created payment and returning to our code. Let's talk about this API call for creating a payment intent. It turns out that there is more than two dozen optional parameters available for tailoring the payment experience for your customers. One of those optional parameters is payment method types, which takes a list of string values for the payment method options you'd like to allow your customers to pay with. So by default, this is set to a slice with one element, the string with the word part and making this even a tent only confirmable with a card payment methods.
CJ Avilla (03:30): So in practice, you would code a list of string values for all the payment method types. You want to accept here, but in this series, you're going to learn how to accept a wide variety of different payment method types. So lets refactor our end point to accept some arguments by de serializing a marshaling that Jason request body. So we'll extract an argument for the payment method type that we want to work with. And furthermore, some payment method types only work with specific currencies. So let's also allow the currency to be passed from the client as well.
CJ Avilla (04:04): All right, let's head back to the terminal, restart our server and update our CRO requests to pass in the payment method type in the currency in the request body. Cool, that works. But if we try to pass a i Bex debit as their payment method type and USD is the currency, notice this fails. In this case, we get a response with an empty client secret and we can see in the server logs and error message explaining that AAU Beck's debit only works with Australian dollars. So if we update the curl request to pass in AUD, the server responds with a client secret as expected. So in the future, we'll want to surface errors in a nice format so that our front end can consistently parse and present errors to customer. So let's store the error response from the API call and render an error response with a well-formed Jason in a failure case.
CJ Avilla (05:06): So we're going to use right, the right Jason helper here to return a 400 status code and follow the structure where the response has an error property pointing at an object with a string message. This matches the shape returned directly from the Stripe API for our client side calls. So it'll make implementing air handling logic on the clients just a little bit easier to reason about all right. So after restarting our server again and attempting to create a payment intent with an invalid combo of payment method type and currency, we now see a well-formed Jason era response.
CJ Avilla (05:42): Most payment method types, complete payment asynchronously for some payments complete nearly instantly like cards, but for others, payments can take a few days or even more to complete due to the asynchronous nature of the way money flows through networks. We highly recommend implementing web hooks to automate fulfillment. We have episodes all about how to set up your web Candler. So let's update our web hook end point here to simply print the S to the server log. When a payment intent event fires, it's quite common to automate things like email notifications, updating your database, pulling from inventory, printing, shipping labels, and more than part of your web hook handler also worth noting that you could use a third party library or a tool like Zapier or IFTTT as a low or no code option for handling web hook notifications. So for now, we're simply going to check and see if the event type is one of payment, intent dot created and print a simple status update to the server log.
CJ Avilla (06:37): From the terminal we'll restart our server and test our new web hook logic with the Stripe CLI using the listen command. Straight listen forms a direct connection from Stripe to this locally running server so that when events happen on the demo Stripe account, they're delivered to the development server without needing any tunneling software like end grok. The strapless and command accepts a URL to which events should be forwarded. Now, if we successfully create a new payment intent with ideal and euros, we'll see in the server log that the payment intent was created. And we can see in the logs for Stripe, listen that the payment intent dot created event fired. So let's head over and improve our log statement to include the IDs of the payment intent and the event and the status of the payment intent. So you'll notice that when receiving an event types that start with payment intent dot an instance of the payment intent is available on event data dot raw.
CJ Avilla (07:31): And we need to unmarcle all that into an actual instance. So we'll restart the server and fire another test to confirm our improved log statement. Now we see here, the idea of the event, the idea of the payment intent and the status of the payment intent note that this payment intent was not created with a specific payment method. So its status is requires payment method. We'll assign a new payment method when confirming the payment on the front end, again, covered in a future episode. So as we add support for more different payment methods in the future, it'll be interesting to see these different status messages and the server logs and align those with what the customer sees and with the various states for payment intent. So note that depending on which payment method types you plan to support and which automations you're looking to build, you likely won't need to handle every single one of these event types.
CJ Avilla (08:23): Okay cool. So at this point, the server is technically ready to add a front end, however, we'll add one last simple config route for fishing, the publishable key. So we don't need a hard code that on the front end, this simple helper is purely for serving our publishable keys when receiving a get request to slash config. This is a best practice when working with mobile clients so that if for some reason you need to roll your API keys, the publishable key is not hard-coded into production. Mobile apps shipped to users that would require that like all your users install an updated version of the app to get the new key. As a quick recap, we added a new end point to create payment intense, and the API call to create the payment intent, passes the amount, the currency and the type of payment method we want to allow.
CJ Avilla (09:09): We also added some logging to the web hook handler for debugging and looking to the future when implementing application logic to automate fulfillment. And finally, we added a quick help route for returning the publishable key so that we don't hard code that in mobile clients. Next we recommend heading over to one of the playlist that most closely fits your front end implementation. You can use the links in the description or head over to the Stripe developers channel and take a look at those playlist. Thanks so much for watching and we'll see you in the next one.