Accept E-Commerce Payments Easily with PayPal’s Buttons Component! 💰
Tags: paypal, node
Published: 2023-10-25 21:39:00

Accepting online payments is now a universal must-have, catering to everyone from solo entrepreneurs to massive global corporations.

PayPal’s Standard Checkout allows for seamless integration of PayPal’s Payment Buttons component into your e-commerce app, granting you the power to accept online payments. In this guide, I am going to show how to add Standard Checkout to a simple shopping app, built with HTML and NodeJS.

### Guide Overview
[Part 1. Prerequisites](#part-1-prerequisites)
[Part 2a. Basic Integration — Code Setup](#part-2a-basic-integration-code-setup)
[Part 2b. Basic Integration — Checkout Flow](#part-2b-basic-integration-checkout-flow)
[Part 3a. Custom Integration — Code Setup](#part-3a-custom-integration-code-setup)
[Part 3b. Custom Integration — Checkout Flow](#part-3b-custom-integration-checkout-flow)
[Part 4. Conclusion](#part-4-conclusion)
[Part 5. Additional PayPal Payment Integrations](#part-5-additional-paypal-payment-integrations)

---

## Part 1. Prerequisites
To complete this integration, you will need the following information:

- API Credentials (Client ID and Secret) for a PayPal REST app: paste these from your Developer Dashboard. Since we are working in a development environment in this demo, ensure that the Sandbox Toggle is on.

![Obtain Test API Credentials](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/thyj2z9u7d1sgyhjc0o4.png)

- The username and password for a Personal Sandbox account: you will need this to complete the checkout process.


![Navigate to Sandbox Accounts under Testing Tools](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gr876dif4zqyaqzxfpvo.png)

![Obtain Personal Sandbox Account login details](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/abko5qiyyynasu2p1hou.png)

---

## Part 2a. Basic Integration — Code Setup
Navigate to PayPal’s [Integrate Checkout documentation](https://developer.paypal.com/docs/checkout/standard/integrate/). The documentation shows you how to set your development environment up: installing **npm**, verifying your **package.json** file, and setting up your **.env** file.

Next, you will set up your back-end server and front-end code. The documentation presents the contents of three files: **server.js** (for the back-end server), **app.js** (for the client-side logic) and **checkout.html** (for the user interface).

![Obtain the Required Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zz6npfq26826cbqgzc2m.png)

Grab these code snippets and paste them into your IDE (Integrated Development Environment). I strongly recommend that you implement the basic integration first, and ensure that you are able to complete the Standard Checkout Flow successfully, before adding your custom e-commerce code. I find that this approach reduces potential errors and associated frustrations. 😅

In the **checkout.html** file, replace the word "test" within the Software Development Kit (SDK) script tag with your Client ID.

```js
<script src="https://www.paypal.com/sdk/js?client-id=CLIENT_ID&currency=USD"></script>
```

In the **app.js** file, note that the "cart" object in the response body is hard-coded with one product’s SKU and quantity information. For important security reasons, we do not pass any transaction or price amounts from the front- end. Instead, we use the SKU/ID and quantity information to look up the product(s) in a datastore and use these product details to calculate the total cart price in our back-end.

```js
body: JSON.stringify({
  cart: [
    {
      id: “YOUR_PRODUCT_ID”,
      quantity: “YOUR_PRODUCT_QUANTITY”,
    },
  ],
})
```

In the **server.js** file, note that the transaction quantity ("100.00") is hardcoded into the createOrder call.

```js
const createOrder = async (cart) => {
  console.log(
    “shopping cart information passed from the frontend createOrder() callback:”,
    cart,
  );

  const accessToken = await generateAccessToken();
  const url = `${base}/v2/checkout/orders`;
  const payload = {
    intent: "CAPTURE",
    purchase_units: [
      {
        amount: {
          currency_code: "USD",
          value: "100.00",
        },
      },
    ],
  };

... more code ...
}
```

---

## Part 2b. Basic Integration — Checkout Flow
Start your server; on the command line, run "node server/server.js" or whichever shortcut is defined in your package.json file. You should see the PayPal Buttons component displayed on the front- end.

![PayPal Button Component — Basic Integration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kt3yxe2keruaugdhm3vd.png)

Click the first PayPal button, which displays the Checkout modal. Note that the URL in the modal shows that we are in a sandbox environment. Sign in using your Personal Sandbox account (if you haven’t already).

![The Checkout Modal starts the checkout process](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8j0aqizpa6q71fm04i0u.png)

You are then presented with the transaction amount (at this point, this should be $100.00) and several payment options.

![The transaction amount is hardcoded to $100](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gon4oig23z08dyspcd8l.png)

Complete the transaction with the PayPal Balance option. A confirmation message should appear in your browser; its location depends on where you place the element with the id "result-message" in your application.

```html
<p id=”result-message”></p>
```

![Status message after completed checkout process
](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0412ub8uxqgu9b0xli2a.png)

---

## Part 3a. Custom Integration — Code Setup
Now, let’s add our custom e-commerce code!

In the **checkout.html** file, I added the code for three products being sold at the LiftOff Shop. I styled the code with TailwindCSS:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>PayPal JS SDK Standard Integration Demo</title>
    <script src="https://cdn.tailwindcss.com"></script>
  </head>
  <body class="p-6">
    <h1 class="text-center text-4xl font-medium">LiftOff Shop</h1>
    <main class="products flex flex-wrap justify-center">
      <div
        class="product text-center m-3 p-3 border border-slate-400 rounded-md"
      >
        <img src="https://picsum.photos/id/21/200" class="rounded-md" />
        <h2 class="text-xl my-2">Galaxy Shoes</h2>
        <p class="text-green-600 font-medium text-lg mb-2">$100</p>
        <div class="mb-3">
          <label class="text-lg" for="quantity1">Quantity:</label>
          <select class="text-lg" id="quantity1">
            <option value="0">0</option>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
          </select>
        </div>
        <button
          class="product-btn py-1 px-3 rounded-md bg-indigo-200 hover:bg-indigo-300"
          data-product-id="hdqgapq9"
          data-quantity-id="quantity1"
        >
          Add to Cart
        </button>
      </div>

      <div
        class="product text-center m-3 p-3 border border-slate-400 rounded-md"
      >
        <img src="https://picsum.photos/id/104/200" class="rounded-md" />
        <h2 class="text-xl my-2">Spaceship Earrings</h2>
        <p class="text-green-600 font-medium text-lg mb-2">$40</p>
        <div class="mb-3">
          <label class="text-lg" for="quantity2">Quantity:</label>
          <select class="text-lg" id="quantity2">
            <option value="0">0</option>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
          </select>
        </div>
        <button
          class="product-btn py-1 px-3 rounded-md bg-indigo-200 hover:bg-indigo-300"
          data-product-id="rnfjwsy0"
          data-quantity-id="quantity2"
        >
          Add to Cart
        </button>
      </div>

      <div
        class="product text-center m-3 p-3 border border-slate-400 rounded-md"
      >
        <img src="https://picsum.photos/id/342/200" class="rounded-md" />
        <h2 class="text-xl my-2">Martian Tote</h2>
        <p class="text-green-600 font-medium text-lg mb-2">$75</p>
        <div class="mb-3">
          <label class="text-lg" for="quantity3">Quantity:</label>
          <select class="text-lg" id="quantity3">
            <option value="0">0</option>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
          </select>
        </div>
        <button
          class="product-btn py-1 px-3 rounded-md bg-indigo-200 hover:bg-indigo-300"
          data-product-id="zytkddw5"
          data-quantity-id="quantity3"
        >
          Add to Cart
        </button>
      </div>
    </main>

    <p id="result-message" class="mx-auto text-center text-red-600 w-1/2"></p>

    <section class="mt-8 mx-auto flex flex-wrap w-1/2">
      <div class="mb-3 w-1/2 text-center" id="cart">
        <h2 class="text-xl font-medium">Cart</h2>
        <ul id="cart-items"></ul>
        <p>TOTAL $<span id="cart-total">0</span></p>
        <button
          id="clear-cart"
          class="py-1 px-3 mt-3 rounded-md bg-gray-200 hover:bg-gray-300"
        >
          Clear Cart
        </button>
      </div>
      <div class="text-center" id="paypal-button-container"></div>
    </section>

    <script src="https://www.paypal.com/sdk/js?client-id=AYCd0wKOWs9itZ23_2XEZUhZpbZdHT_c1qcMCjqTnb6fxFE7tQBnUQGSPh3_PVQkgoBamFV1KgPUI9B4&currency=USD"></script>
    <script type="module" src="app.js"></script>
  </body>
</html>
```

![E-Commerce App with PayPal Buttons Component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3eqwksxl5vu6e4hq9jb.png)

In the **app.js** file, I added code that brings the Add-To-Cart, Calculate-Cart-Total and Clear-Cart functionalities. To calculate my cart total, I imported my product information from the **products.js** file, which serves as my makeshift datastore. I also updated the cart object in the response body to the **cartItems** array (instead of the hard-coded product from earlier).

```js
import { PRODUCTS } from "./products.js";

const cartItems = [];
let cartTotal = 0;

function addToCart(productId, quantityId) {
  const quantitySelect = document.getElementById(quantityId);
  const selectedQuantity = parseInt(quantitySelect.value, 10);

  if (selectedQuantity > 0) {
    cartItems.push({
      id: productId,
      quantity: selectedQuantity,
    });
    cartTotal = calculateCartTotal(cartItems);
    updateCart(cartItems);
  }
}

function calculateCartTotal(cartItems) {
  let total = 0;
  cartItems.forEach((item) => {
    total += item.quantity * PRODUCTS[item.id].price;
  });

  return total;
}

function updateCart(cartItems) {
  const cartItemsList = document.getElementById("cart-items");
  const cartTotalElement = document.getElementById("cart-total");

  cartItemsList.innerHTML = "";
  cartTotalElement.textContent = cartTotal;

  cartItems.forEach((item) => {
    const li = document.createElement("li");
    li.textContent = `${PRODUCTS[item.id].name}: ${item.quantity}`;
    cartItemsList.appendChild(li);
  });
}

window.paypal
  .Buttons({
    async createOrder() {
      try {
        const response = await fetch("/api/orders", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          // use the "body" param to optionally pass additional order information
          // like product ids and quantities
          body: JSON.stringify({
            cart: cartItems,
          }),
        });

... more code ...

... more code ...
  })
  .render("#paypal-button-container");

// Example function to show a result to the user. Your site's UI library can be used instead.
function resultMessage(message) {
  const container = document.querySelector("#result-message");
  container.innerHTML = message;
}

// Event Listeners
const productBtns = document.querySelectorAll(".product-btn");
productBtns.forEach((btn) => {
  btn.addEventListener("click", (e) => {
    const productId = e.target.dataset.productId;
    const quantityId = e.target.dataset.quantityId;
    addToCart(productId, quantityId);
  });
});

// clear cart
document.getElementById("clear-cart").addEventListener("click", () => {
  // clear cart items, without reassigning the array
  cartItems.length = 0;
  cartTotal = 0;
  updateCart(cartItems);
});
```

In the **server.js** file, I imported my products from **products.js** and added a function that calculates the transaction amount using the cart contents. In the **createOrder** call, I replaced the hardcoded transaction value with the calculated cart value.

```js
import express from "express";
import fetch from "node-fetch";
import "dotenv/config";
import path from "path";
import { PRODUCTS } from "../client/products.js";

... more code ...
... more code ...

function calculateTotalPrice(cart) {
  let totalPrice = 0;
  for (let i = 0; i < cart.length; i++) {
    totalPrice += PRODUCTS[cart[i].id].price * cart[i].quantity;
  }
  return totalPrice.toString();
}

/**
 * Create an order to start the transaction.
 * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
 */
const createOrder = async (cart) => {
  // use the cart information passed from the front-end to calculate the purchase unit details
  console.log(
    "shopping cart information passed from the frontend createOrder() callback:",
    cart
  );

  const accessToken = await generateAccessToken();
  const url = `${base}/v2/checkout/orders`;
  const payload = {
    intent: "CAPTURE",
    purchase_units: [
      {
        amount: {
          currency_code: "USD",
          value: calculateTotalPrice(cart),
        },
      },
    ],
  };

  ... more code ...
};

... more code ...
```

---

## Part 3b. Custom Integration — Checkout Flow
Restart the server and add some products to the cart; I chose one of each item, totaling $215.

![Cart total showing total amount of cart items](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f71bqhhvg779mudoridz.png)

Click the gold PayPal button to activate Checkout (signing in with your Personal Sandbox account, if necessary). You should see that the transaction amount is the value of your cart.


![Transaction value in the Checkout modal is equal to the cart amount](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5wv2eg9eyzbg69y4mdxt.png)

Go ahead and complete the purchase. You should see a confirmation message in the browser.

![Confirmation of successful checkout in browser](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g7l23i31elskipggiro4.png)

---

## Part 4. Conclusion
This demo introduced a straightforward integration of PayPal’s Standard Checkout, using the PayPal Buttons component. You may customize your further, to meet your use cases. Read our Checkout Documentation for [examples of these customizations](https://developer.paypal.com/docs/checkout/standard/customize/). The PayPal Developer [GitHub repository](https://github.com/paypaldev) also has several examples of integrations within various code environments, such as React and Angular.

---

## Part 5. Additional PayPal Payment Integrations
- [Pay Later](https://developer.paypal.com/docs/checkout/pay-later/us/)
- Custom Debit/Credit Card fields ([Advanced Checkout](https://developer.paypal.com/docs/checkout/advanced/integrate/))

---

> Join the PayPal Developer Community!
> Our Developer Community members support each other in integrating PayPal technologies, contributing to open source, expanding knowledge and networks, and improving PayPal’s products and documentation. We’d love to have you join us! 💙
> - [Website](https://developer.paypal.com/)
> - [Twitter](https://twitter.com/paypaldev)
> - [GitHub](https://github.com/paypal)