PayPal v6 SDK with Braintree

API

Last updated: Jun 17th, 3:24pm

Overview

  • PayPal Web SDK v6 handles the button and PayPal flow.

  • Braintree Web SDK is used to create the payment and generate a payment method nonce to securely complete the transaction.

  • You will:

    • Initialize PayPal and Braintree clients

    • Render a PayPal button

    • Start a one-time payment flow

    • Capture the payment on your server

Set up your HTML file

Create an index.html file to structure your payment interface. Include the necessary scripts for Braintree and PayPal.

    1<!doctype html>
    2<html lang="en">
    3<head>
    4 <meta charset="UTF-8" />
    5 <title>Braintree One-Time Payment - Recommended Integration - PayPal Web SDK</title>
    6 <meta name="viewport" content="width=device-width, initial-scale=1" />
    7 <style>
    8 .buttons-container {
    9 display: flex;
    10 flex-direction: column;
    11 gap: 12px;
    12 }
    13 </style>
    14</head>
    15<body>
    16 <h1>Braintree One-Time Payment Recommended Integration</h1>
    17
    18 <div class="buttons-container">
    19 <paypal-button id="paypal-button" type="pay" hidden></paypal-button>
    20 </div>
    21 <script src="app.js"></script>
    22 <script src="https://js.braintreegateway.com/web/3.111.0/js/client.min.js"></script>
    23 <script src="https://js.braintreegateway.com/web/3.111.0/js/paypal-checkout.min.js"></script>
    24 <script
    25 async
    26 src="https://www.sandbox.paypal.com/web-sdk/v6/core"
    27 onload="onPayPalLoaded()"
    28 ></script>
    29</body>
    30</html>

    Create Your JavaScript File

    Create an app.js file to set up the SDK and connect to your APIs. This file will include functions to manage the PayPal integration and Braintree payments.

      1async function onPayPalLoaded() {
      2 try {
      3 const clientToken = await getBrowserSafeClientToken();
      4 const paypalInstance = await window.paypal.createInstance({
      5 clientToken,
      6 components: ["paypal-payments"],
      7 pageType: "checkout",
      8 });
      9
      10 const braintreeInstance = await window.braintree.client.create({
      11 authorization: clientToken,
      12 });
      13
      14 const braintreeCheckout = await window.braintree.paypalCheckout.create({
      15 client: braintreeInstance,
      16 });
      17
      18 setupPayPalButton({ paypalInstance, braintreeCheckout });
      19 } catch (error) {
      20 console.error(error);
      21 }
      22}
      23
      24async function setupPayPalButton({ paypalInstance, braintreeCheckout }) {
      25 const paypalPaymentSession = paypalInstance.createPayPalOneTimePaymentSession({
      26 async onApprove(data) {
      27 const { nonce } = await braintreeCheckout.tokenizePayment({
      28 payerID: data.payerId,
      29 paymentID: data.orderId,
      30 });
      31 const orderData = await completePayment(nonce);
      32 console.log("Capture result", orderData);
      33 },
      34 onCancel(data) {
      35 console.log("onCancel", data);
      36 },
      37 onError(error) {
      38 console.log("onError", error);
      39 },
      40 });
      41
      42 const paypalButton = document.querySelector("#paypal-button");
      43 paypalButton.removeAttribute("hidden");
      44
      45 async function createOrder() {
      46 const orderId = await braintreeCheckout.createPayment({
      47 flow: "checkout",
      48 amount: 10.0,
      49 currency: "USD",
      50 intent: "capture",
      51 });
      52 return { orderId };
      53 }
      54
      55 paypalButton.addEventListener("click", async () => {
      56 try {
      57 await paypalPaymentSession.start(
      58 { presentationMode: "auto" },
      59 createOrder()
      60 );
      61 } catch (error) {
      62 console.error(error);
      63 }
      64 });
      65}
      66
      67async function getBrowserSafeClientToken() {
      68 const response = await fetch("/braintree-api/auth/browser-safe-client-token", {
      69 method: "GET",
      70 headers: {
      71 "Content-Type": "application/json",
      72 },
      73 });
      74 const { accessToken } = await response.json();
      75 return accessToken;
      76}
      77
      78async function completePayment(paymentMethodNonce) {
      79 const response = await fetch("/braintree-api/checkout/transaction/sale", {
      80 method: "POST",
      81 headers: {
      82 "Content-Type": "application/json",
      83 },
      84 body: JSON.stringify({
      85 paymentMethodNonce,
      86 amount: 10.0,
      87 }),
      88 });
      89 const result = await response.json();
      90 return result;
      91}

      Constant & Function Reference Table

      Constant / Function Name Description
      onPayPalLoaded() Main entry point. Called when the PayPal SDK is loaded. Initializes PayPal + Braintree instances and sets up the PayPal button.
      getBrowserSafeClientToken() Calls your server to get a Braintree browser-safe client token, used to authorize both PayPal and Braintree SDK instances.

      This can be done server-side and hydrated into your frontend if using a SSR set up.
      paypalInstance Instance of PayPal SDK v6, initialized using paypal.createInstance(). Used to create the PayPal one-time payment session.
      braintreeInstance Instance of Braintree Client SDK (braintree.client.create()), used as the base client for PayPal Checkout.
      braintreeCheckout Instance of Braintree PayPal Checkout integration (braintree.paypalCheckout.create()), used to create Braintree PayPal transactions and tokenize them.
      setupPayPalButton({ ... }) Sets up PayPal button click behavior, and registers callbacks for approval, cancel, and error events in the PayPal payment session.
      paypalPaymentSession PayPal one-time payment session created by paypalInstance.createPayPalOneTimePaymentSession(). Starts the payment flow when invoked.
      createOrder() Function to create a PayPal order via braintreeCheckout.createPayment(). Returns orderId, which is passed to PayPal payment session.
      paypalButton DOM element reference to your PayPal button. The hidden attribute is removed once the button is ready.
      paypalButton.addEventListener("click", ...) Click listener that starts the PayPal payment session when the user clicks the button.
      onApprove(data) (callback) Called when the user approves the PayPal payment. Tokenizes the PayPal payment via Braintree and sends it to the server to complete the transaction.
      onCancel(data) (callback) Called if the user cancels the PayPal payment. Logs cancel data.
      onError(error) (callback) Called if an error occurs during the PayPal flow. Logs the error.
      completePayment(paymentMethodNonce) Sends the tokenized payment nonce to your server endpoint /braintree-api/checkout/transaction/sale to complete the transaction with Braintree. Returns the result.

      Implementing the server code

      This server-side example uses Node.js but you are free to use any backend language you choose. This file sets up the Express server and defines API endpoints that the frontend relies on to successfully process a one time payment. 

        1import express, { Request, Response } from "express";
        2import cors from "cors";
        3
        4import {
        5 getBrowserSafeClientToken,
        6 completeTransactionSale,
        7} from "./braintreeServerSdk";
        8
        9const app = express();
        10
        11app.use(cors());
        12app.use(express.json());
        13
        14/* ######################################################################
        15 * API Endpoints for the client-side JavaScript Braintree Integration code
        16 * ###################################################################### */
        17
        18app.get(
        19 "/braintree-api/auth/browser-safe-client-token",
        20 async (_req: Request, res: Response) => {
        21 try {
        22 const accessToken = await getBrowserSafeClientToken();
        23 res.status(200).json({ accessToken });
        24 } catch (error) {
        25 res.status(500).json({
        26 errorMessage: `failed to create the braintree client token: '${(error as Error).message}'`,
        27 });
        28 }
        29 },
        30);
        31
        32app.post(
        33 "/braintree-api/checkout/transaction/sale",
        34 async (req: Request, res: Response) => {
        35 const { amount, paymentMethodNonce } = req.body;
        36 const result = await completeTransactionSale({
        37 amount,
        38 paymentMethodNonce,
        39 });
        40
        41 const statusCode = result.errors ? 500 : 200;
        42 res.status(statusCode).json(result);
        43 },
        44);
        45
        46const port = process.env.PORT ?? 8080;
        47
        48app.listen(port, () => {
        49 console.log(`API server listening at https://localhost:${port}`);
        50});

        Implementing Braintree Server SDK Functions

        This file configures the Braintree SDK and includes functions for token generation and transaction processing.

          1import { config } from "dotenv";
          2import { join } from "path";
          3import braintree from "braintree";
          4import type { BraintreeGateway } from "braintree";
          5
          6const envFilePath = join(__dirname, "../../../", ".env");
          7config({ path: envFilePath });
          8
          9let gateway: BraintreeGateway;
          10
          11function getGateway() {
          12 if (!gateway) {
          13 if (!process.env.BRAINTREE_SANDBOX_MERCHANT_ID || !process.env.BRAINTREE_SANDBOX_MERCHANT_PUBLIC_KEY || !process.env.BRAINTREE_SANDBOX_MERCHANT_PRIVATE_KEY) {
          14 throw new Error("Required Braintree credentials are not defined in the .env file.");
          15 }
          16 gateway = new braintree.BraintreeGateway({
          17 environment: braintree.Environment.Sandbox,
          18 merchantId: process.env.BRAINTREE_SANDBOX_MERCHANT_ID,
          19 privateKey: process.env.BRAINTREE_SANDBOX_MERCHANT_PUBLIC_KEY,
          20 publicKey: process.env.BRAINTREE_SANDBOX_MERCHANT_PRIVATE_KEY,
          21 });
          22 }
          23 return gateway;
          24}
          25
          26export async function getBrowserSafeClientToken() {
          27 const clientTokenResponse = await getGateway().clientToken.generate({});
          28 return clientTokenResponse.clientToken;
          29}
          30
          31export async function completeTransactionSale({ paymentMethodNonce, amount }: { paymentMethodNonce: string; amount: string; }) {
          32 const result = await getGateway().transaction.sale({
          33 amount,
          34 paymentMethodNonce,
          35 });
          36 return result;
          37}

          Configure Environment Variables

          The example above uses enviroment variables to generate tokens for order processing. Make sure you create a .env file with the values below. 

            1BRAINTREE_SANDBOX_MERCHANT_ID=your_merchant_id
            2BRAINTREE_SANDBOX_MERCHANT_PUBLIC_KEY=your_public_key
            3BRAINTREE_SANDBOX_MERCHANT_PRIVATE_KEY=your_private_key