How to process payments with Stripe in React Native

How to process payments with Stripe in React Native

Payments are a very important skill to have as a developer, but they can sometimes be confusing. Stripe is a very good tool to use when processing payments. Today, I will be teaching you how to use Stripe to process your payments in React Native.

Install the React Native Stripe SDK into your project (client-side)

# React Native CLI managed projects
npm i @stripe/stripe-react-native # NPM
# or
yarn add @stripe/stripe-react-native # Yarn

pod install # in the ios directory of your project
# Expo managed projects
expo install @stripe/stripe-react-native

Wrap your app in a Stripe Provider (client-side)

const App = () => {
    return (
        <StripeProvider
            publishableKey="" // publishable key from stripe (found in the stripe dashboard under "Developers", "API Keys")
            urlScheme="your-url-scheme" // required for 3D Secure and bank redirects
            merchantIdentifier="merchant.com.{{YOUR_APP_NAME}}" // required for Apple Pay
        >
            // Your app code here
        </StripeProvider>
    )
}

Add a backend endpoint (server-side)

Stripe uses something called a Payment Intent to process a payment. You will need to create an endpoint on your backend to create the payment intent so that you can use it on the client-side later. This will just be a basic express server.

Install required packages

npm i express stripe dotenv # NPM
# or
yarn add express stripe dotenv # Yarn

Create the server

// server.js

require("dotenv").config({ path: "./.env" }); // this will fetch your environment variables from a .env file
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY); // we will add to environment variable later
const express = require("express");

const app = express();

app.use(express.json()); // middleware to parse data as json

app.post("/create-payment-intent", async (req, res) => {
    const paymentIntent = await stripe.paymentIntents.create({
        amount: req.body.amount,
        currency: "cad", // whatever your currency is
        payment_method_types: ["bancontact", "card", "ideal", "sepa_debit", "sofort"], // those are all your options, I'm only using card
    })

    res.json({
        clientSecret: paymentIntent.client_secret
    })
})

// You will also need to host this endpoint somewhere, but I'm not going to get into that

Add your secret key to the environment variables

// .env file (server-side)

STRIPE_SECRET_KEY=your_secret_key // found in the stripe dashboard under "Developers", "API Keys"

// DO NOT SHARE THIS KEY WITH ANYONE

Fetch payment details and process payment

const CheckoutScreen = () => {
    const { initPaymentSheet, presentPaymentSheet } = useStripe(); // imported from the stripe react native package
    const [total] = useState(your_total);
    const [sheetLoading, setSheetLoading] = useState(false);

    const fetchPaymentDetails = async () => {
        const response = await fetch("${API_URL}/create-payment-intent", {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify({
                amount: (total * 100).toFixed(0) // stripe takes the amount in your sub currency so for me, Canadian dollars sub currency is cents, which there are 100 of in each dollar, therefore I multiply the total by 100
            })
        })

        const { clientSecret } = await response.json();

        return clientSecret
    }

    const initializePaymentSheet = async () => {
        setSheetLoading(true);

        const clientSecret = await fetchPaymentDetails();

        const { error } = await initPaymentSheet({
            paymentIntentClientSecret: clientSecret
        })

        if (!error) openPaymentSheet();
    }

    const openPaymentSheet = async () => {
        setSheetLoading(false);

        const { error } = await presentPaymentSheet();

        if (error) Alert.alert(`Error Code: ${error.code}`, error.message)
        else Alert.alert("Success!", "Your payment has been confirmed!")
    }

    return (
        <TouchableOpacity onPress={initializePaymentSheet}>
            Pay
        </TouchableOpacity>
    )
}

export default CheckoutScreen

That's it! You have successfully processed a payment in your React Native app!

Did you find this article valuable?

Support Ben Carter by becoming a sponsor. Any amount is appreciated!