Payment Handling with Stripe, Node and Express
Tags: stripe, node, tutorial, javascript
Published: 2020-10-18 12:48:24

# Why do you need a payment gateway ?  
 - Let's just assume that we are creating an e-commerce shopping website. Payment handling is one of the crucial part in e-commerce site. 
 - There are many other payment gateways are available like PayPal, Amazon Pay, World Pay, Stripe etc. But in this tutorial we are going to stick with Stripe.
 - And using a payment gateway is not just for transferring money, but it has other benefits as well.
 - A payment gateway focuses on creating a secure pathway between a customer and the merchant to facilitate payments securely.
  
In this tutorial we are going to create payment gateway service for Node JS using STRIPE.

#### Github Repo Link and Postman Collection: [Click Here](https://github.com/Novartus/Node-Stripe)

### What are we building here:
1) Saving Customer's Details to Stripe
2) Add customer's Card in Stripe.
3) View Customer's Cards.
4) Update Customer's Cards.
5) Delete Customer's Card from stripe
6) Payment Checkout with Saved Card.
7) One Time Payment Checkout without saving card info.

### How we are gonna save customer sensitive card details?	
Instead of saving card details directly by passing them to API, we are going to create a charge first and after that we are going to save the charge details to customer. This we are not going to handle card information directly and our production integration is developed in a [PCI Compliant](https://stripe.com/docs/security#pci-dss-guidelines) manner. Which is also recommended by the Stripe.

### What do we need ?
- Stripe API Key
- Node version >= 12 installed in your system
- Postman/ Insomnia (Or any other software for testing API Calls)

### Getting the stripe API Key:  
- You can get your own stripe API key by logging into [Stripe Dashboard](https://dashboard.stripe.com/) and get the test key. It will look something like this 'sk_live_...3Vls'.
- In this tutorial we are gonna use the default sandbox key from [here](https://stripe.com/docs/api/authentication) which is provided by stripe. 

#### Note:
>If you are using your own API key, then make sure to turn on "TEST MODE" from your Stripe Dashboard otherwise you might face some unexpected charges during the test and you will be able to see the test transactions in your dashboard.

### Getting Started: 
- Stripe Charges the amount in cents so if you want to charge $200 then your amount would be 20000 ($200 x 100 = 20000).
- We are not using any Database here so I'm just gonna store customer ID as a Constant during this tutorial. So if you use this make sure to connect to Database if you want to store customer's stripe data.

Install the dependencies.

```sh
$ npm init
```
Install Express, Stripe-Node packages
```sh
$ npm install express 
$ npm install --save stripe
```

### Index.js
Ok now we get to create our first file called index.js . Once created, at the top of the file we want to include all of the dependencies that we will need for our project:

```sh
const express = require("express");
const app = express();
const port = 3000;
	
app.use(express.json());
```
When we want to test and make sure our server is working, we will run this function to listen on port 3000 and log a string if its successful:
```sh
app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.listen(port, () => {
  console.log(`App listening at http://localhost:${port}`);
});
```
Now if you open your browser and type: http://localhost:3000/ you will see ' Hello World!' in your browser.

At this point our index.js file should look like this:
```sh
const express = require("express");
const app = express();
const port = 3000;
	
app.use(express.json());

app.get("/", (req, res) => {
	res.send("Hello World!");
});
	
app.listen(port, () => {
    console.log(`App listening at http://localhost:${port}`);
});
	
```

### Stripe.js
Let's create a new file called strie.js which will be used for handling all stripe calls. Once created we are going to create a simple GET request and exporting our route file so index.js can access it:

```sh
const express = require("express");
const router = express.Router();

router.get("/", (req, res) => {
  res.status(200).json({
    message: "Stripe Hello World!",
  });
});

module.exports = router;
```

#### Adding stripe.js route to index.js
```sh
const stripe = require("./stripe");
app.use("/api/", stripe);
```
Now the index.js will something similar to this:
``` sh
const express = require("express");
const app = express();
const stripe = require("./stripe");
const port = 3000;

app.use(express.json());

app.use("/api/", stripe);

app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.listen(port, () => {
  console.log(`App listening at http://localhost:${port}`);
});
```
Now if you open your browser and type: http://localhost:3000/api/ you will see ' Stripe Hello World!' in your browser.

---
#### Creating a new Stripe Customer
---
In Stripe.js file let's add the stripe key as a constant and adding stripe module:
``` sh 
const Stripe_Key = 'sk_test_....jQb';
const stripe = require("stripe")(Stripe_Key);
```
and let's create an api which will create a new customer id from user's email address
![Creating a new Stripe Customer Code Snippet](https://drive.google.com/uc?export=view&id=18tF1PL-b-g8Modnsd1gKGs9IyEm_zWe0
)

> Note
If you are using your own API key then you can add your organization account Secret Key. So it will link the customer with your organization.

You can add some extra fileds during creating the new customer using stripe API which you can found here on [Stripe Documents](https://stripe.com/docs/api/customers/object)
Currently we are not using any Database so we have to note down the customer id somewhere from our response message.

##### Response :
![New Customer Response](https://drive.google.com/uc?export=view&id=1zDaVceP-8w6a22J-Pl1fbuQEqDWb3Xcv)

- Let's Note Down Our Customer ID here: 'cus_IDxxDETTAorXTO'

---
#### Adding a card to the existing customer
----
For testing purposes we don't need to use real card data. Stripe has given some list of the card for the testing purposes and we are going to use it in this. You can find it here [Stripe Test Cards](https://stripe.com/docs/testing)

Card Number, Expiry Month, Year, CVC these are the required parameters for adding a new card. So if those parameters are not passed in the body then we are going throw a bad request error as the response.
![Add Card Code Snippet](https://drive.google.com/uc?export=view&id=1rwMkJuFDP_-0y69AQAvb5kzHTOhPX-HG)

##### Response :
![Add Card Response](https://drive.google.com/uc?export=view&id=167gGIh2k51PtekWDGJNAAxI_B0ybhw0Q)
---
#### View Customer's All Cards
---
- To get the list of customer's saved cards we need to just pass the customerID which was generated by the stripe earlier.
- In this case we only need cardId, Card Type, Expiry Details and Last 4 digit of the saved card. But if you need more data of the saved card you can find it here on [Stripe Docs for View saved Cards](https://stripe.com/docs/api/cards/list)

![View Customer's All Cards Code Snippet](https://drive.google.com/uc?export=view&id=1fGIzMqH2-okWeIxdcePn4h9AHlxB2xlM)

##### Response :
![View Cards Response](https://drive.google.com/uc?export=view&id=1H55Z8rs2NNLbL6kbTDx02SzwqUUxb2Vg)
----
#### Update Card Details
---
- From customer's saved card details we will get the cardID and from cardID we can update the saved card details like card holder name, expiry month, expiry year, address details etc. All the details except cardId is optional for update operation.
- If you need to update more fields then you can find it here on [Stripe Docs for Updating Card Details](https://stripe.com/docs/api/cards/update)

![Update Card Details Code Snippet](https://drive.google.com/uc?export=view&id=1g9u0Rsrfqw6K38szfBSBqAIbo3f0Afvi)

##### Response :
![Update Card Details Response](https://drive.google.com/uc?export=view&id=1ICVw-3Bhf3uz6ur6HVomEbWkKWtNoZ-p)

---
#### Delete Saved Card
---
To delete a saved card we need to pass the ID of the savedCard
![Delete Saved Card Code Snippet](https://drive.google.com/uc?export=view&id=1b38Xsre4uMfOrO3_OSmBByQP7dvx65TB)

##### Response :
![Delete Saved Card Response](https://drive.google.com/uc?export=view&id=1AcFneB80phfB-wMaWfcR08rlfsqlSelw)

---
#### Creating A Payment Charge
---
- We have two choices over here 
-- Customer can pay from existing card.
-- Customer can pay without saving the new card or without existing cards.
- So we are going to use 'oneTime' parameter from request.body as a toggle switch between them.

##### One Time Payment with new Card

 ---
```sh
const { amount, email } = req.body;
    const {
      cardNumber,
      cardExpMonth,
      cardExpYear,
      cardCVC,
      country,
      postalCode,
    } = req.body;

    if (!cardNumber || !cardExpMonth || !cardExpYear || !cardCVC) {
      return res.status(400).send({
        Error: "Necessary Card Details are required for One Time Payment",
      });
    }
    try {
      const cardToken = await stripe.tokens.create({
        card: {
          number: cardNumber,
          exp_month: cardExpMonth,
          exp_year: cardExpYear,
          cvc: cardCVC,
          address_state: country,
          address_zip: postalCode,
        },
      });

      const charge = await stripe.charges.create({
        amount: amount,
        currency: "usd",
        source: cardToken.id,
        receipt_email: email,
        description: `Stripe Charge Of Amount ${amount} for One Time Payment`,
      });

      if (charge.status === "succeeded") {
        return res.status(200).send({ Success: charge });
      } else {
        return res
          .status(400)
          .send({ Error: "Please try again later for One Time Payment" });
      }
    } catch (error) {
      return res.status(400).send({
        Error: error.raw.message,
      });
    }

```
##### Payment with an existing Card
---
```sh
const { amount, cardId,  email } = req.body;

try {
      const createCharge = await stripe.charges.create({
        amount: amount,
        currency: "usd",
        receipt_email: email,
        customer: customerId,
        card: cardId,
        description: `Stripe Charge Of Amount ${amount} for Payment`,
      });
      if (createCharge.status === "succeeded") {
        return res.status(200).send({ Success: createCharge });
      } else {
        return res
          .status(400)
          .send({ Error: "Please try again later for payment" });
      }
    } catch (error) {
      return res.status(400).send({
        Error: error.raw.message,
      });
    }
```

#### Final Charge Payment Code
---
![Final Charge Payment Code Snippet](https://drive.google.com/uc?export=view&id=1IOQ04__-aRWSmsCHQqxCsWhT1ZHpTE5O)

##### One Time Payment Response :
![One Time Payment Response](https://drive.google.com/uc?export=view&id=1WdupkSpKNzReAIgb94Q3f_mXNeIs6VhT)

##### Saved Card Payment Response :
![One Time Payment Response](https://drive.google.com/uc?export=view&id=1ZsKl1lFAd2vyuIFkLCIexXsJZ-rDV7EE)

---
### Final Stripe.JS
---
Now the stripe.js will something similar to this:
```sh
const express = require("express");
const router = express.Router();
const Stripe_Key =
  "sk_test_....Qb";
const stripe = require("stripe")(Stripe_Key);
const customerId = "cus_IDxx....orXTO";

router.get("/", (req, res) => {
  res.status(200).json({
    message: "Stripe Hello World!",
  });
});

// Create a new customer for stripe
router.post("/newCustomer", async (req, res) => {
  console.log("\n\n Body Passed:", req.body);
  try {
    const customer = await stripe.customers.create(
      {
        email: req.body.email,
      }
      // {
      //   // If you are using your own api then you can add your organization account here. So it will link the customer with your organization
      //   stripeAccount: process.env.StripeAccountId,
      //}
    );
    return res.status(200).send({
      //   customerDetails: customer,
      customerId: customer.id,
      customerEmail: customer.email,
    });
  } catch (error) {
    return res.status(400).send({ Error: error.raw.message });
  }
});

// Add a new card of the customer
router.post("/addNewCard", async (req, res) => {
  console.log("\n\n Body Passed:", req.body);
  const {
    cardNumber,
    cardExpMonth,
    cardExpYear,
    cardCVC,
    cardName,
    country,
    postal_code,
  } = req.body;

  if (!cardNumber || !cardExpMonth || !cardExpYear || !cardCVC) {
    return res.status(400).send({
      Error: "Please Provide All Necessary Details to save the card",
    });
  }
  try {
    const cardToken = await stripe.tokens.create({
      card: {
        name: cardName,
        number: cardNumber,
        exp_month: cardExpMonth,
        exp_year: cardExpYear,
        cvc: cardCVC,
        address_country: country,
        address_zip: postal_code,
      },
      // customer: customer.stripe_id,
      // stripe_account: StripeAccountId,
    });

    const card = await stripe.customers.createSource(customerId, {
      source: `${cardToken.id}`,
    });

    return res.status(200).send({
      card: card.id,
    });
  } catch (error) {
    return res.status(400).send({
      Error: error.raw.message,
    });
  }
});

// Get List of all saved card of the customers
router.get("/viewAllCards", async (req, res) => {
  let cards = [];
  try {
    const savedCards = await stripe.customers.listSources(customerId, {
      object: "card",
    });
    const cardDetails = Object.values(savedCards.data);

    cardDetails.forEach((cardData) => {
      let obj = {
        cardId: cardData.id,
        cardType: cardData.brand,
        cardExpDetails: `${cardData.exp_month}/${cardData.exp_year}`,
        cardLast4: cardData.last4,
      };
      cards.push(obj);
    });
    return res.status(200).send({
      cardDetails: cards,
    });
  } catch (error) {
    return res.status(400).send({
      Error: error.raw.message,
    });
  }
});

// Update saved card details of the customer
router.post("/updateCardDetails", async (req, res) => {
  const { cardName, cardExpMonth, cardExpYear, cardId } = req.body;

  if (!cardId) {
    return res.status(400).send({
      Error: "CardID is Required to update",
    });
  }
  try {
    const card = await stripe.customers.updateSource(customerId, cardId, {
      name: cardName,
      exp_month: cardExpMonth,
      exp_year: cardExpYear,
    });
    return res.status(200).send({
      updatedCard: card,
    });
  } catch (error) {
    return res.status(400).send({
      Error: error.raw.message,
    });
  }
});

// Delete a saved card of the customer
router.post("/deleteCard", async (req, res) => {
  console.log("\n\n Body Passed:", req.body);
  const { cardId } = req.body;
  if (!cardId) {
    return res.status(400).send({
      Error: "CardId is required to delete Card",
    });
  }
  try {
    const deleteCard = await stripe.customers.deleteSource(customerId, cardId);
    return res.status(200).send(deleteCard);
  } catch (error) {
    return res.status(400).send({
      Error: error.raw.message,
    });
  }
});

// Create a payment charge
router.post("/createCharge", async (req, res) => {
  const { amount, cardId, oneTime, email } = req.body;
  if (oneTime) {
    const {
      cardNumber,
      cardExpMonth,
      cardExpYear,
      cardCVC,
      country,
      postalCode,
    } = req.body;

    if (!cardNumber || !cardExpMonth || !cardExpYear || !cardCVC) {
      return res.status(400).send({
        Error: "Necessary Card Details are required for One Time Payment",
      });
    }
    try {
      const cardToken = await stripe.tokens.create({
        card: {
          number: cardNumber,
          exp_month: cardExpMonth,
          exp_year: cardExpYear,
          cvc: cardCVC,
          address_state: country,
          address_zip: postalCode,
        },
      });

      const charge = await stripe.charges.create({
        amount: amount,
        currency: "usd",
        source: cardToken.id,
        receipt_email: email,
        description: `Stripe Charge Of Amount ${amount} for One Time Payment`,
      });

      if (charge.status === "succeeded") {
        return res.status(200).send({ Success: charge });
      } else {
        return res
          .status(400)
          .send({ Error: "Please try again later for One Time Payment" });
      }
    } catch (error) {
      return res.status(400).send({
        Error: error.raw.message,
      });
    }
  } else {
    try {
      const createCharge = await stripe.charges.create({
        amount: amount,
        currency: "usd",
        receipt_email: email,
        customer: customerId,
        card: cardId,
        description: `Stripe Charge Of Amount ${amount} for Payment`,
      });
      if (createCharge.status === "succeeded") {
        return res.status(200).send({ Success: charge });
      } else {
        return res
          .status(400)
          .send({ Error: "Please try again later for payment" });
      }
    } catch (error) {
      return res.status(400).send({
        Error: error.raw.message,
      });
    }
  }
});

module.exports = router;
```

### Conclusion
This is the totally working code to handle payment and its related data. All you have to do is replace the sandbox key with your Strip API key and it will work perfectly. Let me know if it is not working or anything I would really appreciate your feedbacks.