availability

This page is only relevant for JavaScript v3 PayPal custom integrations (not Drop-in UI).

This guide won't be relevant to you if:

Previously, Braintree documented how to integrate with version 4 of PayPal's JavaScript SDK, called checkout.js. While that integration is still supported, Braintree now offers support for version 5 of the PayPal JavaScript SDK.

This guide walks through how to upgrade from the old version to the new version.

Script tag

Using checkout.js, it was necessary to load the script tag separately from the Braintree SDKs:

HTML
<!-- Load PayPal's checkout.js library. -->
<script src="https://www.paypalobjects.com/api/checkout.js" data-version-4></script>

<!-- Load the Braintree components -->
<script src="https://js.braintreegateway.com/web/3.73.1/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.73.1/js/paypal-checkout.min.js"></script>

With the PayPal JS SDK, all you need to do is load the Braintree SDK and then call loadPayPalSDK on the paypalCheckoutInstance that is created.

HTML
<!-- No need to manually load the PayPal JS SDK -->

<!-- Load the Braintree components -->
<script src="https://js.braintreegateway.com/web/3.73.1/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.73.1/js/paypal-checkout.min.js"></script>
braintree.paypalCheckout.create({
  client: clientInstance
}, function (paypalCheckoutErr, paypalCheckoutInstance) {
  paypalCheckoutInstance.loadPayPalSDK(function (loadPayPalSDKErr) {
    // Adds https://www.paypal.com/sdk/js script to the page and
    // adds the paypal object to the window

    // Set up PayPal JS SDK (see next section)
  });
});

A configuration object can be passed into loadPayPalSDK that will overwrite the default properties for configuring the PayPal JS SDK:

paypalCheckoutInstance.loadPayPalSDK({
  intent: 'capture', // Braintree defaults this to 'authorize'
  currency: 'USD',
  commit: true,
  vault: true,
}, function (loadPayPalSDKErr) {
  // Adds https://www.paypal.com/sdk/js script to the page and
  // adds the paypal object to the window

  // Set up PayPal JS SDK (see next section)
});

For all possible values, review the documentation for supported query params in the PayPal JS SDK.

Alternatively, you can load the PayPal JS SDK directly on the page:

HTML
<!-- Load the PayPal JS SDK -->
<script src="https://www.paypal.com/sdk/js?client-id=your-sandbox-or-prod-client-id"></script>

<!-- Load the Braintree components -->
<script src="https://js.braintreegateway.com/web/3.73.1/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.73.1/js/paypal-checkout.min.js"></script>

Replace your-sandbox-or-prod-client-id with the PayPal client ID found in the Braintree Control Panel under Settings > Processing > PayPal > Options > PayPal Client ID.

This ID will be different for your sandbox account and your production account.

There are many other query parameters that can be used in addition to the client-id param.

Setting up the SDK

How to initialize the PayPal SDK

The biggest difference between checkout.js and the PayPal JS SDK is in how PayPal button(s) are rendered.

In checkout.js, paypal.Button.render was called with your PayPal JS SDK config and selector for the PayPal button.

JavaScript
// With checkout.js
paypal.Button.render(paypalConfig, '#paypal-button-selector');

For the PayPal JS SDK, call paypal.Buttons with your PayPal JS SDK config, and then call render on the result with your selector for your PayPal button.

JavaScript
// With the PayPal JS SDK
paypal.Buttons(paypalConfig).render('#paypal-button-selector');

How to render a PayPal button

In checkout.js, it was necessary to pass a style parameter to configure the display of the button.

JavaScript
// With checkout.js

// Render a normal PayPal button
paypal.Button.render({
  // Other configuration
  style: {
    color: 'blue'
  }
}, '#paypal-button-selector');

For the PayPal JS SDK, use fundingSource: paypal.FUNDING.PAYPAL in your configuration to load only a PayPal button (by default, the integration will try to render all eligible payment methods). In addition, the PayPal JS SDK supports the style parameter:

JavaScript
paypal.Buttons({
  fundingSource: paypal.FUNDING.PAYPAL,
  style: {
    layout:  'vertical',
    color:   'blue',
    shape:   'rect',
    label:   'paypal'
  }
  // Other configuration
}).render('#paypal-button-selector');

Creating a payment resource

In checkout.js, a payment function was used to create the payment resource. This could be used for either the Vault or Checkout integration flows.

JavaScript
// With checkout.js
paypal.Button.render({
  payment: function () {
    return paypalCheckoutInstance.createPayment({
      // Your createPayment options
    });
  }
  // Other configuration
}, '#paypal-button-selector');

The payment function has been renamed to createOrder for the Checkout flow or createBillingAgreement for the Vault flow.

JavaScript
// PayPal JS SDK with Checkout flow
paypal.Buttons({
  createOrder: function () {
    return paypalCheckoutInstance.createPayment({
      // Your createPayment options
    });
  }
  // Other configuration
}).render('#paypal-button-selector');
JavaScript
// PayPal JS SDK with Vault flow
paypal.Buttons({
  createBillingAgreement: function () {
    return paypalCheckoutInstance.createPayment({
      // Your createPayment options
    });
  }
  // Other configuration
}).render('#paypal-button-selector');

Tokenizing the PayPal account

In checkout.js, an onAuthorize function was used to finish the flow.

// With checkout.js
paypal.Button.render({
  onAuthorize: function (data) {
    return paypalCheckoutInstance.tokenizePayment(data, function (err, payload) {
      // Send payload.nonce to your server
    });
  }
  // Other configuration
}, '#paypal-button-selector');

The onAuthorize function in the PayPal JS SDK config has been renamed to onApprove.

// PayPal JS SDK
paypal.Buttons({
  onApprove: function (data) {
    return paypalCheckoutInstance.tokenizePayment(data, function (err, payload) {
      // Send payload.nonce to your server
    });
  }
  // Other configuration
}).render('#paypal-button-selector');

Other considerations

onCancel and onError functions are unchanged.

env no longer needs to be passed as the environment is pulled from the PayPal client-id.

Checkout flow vs Vault flow

With checkout.js, you could dynamically choose whether the Checkout flow or the Vault flow would be used. With the PayPal JS SDK, this decision needs to be made during the setup of the SDK.

With the Checkout flow, you will use a createOrder function in your PayPal JS SDK config to initialize the login. With the Vault flow, you will pass vault: true when calling loadPayPalSDK and use a createBillingAgreement function to initialize the login.

Checkout flow

A typical PayPal integration using the Checkout flow with checkout.js would look something like:

braintree.client.create({
  authorization: CLIENT_AUTHORIZATION
}, function (clientErr, clientInstance) {
  braintree.paypalCheckout.create({
    client: clientInstance
  }, function (paypalCheckoutErr, paypalCheckoutInstance) {
    paypal.Button.render({
      env: 'production', // Or 'sandbox'

      payment: function () {
        return paypalCheckoutInstance.createPayment({
          flow: 'checkout',
          amount: '100.00',
          currency: 'USD'
        });
      },

      onAuthorize: function (data) {
        return paypalCheckoutInstance.tokenizePayment(data, function (err, payload) {
          // Submit `payload.nonce` to your server
        });
      }
    }, '#paypal-button').then(function () {
      // The PayPal button will be rendered in an html element with the ID
      // `paypal-button`. This function will be called when the PayPal button
      // is set up and ready to be used
    });
  });
});

A full PayPal JS SDK integration with currency and intent set may look like:

braintree.client.create({
  authorization: CLIENT_AUTHORIZATION
}, function (clientErr, clientInstance) {
  braintree.paypalCheckout.create({
    client: clientInstance
  }, function (paypalCheckoutErr, paypalCheckoutInstance) {
    paypalCheckoutInstance.loadPayPalSDK({
      currency: 'USD',
      intent: 'capture'
    }, function () {
      paypal.Buttons({
        createOrder: function () {
          return paypalCheckoutInstance.createPayment({
            flow: 'checkout',
            amount: '100.00',
            currency: 'USD', // Make sure this matches the currency passed into loadPayPalSDK
            intent: 'capture' // Make sure this matches the intent passed into loadPayPalSDK
          });
        },

        onApprove: function (data) {
          return paypalCheckoutInstance.tokenizePayment(data, function (err, payload) {
            // Submit `payload.nonce` to your server
          });
        }
      }).render('#paypal-button').then(function () {
        // The PayPal button will be rendered in an html element with the ID
        // `paypal-button`. This function will be called when the PayPal button
        // is set up and ready to be used
      });
    });
  });
});

Vault flow

vault: true must be passed when calling loadPayPalSDK.

braintree.client.create({
  authorization: CLIENT_AUTHORIZATION
}, function (clientErr, clientInstance) {
  braintree.paypalCheckout.create({
    client: clientInstance
  }, function (paypalCheckoutErr, paypalCheckoutInstance) {
    paypalCheckoutInstance.loadPayPalSDK({
      vault: true
    }, function () {
      paypal.Buttons({
        createBillingAgreement: function () {
          return paypalCheckoutInstance.createPayment({
            flow: 'vault'
          });
        },

        onApprove: function (data) {
          return paypalCheckoutInstance.tokenizePayment(data, function (err, payload) {
            // Submit `payload.nonce` to your server
          });
        }
      }).render('#paypal-button').then(function () {
        // The PayPal button will be rendered in an html element with the ID
        // `paypal-button`. This function will be called when the PayPal button
        // is set up and ready to be used
      });
    });
  });
});

See also