PayPal

Vaulted Paymentsanchor

Vaulted payments with PayPal account will allow you to charge the account in the future without requiring your customer to be present during the transaction or re-authenticate with PayPal when they are present during the transaction.

The Vault is used to process payments with our recurring billing feature, and is also used for non-recurring transactions so that your customers don't need to re-enter their information each time they make a purchase from you.

Vaulted payments with PayPal account allows you to charge the account in the future without requiring your customer’s presence during the transaction.

The vaulted payment flow lets the user:

  • Select or add shipping addresses in the PayPal account
  • Select or add funding instruments in the PayPal account
  • Two-factor authentication support (currently only for US, UK, CA, DE, AT, and AU)

vault-flow

Typical use cases for the vaulted payment flow:

  • Faster payments for repeat customers
  • Subscriptions
  • Recurring billing (e.g. automatic top-up or usage based charges)

Launch the flowanchor

  1. javascript
// Pass the user's email on the vault request
 * @param {string} options.flow Set to 'checkout' for one-time payment flow,
 or 'vault' for Vault flow. If 'vault' is used with a client token 
 generated with a customer ID, the PayPal account will be added to that 
 customer as a saved payment method.
var isVaultFlow = options.flow === "vault";
var data = {
    paypalAccount: {
      correlationId: correlationId,
      options: {
        validate: isVaultFlow && !isTokenizationKey && options.vault,
      },
    },
  };
  if (isVaultFlow) {
    data.paypalAccount.billingAgreementToken = params.billingToken;
  } else {
    data.paypalAccount.paymentToken = params.paymentId || params.orderId;
    data.paypalAccount.payerId = params.payerId;
    data.paypalAccount.unilateral =
      gatewayConfiguration.paypal.unvettedMerchant;
      }
if (options.userAuthenticationEmail) {      
// eslint-disable-next-line camelcase      
paymentResource.payer_email = options.userAuthenticationEmail;    
}

Invoking the Vault flowanchor

note

The examples here require version 3.90.0 or higher of the Braintree JavaScript SDK.

If you are using the Braintree JavaScript SDK with the deprecated PayPal checkout.js library, review this migration guide to upgrade your integration.

important

The Vault flow does not support Pay Later offers. If you want to offer Pay Later to your customers, please integrate the Checkout with Vault flow.

An integration with our Vault would typically be used in conjunction with your PayPal Checkout flow. The only differences are how the PayPal JS SDK is loaded and the options you provide when tokenizing with the PayPal Checkout component.

Enable the Vault flow by setting the flow option to vault and passing vault:true in the loadPayPalSDK method and using a createBillingAgreement function to create the payment resource:

  1. Callback
  2. Promise
// Create a PayPal Checkout component
// Create a client.
braintree.client.create({
  authorization: CLIENT_AUTHORIZATION
}, function (clientErr, clientInstance) {

  // Stop if there was a problem creating the client.
  // This could happen if there is a network error or if the authorization
  // is invalid.
  if (clientErr) {
    console.error('Error creating client:', clientErr);
    return;
  }

  // Create a PayPal Checkout component.
  braintree.paypalCheckout.create({
    client: clientInstance
  }, function (paypalCheckoutErr, paypalCheckoutInstance) {
    paypalCheckoutInstance.loadPayPalSDK({
      vault: true
    }, function () {
      paypal.Buttons({
        fundingSource: paypal.FUNDING.PAYPAL,

        createBillingAgreement: function () {
          return paypalCheckoutInstance.createPayment({
            flow: 'vault', // Required

            // The following are optional params
            billingAgreementDescription: 'Your agreement description',
            enableShippingAddress: true,
            shippingAddressEditable: false,
            shippingAddressOverride: {
              recipientName: 'Scruff McGruff',
              line1: '1234 Main St.',
              line2: 'Unit 1',
              city: 'Chicago',
              countryCode: 'US',
              postalCode: '60652',
              state: 'IL',
              phone: '123.456.7890'
            }
          });
        },

        onShippingChange: function (data, actions) {
          // Perform some validation or calculation logic on 'data'
          if ( /* need to update shipping options or lineItems */ ) {
            return paypalCheckoutInstance.updatePayment({
              amount: 10.00,              // Required
              currency: 'USD',
              lineItems: [...],           // Required
              paymentId: data.paymentId,  // Required
              shippingOptions: [...],     // Optional       
            });
          } else if (/* address not supported */) {
            return actions.reject();
          }
 
          return actions.resolve();
        },

        onApprove: function (data, actions) {
          return paypalCheckoutInstance.tokenizePayment(data, function (err, payload) {
            // Submit 'payload.nonce' to your server
          });
        },

        onCancel: function (data) {
          console.log('PayPal payment canceled', JSON.stringify(data, 0, 2));
        },

        onError: function (err) {
          console.error('PayPal error', err);
        }
      }).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
      });

    });

  });

});

Use the onShippingChange function from the PayPal JS SDK setup method to listen for shipping changes that occur within the PayPal pop-up; then, use the updatePayment function , part of the Braintree JS SDK's paypalCheckoutInstance, to update the PayPal checkout flow with modified order line items or shipping options. Note that updatePayment replaces use of actions.order.patch.

Use the paypalCheckoutInstance in the onApprove function of the PayPal JS SDK setup method to tokenize the PayPal account. After the customer completes the consent flow and the PayPal pop-up closes, successful tokenization will return a payment method nonce.

Send the nonce to your server and use a Braintree server SDK to call PaymentMethod.create, which creates a PayPal payment method in your Vault. Alternatively, use Transaction.sale to create a transaction.

Returning customer experienceanchor

This allows customers the flexibility to change the payment method that they had previously selected within the PayPal Wallet when storing it within a vault.

Customers can choose to change the payment method by clicking on the PayPal button as seen below and clicking the link Change payment method.

The PayPal button can be rendered as a Change payment method button for vaulted customers.

  1. Be sure to use the One-time Payments flow instead of the Vault flow
  2. Use a client token generated with a customer ID that has a vaulted PayPal Billing Agreement when initializing the Braintree client instance
  3. Set autoSetDataUserIdToken: true when initializing the Braintree PayPal Checkout instance
  4. Optionally set additional dataAttributes, such as amount, when using the Braintree PayPal Checkout instance to load the PayPal SDK. For details, see the PayPal docs.
  1. Callback
  2. Promise
// Create a client.
braintree.client.create({
  authorization: CLIENT_TOKEN_ENCODED_WITH_CUSTOMER_ID
}, function (clientErr, clientInstance) {

  // Create a PayPal Checkout component.
  braintree.paypalCheckout.create({
    autoSetDataUserIdToken: true,
    client: clientInstance
  }, function (paypalCheckoutErr, paypalCheckoutInstance) {
    paypalCheckoutInstance.loadPayPalSDK({

      // The following are optional params
      dataAttributes: {
        amount: "100.00"
      }
    }, function () {
      paypal.Buttons({
        fundingSource: paypal.FUNDING.PAYPAL,

        createOrder: function () {
          return paypalCheckoutInstance.createPayment({
            //...
          });
        },

        onApprove: function (data, actions) {
          return paypalCheckoutInstance.tokenizePayment(data, function (err, payload) {
            // Submit 'payload.nonce' to your server
          });
        },

        onCancel: function (data) {
          console.log('PayPal payment canceled', JSON.stringify(data, 0, 2));
        },

        onError: function (err) {
          console.error('PayPal error', err);
        }
      }).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
      });

    });

  });

});

When you receive a result via onPayPalSuccess, you can query the PayPalAccountNonce result for specific customer information.

Collecting device dataanchor

Collecting device data from your customers is required when initiating non-recurring transactions from Vault records. Collecting and passing this data with transactions will help reduce decline rates.

To collect device data for PayPal, use the dataCollector component. If you're using script tags to load files, make sure to include:

  1. HTML
<script src="https://js.braintreegateway.com/web/3.111.0/js/data-collector.min.js"></script>
  1. Callback
  2. Promise
var myDeviceData;

braintree.client.create({
  authorization: 'TOKEN',
}, function (err, clientInstance) {
  braintree.dataCollector.create({
    client: clientInstance,
  }, function (err, dataCollectorInstance) {
    if (err) {
      // Handle error
      return;
    }
    // At this point, you should access the dataCollectorInstance.deviceData value and provide it
    // to your server, e.g. by injecting it into your form as a hidden input
    myDeviceData = dataCollectorInstance.deviceData;
  });

  // Initialize your PayPal Checkout component here
  braintree.paypalCheckout.create(/* ... */);
});

To cleanly reset your integration, call teardown() on the dataCollectorInstance object.

  1. JavaScript
dataCollectorInstance.teardown();

App Switchanchor

The App Switch initiative will enable PayPal users that have a PayPal app installed on their phone to complete payment on the app when it is available.

This new feature enables a version of App Switch that avoids the interstitial page previously required. This design requires a merchant to adopt a new integration pattern called “redirect flow” that supports the ability for a full page client-side redirect within the browser either to App Switch or to redirect to PayPal in the same tab.

Initialize the SDK via the client tokenanchor

Your server is responsible for generating a client token that contains all the authorization and configuration information your client needs to initialize the client SDK to communicate with Braintree. Braintree offers different languages for integrating with its Server SDKs, and the following example is using Node.js: Documentation on Client Tokens: Braintree Developer Documentation

import braintree from "braintree"
const gateway = new braintree.BraintreeGateway({
  environment: braintree.Environment.Sandbox,
  merchantId: MERCHANT_ID,
  publicKey: PUBLIC_KEY,
  privateKey: PRIVATE_KEY,
});
const { clientToken } = await gateway.clientToken.generate({})
Client-Side integrationanchor

createOrderCallback has two new options to opt into the app switch flow: returnUrl and cancelUrl. Merchants can pass in the new options in their paypalCheckoutInstance.createPayment() call like this:

createOrder: function() {
  return paypalCheckoutInstance.createPayment({
    // other options
    returnUrl: 'example.com/return',
    cancelUrl: 'example.com/cancel'
  })
};
const buttons = paypal
  .Buttons({
    // Sets up the transaction when a payment button is clicked
    appSwitchWhenAvailable: true, // Need an indicator to trigger app switch
    createOrder: createOrderCallback, //call API to create order
    onApprove: onApproveCallback,
    onError: function (error) {
      // Do something with the error from the SDK
    },
  });
// If you suport app switch, depending on the browser the buyer may end up in a new tab
// To trigger completion of the flow, execute the code below after re-instantiating buttons
if (buttons.hasReturned()) {
  buttons.resume();
} else {
  buttons.render("#paypal-button-container");
}

Shipping addressanchor

Shipping addresses collected during the PayPal Vault flow. However, if you choose to collect shipping addresses yourself, it can be passed along with the server side Transaction.Sale call. Look at the Server-side page for more information.

Country and language supportanchor

PayPal is available to merchants in all countries that we support and to customers in 140+ countries. Ensure you are using a desired locale code as outlined in our JavaScript PayPal client reference.

Currency presentmentanchor

In the Vault flow itself, the transaction currency and amount are not displayed to the customer. It is up to you to display these details in your checkout flow somewhere (e.g. cart page, order review page, etc.). Our Server-Side guide outlines which currencies are supported for PayPal transactions.


Next Page: Recurring Payments