React Native MasteryThe Ultimate React Native and Expo Course. Launching November 26

Integrating Stripe Payments in your E-commerce React Native App

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

BASH
npm install stripe --save

Payment routes

Let’s start by creating a new Router src/router/paymentRoutes.js responsible for Payments.

JAVASCRIPT
const express = require('express');
const router = express.Router();
module.exports = router;

Now, let’s connect it to our main app inside src/index.js

JAVASCRIPT
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
JAVASCRIPT
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

BASH
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

BASH
npx expo install @stripe/stripe-react-native

Inside App.js, we have to add the <StripeProvider>

JAVASCRIPT
<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

JAVASCRIPT
// Payments
createPaymentIntent: 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:

  1. Create a PaymentIntent by sending a request to our server
  2. Initialize the Payment Sheet, which will display the payment modal
  3. Process the payment by presenting the Payment Sheet
  4. 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

JAVASCRIPT
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 order
onCreateOrder();
};

1. Create a PaymentIntent

We will use the mutation generated by Redux Toolkit Library

JAVASCRIPT
import {
useCreateOrderMutation,
useCreatePaymentIntentMutation,
} from '../store/apiSlice';
const ShoppingCart = () => {
...
const [createPaymentIntent] = useCreatePaymentIntentMutation();
...
const onCheckout = async () => {
// 1. Create a payment intent
const 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

JAVASCRIPT
const ShoppingCart = () => {
...
const { initPaymentSheet, presentPaymentSheet } = useStripe();
const onCheckout = async () => {
...
// 2. Initialize the Payment sheet
const { 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

JAVASCRIPT
const onCheckout = async () => {
...
// 3. Present the Payment Sheet from Stripe
const { 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.


Vadim Savin profile picture

Vadim Savin

Hi 👋 Let me introduce myself

I started my career as a Fullstack Developer when I was 16 y.o.

In search of more freedom, I transitioned to freelancing, which quickly grew into a global software development agency 🔥

Because that was not challenging enough, I started my startup which is used by over 20k users. This experience gave another meaning to being a (notJust) developer 🚀

I am also a proud ex-Amazon SDE and Certified AWS Architect, Developer and SysOps. You are in good hands 👌