One-time-payments with Stripe (+3DSecure), React, Redux, and Asp.NET
How to process a one time payment using React, Asp.NET and Stripe. This also involves performing payment authorisation with the customer’s bank, if required.
The Need
Out of the two common types of payments, one-time-payment and subscription based, in this post I focus on one time payments which are ideal for purchasing goods, packages, and processing payments associated with shopping carts for example.
In the last post, I covered how to initiate this process by taking payment details from your customers safely, so if you haven’t read it, refer to Capturing Billing and Payment Details as a prerequisite to this post.
End Result
You can find the live demo of this guide right here at Pellerex. By following this post, at the end you will have the complete flow including the frontend React App and backend Asp.NET APIs to integrate and process payments with Stripe safely.
By the way, this topic belongs to the series to set up Payments with React, Asp.NET and Stripe.
- Capturing Billing and Payment Details
- One Time Payment
- Subscriptions
- Cancel Subscription
- Switch Subscription
- Callbacks
Libraries
I am using Stripe backend library that you can fetch from here Stripe.net.
Also in your backend API, you would need to set up your Stripe Secret key like below:
If you like to read more on how I manage my API secrets, refer to Secret Management for Asp.NET APIs.
To read more on how to set up your React app for Stripe, refer to Step by Step Guide to Use Stripe Elements with React.
Flow
This is important as it sets the scene for the rest of this post, and I will walk through every step.
- Frontend: Capture billing and payment details, already covered here
- Frontend: Dispatch the payment command using Redux
- Frontend: Create Stripe PaymentMethod using Redux Middleware
- Backend: Create customer on Stripe and our database
- Backend: Create PaymentIntent using Stripe API
- Backend: Attach PaymentMethod using Stripe API
- Backend: Confirm PaymentIntent using Stripe API
- Bank: Redirect to customer’s bank for payment authorisation (optional)
- Frontend: Redirect to our web app for final confirmation, if the above payment authorisation happened
- Backend: Checking with Stripe on how the bank authorisation went
Test Cards
Before we begin, here is the link that you can find all the test cards to test different scenarios such as Success, Card Declines, or RequiresPaymentAuthorisation.
2. Dispatch Payment
We went through how to capture payment details securely before, so let’s start now by what happens when the user presses the submit button on our form. Below is the code.
By the way, if you like to know how I manage my React forms, have a look at Form Handling and Input Validation, and if you might need a refresher on Redux, please read my Redux in Plain English.
Note
Configuration, plumbing and troubleshooting your software foundation take a considerable amount of time in your product development. Consider using Pellerex which is a complete foundation for your enterprise software products, providing source-included Identity and Payment functions across UI (React), API (.NET), Pipeline (Azure DevOps) and Infrastructure (Kubernetes).
Here are the points to consider about this snippet:
- Form Check: I start by checking all the validations are passing before I proceed.
- Stripe is loaded: then I check if Stripe library has been fully loaded.
- Billing Details: followed by constructing billing details in the format that Stripe wants it.
- Access Card Details: Card details are passed to the payment function using an instance of Stripe object.
- Tokens: As my API endpoints are protected using JWTs, I use withAuth as a higher order components to access users’ tokens. Obviously this means I am not allowing users with no profile to make any payments, a policy which you can change if you want to. To read on how I access user information with Higher Order Components, refer to Access User Details using HOCs.
- Dispatch: Finally when I have all the information, I dispatch the call.
2.1 Reducers
Here is how I am creating and handling my actions and reducers:
I will come back and explain what these reducers do, but I will skip it for now, as I’d like to follow the flow of information, so everything makes sense.
3. Creating PaymentMethod
Some context first. PaymentMethod is the terminology that just means how the payment is done, is it by card, money transfer, etc. Here I have simply used card.
Also as part of the one time payment operation, I have a series of tasks that need to be chained together, meaning I use the response from one call to prepare the request for another.
Don’t Change the State from within the Reducer
One way to achieve this is through initiating another call from within the reducer, however this pattern is discouraged, as each reducer needs to be a pure function, meaning using the same input and current state of store, the output (target state of the store) needs to be always the same. Introducing a third variable (i.e. another API call) won’t guarantee this notion, as the API might return a different value each time it is called. Hence I use a middleware called OneTimePaymentManager, to orchestrate all these tasks.
And here is the code for the middleware:
And here is what’s happening here:
- Execute the Right Middleware: First thing first, make sure this middleware is intended to be run for the right action.
- OnStart: If there is anything that needs to be run before the actual operation, run it here.
- createPaymentMethod: This is where the first task happens. I am sending the credit card details directly to Stripe as a PaymentMethod, and receive a PaymentMethod Id for it, which I will use later to process and confirm the payment in the call to my own backend API.
- 3DSecure Authentication: Once the result comes back from my own API, I will know if there is a need to perform authorisation on the payment, by redirecting the user to their bank, where the bank sends a token to user’s mobile device, and they verify their identity. Once successful, they will be redirected back to my website.
If you would like to understand what’s behind getApi, and how I make a call to my backend APIs, refer to How to Call Backend APIs in React using Axios.
Note
Configuration, plumbing and troubleshooting your software foundation take a considerable amount of time in your product development. Consider using Pellerex which is a complete foundation for your enterprise software products, providing source-included Identity and Payment functions across UI (React), API (.NET), Pipeline (Azure DevOps) and Infrastructure (Kubernetes).
4. Process One Time Payment
Now that I have the PaymentMethod Id, as a reference to user’s credit card details on Stripe side, I can initiate processing and confirmation of the actual payment, by sending a request to my backend API. Below are the list of tasks which I will cover in detail.
4.1 Create customer on Stripe and our database
If you look at the list of items I am sending to my backend API, they are all straightforward, however let me explain the priceId.
As far as the One Time Payments are concerned, you really don’t have to define any products or prices on the Stripe dashboard before you process them. I simply send a dollar amount to Stripe, and ask Stripe to charge my customer that amount. Hence I have defined a set of tables to keep price information in my database.
When I load prices from my database on the pages (like here), I let the user choose the goods or products they want to buy, I record the priceId, and pass it on to backend for payment. That’s the purpose of priceId.
Now let’s have a look at how I create the customer, and I am basically doing a couple of tasks here:
- Save/Retrieve Customer: If customer doesn’t exist in my DB, create it, otherwise fetch it
- Create Stripe Cystomer: If customer didn’t exist, then create it on Stripe side as well. This is done through Stripe’s customer service APIs, which I have used from their Stripe.net package.
If you’d like to read more on how I manage my database through unit of work, refer to Unit of Work with EF, Code First, and Repository Patterns.
4.2 Create PaymentIntent using Stripe API
Next is to create PaymentIntent, which as its name implies, flags the intention of the customer we created/fetched from last step to pay a certain amount. Please note the amount needs to be in the smallest of the unit, in my case cent.
4.3 Attach PaymentMethod using Stripe API
Next we will need to attach the PaymentMethod Id we acquired from Step 3 (Frontend), and attach it to the Customer we created from Step 4.1.
4.4 Confirm PaymentIntent using Stripe API
Next I need to confirm the payment. This is the step that in some websites, you would take customer to another page, and ask them if they are sure to process with this payment. You can skip this step, as I have, and move it to your backend like what I have done, to reduce the number of back and forth. Here are what I provide to payment confirmation:
- ReturnUrl: This is the Url (on your website) you will give to the user’s financial institution to forward the customer to after the payment authorisation (3DSecure) is done, regardless of success/fail outcome.
- Payment Method: which I get from the PaymentMethod I have already mentioned.
Now let’s talk about the return values of Payment Confirmation as they are pretty important:
- Status: Status indicates the result of the payment. The status can be three values: requires_action, succeeded, requires_payment_method.
- RedirectToUrl: If the payment status is ‘requires_action’, then that means the payment needs to be authenticated by sending the users to their financial institution, and confirming their payment now. The URL is the address to their bank’s page.
- PaymentIntent.ID: I also include the payment intent Id in my response to UI, so when the user is redirected to my website from their bank, I have something to check their payment status against my backend.
4.5 Redirect to customer’s bank for payment authorisation (optional)
Now back to Step 3, when I created the PaymentMethod, and called my backend API to do all these processing, I am now at the point that I receive the response from Step 4.4, and I can now continue. Here is the code again:
We are at line 59 now, and if the Payment Authorisation is required, I will redirect the user to their bank using my route manager, which is another middleware I use to manage redirects in my Redux chain of command.
4.6 Redirect to our web app for final confirmation (optional)
Stripe will provide you with a test page to test your payment authorisation and different flows. Once the user authorised/rejected the payment, they will be redirected to the ReturnUrl we specified above.
4.7 Checking with Stripe on how the bank authorisation went
And last but not least, I would recommend to check the final outcome of the payment when the user is back on your site, using the payment intent id we received from our backend. Based on that response, you can navigate the user through your website.
Pellerex: Payment Foundation for Your Next Enterprise Software
How are you building your current software today? Build everything from scratch or use a foundation to save on development time, budget and resources? For an enterprise software MVP, which might take 8–12 months with a small team, you might indeed spend 6 months on your foundation. Things like Identity, Payment, Infrastructure, DevOps, etc. they all take time, while contributing not much to your actual product. These features are needed, but they are not your differentiators.
Pellerex does just that. It provides a foundation that save you a lot development time and effort at a fraction of the cost. It gives you source-included Identity, Payment, Infrastructure, and DevOps to build Web, Api and Mobile apps all-integrated and ready-to-go on day 1.
Check out Pellerex and talk to our team today to start building your next enterprise software fast.