Introduction
You’ve been working hard on your e-commerce app, and now it is time to start processing payments.
In this project-based tutorial, you will learn how to integrate Stripe to process payments in a React Native e-commerce application.
For that, we will use the Nike Project that we created in the previous episodes.
On the client side, we have a React Native application built with Expo.
We have a Rest API build with NodeJS and Express on the backend side.
This guide is meant to be used alongside our video tutorial:
Grab a ☕ and let’s get started
Server-side: NodeJS - Stripe integration
To be able to charge customers, you have to create PaymentIntents.
For security reasons, you cannot create PaymentIntents directly from your client side (React Native). You have to create them from your backend.
Stripe has SDKs for most backend languages (ruby, python, go, java, php, .net). What we are interested in, is the NodeJS SDK.
To follow along, you have to create a Stripe account here.
Install Stripe SDK
Let’s install stripe SDK in our backend project using npm
npm install stripe --save
Payment routes
Let’s start by creating a new Router src/router/paymentRoutes.js responsible for Payments.
const express = require('express');const router = express.Router();module.exports = router;
Now, let’s connect it to our main app inside src/index.js
const paymentRoutes = require('./router/paymentRoutes');app.use('/payments', paymentRoutes);
Create PaymentIntents
We have to create an endpoint that will create payment intents.
The endpoint will:
- Handle POST requests
- Receive the amount as an input inside the body
- Create a paymentIntent using Stripe SDK
- Return the identifier of the intent
const stripe = require('stripe')('<Stripe Secret Key>');router.post('/intent', async (req, res) => {try {const paymentIntent = await stripe.paymentIntents.create({amount: req.body.amount,currency: 'usd',automatic_payment_methods: {enabled: true,},});res.json({ paymentIntent: paymentIntent.client_secret });} catch (e) {res.status(400).json({error: e.message,});}});
After we run the server, we can test this endpoint by sending a curl request from a new terminal
curl -X POST -H "Content-Type: application/json" \-d "{\"amount\":17950}" \http://localhost:3000/payments/intent
Client-side: React Native - Stripe integration
For our client side, we are working with a React Native application built with Expo. Stripe integrates seamlessly with Expo without any additional configurations.
Let’s start by installing the stripe package
npx expo install @stripe/stripe-react-native
Inside App.js, we have to add the <StripeProvider>
<StripeProvider publishableKey="<Your Publishable Key}"><Navigation /></StripeProvider>
Because we are using the Redux Toolkit Query library, let’s set up a new endpoint inside src/store/apiSlice.js
// PaymentscreatePaymentIntent: builder.mutation({query: (data) => ({url: 'payments/intents',method: 'POST',body: data,}),}),export const {...useCreatePaymentIntentMutation,} = apiSlice;
Checkout logic
The last step is to implement the checkout logic. When the user clicks on the Checkout button, we have to:
- Create a PaymentIntent by sending a request to our server
- Initialize the Payment Sheet, which will display the payment modal
- Process the payment by presenting the Payment Sheet
- If payment was processed successfully, we can save the order in our database
With this in mind, let’s define the onCheckout method inside src/screens/ShoppingCart./js and call it when we press on the Checkout button
const onCheckout = async () => {// 1. Create a payment intent// 2. Initialize the Payment sheet// 3. Present the Payment Sheet from Stripe// 4. If payment ok -> create the orderonCreateOrder();};
1. Create a PaymentIntent
We will use the mutation generated by Redux Toolkit Library
import {useCreateOrderMutation,useCreatePaymentIntentMutation,} from '../store/apiSlice';const ShoppingCart = () => {...const [createPaymentIntent] = useCreatePaymentIntentMutation();...const onCheckout = async () => {// 1. Create a payment intentconst response = await createPaymentIntent({amount: Math.floor(total * 100),});console.log(response);if (response.error) {Alert.alert('Something went wrong', response.error);return;}...}}
2. Initialize the Payment Sheet
We will use the function initPaymentSheet that we can get from the useStripe hook to initialize the Payment sheet by sending the paymentIntentClientSecret
const ShoppingCart = () => {...const { initPaymentSheet, presentPaymentSheet } = useStripe();const onCheckout = async () => {...// 2. Initialize the Payment sheetconst { error: paymentSheetError } = await initPaymentSheet({merchantDisplayName: 'Example, Inc.',paymentIntentClientSecret: response.data.paymentIntent,defaultBillingDetails: {name: 'Jane Doe',},});if (paymentSheetError) {Alert.alert('Something went wrong', paymentSheetError.message);return;}}}
3. Process payment
We will present the payment sheet that we initialized in the previous step, and if we do not receive any errors back, that means that the payment was successfully processed by Stripe
const onCheckout = async () => {...// 3. Present the Payment Sheet from Stripeconst { error: paymentError } = await presentPaymentSheet();if (paymentError) {Alert.alert(`Error code: ${paymentError.code}`, paymentError.message);return;}}
Let’s test it out
Several test cards are available for you to use in test mode to make sure this integration is ready. Use them with any CVC, postal code, and future expiration date.
- 4242 4242 4242 4242 Succeeds and immediately processes the payment.
- 4000 0025 0000 3155 Requires authentication. Stripe will trigger a modal asking for the customer to authenticate.
- 4000 0000 0000 9995 Always fails with a decline code of insufficient_funds.
Then, open up your Stripe Dashboard and you should see the payment.
Congrats 🎉
You have integrated Stripe Payments in React Native and successfully managed your first transaction.
The next step is to Activate your Stripe account and switch from the test mode to the Production mode.