You can 🎥 watch a video to see how this server was implemented and read the transcripts.
CJ Avilla (00:02): 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 developer channel. So 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's secret for the payment intent. In this episode, you'll learn how to add an endpoint to your server to create the payment intent. So 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 implementations that will pair with the code we implement here. So rather than start from scratch, we're going to jump start our server implementation using the developer office hours based sample.
CJ Avilla (00:52): So if you want to see how we go from zero to one, check out the starter episode, linked in the description. You might also be interested in 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're going to run Stripe samples create eight developer office hours, and we'll give this one, an alias of tutorial. We can now pick.net and that'll download it, scaffold the bare bones project with a simple client, with some HTML and a server solution for us. So in this episode, we're going to spend all of our time in the server directory and in future episodes, we'll implement those front ends to confirm payment. So let's change into the server directory and open up server Dodd solution. All right, you'll see that it already contains a route [inaudible 00:01:39] for rendering basic HTML using the use web route and passing in the path to the client side code, using an environment variable.
CJ Avilla (01:48): You notice it also has a skeleton already for the web hook end point. Now at a minimum, we need to add one new server end point to create a payment intent that we'll later confirm on the front end. Let's stick with the same naming convention as the Stripe docs and we'll name our route create payment intent. This will be a post route as by convention. We're creating a new resource, a payment intent. So the logic in this route is very simple. We'll create a payment intent using the stripe.net client library to make an API request to Stripe. Initially we'll hard code and pass just the minimum required arguments, so amount and currency. This amount value is denoted in the smallest denomination for a given currency. So in this case since, we'll initialize an instance of the payment intent service with our client instance and then call create a sync to make the API call to Stripe.
CJ Avilla (02:40): Finally, we need to return some Jason with only the client secret property of that newly created payment intent. We'll fire up the server by pushing the play button here in the top left, and then jump into a terminal to test with curl. This is going to be a post request to local host 4242 with an empty object in the request body. Notice the response is well-formed Jason and includes the client secret for the newly created payment intent. So for this demo, we actually want the client secret to be camel case rather than snake case in order to match some of our other search server implementations and to match the client. So in practice, it doesn't matter either way, and it doesn't matter what you name the property returned to the client. Just as long as we're sending this client secret, It should work.
CJ Avilla (03:26): So we'll need to create A model with Newton soft Jason property attributes to override the name of the property to use Campbell case. We'll name the class, create payment intent response. Let's test again. Okay, that Looks great and has a camel cased client secret property. Returning to our controller code, let's talk about this API call for creating a payment intent again. So there's 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 for the payment method options. You'd like to allow your customers to pay with . By default, this is a list of string with just one entry and that's the word card making this payment intent only confirmable with card payment methods. So in practice you can hard-code a list of values for all the different payment method types you want to accept here, but in this series, you're going to learn how to accept a wide variety of payment method types. So let's refactor our end point to accept some arguments by de-centralizing the Jason body we'll create a new class called create payment intent requests so that we can use model binding. And in this class, we'll extract an argument for the payment method type and furthermore, some payment method types only work with specific currencies. So let's allow the currency to be passed from the client as well.
CJ Avilla (05:07): Well, why are Up the model binding arguments to the controller action and pass those down to the options. Let's head back to the terminal and update our CRO request to pass in the payment method type in the currency in the request body cool that works. But if we try to pass a U Bex debit as our payment method type, and we leave USD as the currency notice this fails. In this case, we get a big failure response with an error message explaining that AAU Beck's debit only works with Australian dollars. If we update our occur request and pass in AUD, the server responds with a client secret as expected. Now in the future, we'll want to surface these failures in a nice format so that the front end can consistently pass and present those errors to customers. So let's wrap the API call in and try catch block. And if there's a strip exception thrown, we'll respond with a 400 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 straight API for client side calls. So it'll make implementing error handling logic on the client's just a bit easier to reason about. All right, so after restarting and attempting to create a payment intent with an invalid combo of payment method type in currency, we now see a well-formed area response.
CJ Avilla (06:30): So 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. So we have episodes all about how to set up your web hook Candler. Let's update our web hook and point to simply print the server log when payment attend events, fire. It's quite common to automate things like sending email notifications or updating your database or pulling from inventory printing, shipping labels, and more as part of your web Candler. Also with noting is that you could use a third party tool like Zapier or IFT as a low or no code solution for handling would put notifications. For now, we're going to simply check to see if the event type is one of payment intent dot created and print a simple status update from the terminal. We'll test our new web hook logic with the Stripe CLI using the listen command. Stripe listen forms a direct connection from Stripe to this locally running server so that when events happen on the demo Stripe account, they're going to be delivered to the development server without needing any tunneling software like end grok.
CJ Avilla (07:40): The Stripe, listen, command accepts a URL to which events should be forwarded. We're going to add this dash L so that we're using latest event or the latest version of the API when generating event objects. Now, if we successfully create a new payment intent, see in the server log that the payment intent was created, and we can see in the logs for Stripe, listen that the payment and tank event fired. All right, let's improve our log statement to include the IDs of the event and the payment intent and the status of the payment intent. when receiving these event types that start with payment intent dot an instance of the payment intent is available on event.data at an object. And here we're doing some casting. We have the right type of instance. We'll restart this server and fire and other tests to confirm our improved log statement. And now we see the ID of the event, the ID of the payment intent and the status of the payment intent.
CJ Avilla (08:32): Note that this payment intent was not created with a specific payment method. So it's status is requires payment method. We'll assign a new payment method when confirming on the front end, again covered in a future episode. So as we add support for more payment method types in the future, it'll be interesting to see these status messages in the server logs and align those with what the customer sees and with the various states for payment intense.
CJ Avilla (08:57): So note that depending on which payment method types you plan to support in which automations you're looking to build, you likely won't need to handle every single one of these event types. So at this point, the server is technically ready to add a front end, however, we'll add one last simple configure for fetching a publishable key. So we don't need to hard-code that on the front end. This simple helper is purely for serving our publishable keys when receiving a get request to/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 all mobile users install an updated version of the app to get the new key. All right. So as a quick recap, we added a new end point to create payment, intense the API call to the create the payment intent passes the amount, the currency, and now the type of payment methods we want to allow.
CJ Avilla (09:54): And we also added some logging to the web hook Candler for debugging and looking to the future when implementing application logic to automate fulfillment. And finally, we added a quick helper for returning the publishable key so that we don't have to hard code that in the 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 the playlist. Thanks for watching, and we'll see you in the next one.