Integrating Stripe Payments in Ionic React JS App with Capacitor and NodeJS
Tags: stripe, ionic, react, javascript
Published: 2023-05-08 17:53:15

This code will show you how to setup your [Ionic React](https://ionicframework.com/docs/react) application to support the Payment Sheet From Stripe using the [Capacitor Community Stripe Plugin](https://stripe.capacitorjs.jp). We will also create a small server application to run locally to create the payment intent secret that is required for the application to work properly with stripe. Finally we will show how to package and deploy the application to a mobile device using [Ionic Capacitor](https://capacitorjs.com/)

> You need to have a stripe account setup for this demo. See documentation for setting up your account here - https://stripe.com/docs/implementation-guides/core-payments/welcome-stripe



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/af8kd5r4y8zk3yw11a2m.png)

###Video
{% youtube kAdIW9hQ-dI %}

##The React Client Application
create ionic react application
```shell
ionic start --type react  
```
Install the Capacitor Stripe plugin using the following command:
```shell
npm install @capacitor-community/stripe
```

> Additional plugin configuration available here https://stripe.capacitorjs.jp/docs/configuration

Create `.env` in root of project to hold the 
```shell
REACT_APP_STRIPE_PUBLISHABLE_KEY='pk_test_VALUE'
```

Initialize the Stripe plugin with your publishable key in your App.tsx file:
```react
import { Capacitor } from '@capacitor/core';
import { Stripe } from '@capacitor-community/stripe';

// Initialize the Stripe plugin
if (Capacitor.isPluginAvailable("Stripe")) {
  Stripe.initialize({
    publishableKey : process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY+'',
  })
}
```
Create a new component for a `StripeCheckoutButton` and add the following code.

>Make sure to adjust the IP address for the API call to match the address of your computer so this can be tested appropriately on device.

This code accomplishes two things
1) make API call to get  payment intent from the server
2) Present the payment sheet to get credit card information from the user and charge the user.

```react
import React, { useState } from "react";
import { IonButton } from "@ionic/react";
import { Stripe } from "@capacitor-community/stripe";

const StripeCheckoutButton: React.FC = () => {
  const [loading, setLoading] = useState(false);

  const handleCheckout = async () => {
    setLoading(true);

    try {
      const response = await fetch(
        "http://192.168.1.56:3000/create-payment-intent",
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ amount: 1000, currency: "usd" }),
        }
      );

      const data = await response.json();
      console.log("PaymentIntent client secret:", data.clientSecret);

      await Stripe.createPaymentSheet({
        paymentIntentClientSecret: data.clientSecret,
        merchantDisplayName: "Inclusive Innovation Incubator",
      });

      const { paymentResult } = await Stripe.presentPaymentSheet();
      console.log(paymentResult);

    } catch (error) {
      console.error("Payment failed:", error);
    } finally {
      setLoading(false);
    }
  };

  return (
    <IonButton onClick={handleCheckout} disabled={loading}>
      {loading ? "Loading..." : "Checkout - Payment Sheet"}
    </IonButton>
  );
};

export default StripeCheckoutButton;

```

When the Payment Sheet is displayed, the user can enter their payment information and submit the payment. If the payment succeeds, the paymentIntent object will contain information about the successful payment. If the payment fails, an error will be thrown.


##The Server
We need to create a Payment Intent endpoint on a server to create the payment-intent client secret and pass it to the Payment Sheet.

For the purpose of this example we will create a small node server and run it locally.

First create a new directory in your project called server
```shell
mkdir server
cd server
```

Then initialize a node project
```shell
npm init
```

Then install the required libraries
```shell
npm install express body-parser cors stripe
```

First of all, install an npm package called dotenv using the following command in your node.js project root directory;
```shell
npm install dotenv --save
```
dotenv package automatically loads environment variables from .env file into process object in node.js applications.

Create a .env file in your server root directory and add the stripe key, we will use it in the `createPaymentIntent` method
```
STRIPE_SECRET_KEY='sk_test_VALUE'
```

Next create an file called `index.js` as the main file for your server; it has one route `/create-payment-intent`. 

In this code, we're importing the createPaymentIntent method from the `createPaymentIntent.js` file, and setting up an Express app that listens for POST requests to the /createPaymentIntent path.

When a POST request is received at this path, the createPaymentIntent function is called with the request and response objects.

```javascript
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const { createPaymentIntent } = require('./createPaymentIntent');

const app = express();

app.use(bodyParser.json());
app.use(cors());

app.post('/create-payment-intent', createPaymentIntent);

app.listen(3000, () => {
  console.log('Server listening on port 3000');
});
```
Then create the file that has the code for the `/create-payment-intent` route.

In this code, we're requiring the stripe package and creating a createPaymentIntent function that takes in a req (request) and res (response) object.

Inside the function, we're extracting the amount and currency values from the request body, and using the Stripe SDK to create a new payment intent with those values.

Once the payment intent is created, we're sending the client secret back to the client in the response body, which can then be used to complete the payment process.

Here we also use the information from the `.env` file to set the API key

```javascript
require('dotenv').config();
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

function createPaymentIntent(req, res) {
  const { amount, currency } = req.body;

  stripe.paymentIntents.create({
    amount,
    currency,
    // You can also add additional parameters here, such as a customer ID or payment method ID
    metadata: { integration_check: 'accept_a_payment' },
  })
    .then(paymentIntent => {
      res.json({ clientSecret: paymentIntent.client_secret });
    })
    .catch(error => {
      console.error(error);
      res.status(500).send({ error: 'An error occurred while creating the payment intent' });
    });
}

module.exports = {
  createPaymentIntent,
};
```

To run the server, navigate to the directory where your `index.js` file is located, and run `node index.js`. This will start the server and allow you to test your payment process locally.

>You can also use a client like postman or thunderclient to test the API locally

##Running the Application
First start the node server
```shell
node index.js
```
Next launch your capacitor application, I am using IOS so I need to add capacitor ios package.
```shell
npx cap add ios
```

To actually build and run the project you then use the following commands
```shell
npx cap add ios
npx ionic build
npx cap copy ios;
npx cap run ios --external --no-build --no-sync
```

### Links
Stripe Plugin - https://stripe.capacitorjs.jp/
Capacitor - https://capacitorjs.com/
Ionic React - https://ionicframework.com/docs/react
Stripe Account Setup - https://stripe.com/docs/implementation-guides/core-payments/welcome-stripe