Braintree- Billing Agreements

SDK

Last updated: Aug 4th, 1:26pm

Overview

This guide explains how to implement PayPal payment vaulting (save payment methods) using the PayPal v6 Web SDK with Braintree integration, allowing customers to save their PayPal payment method for future use without requiring an immediate purchase.

Prerequisites

Before integrating save payment functionality, ensure you have a Braintree Sandbox Account with PayPal linked, a PayPal Developer Account with Vault feature enabled, and server-side API endpoints for client token generation and payment method saving.

HTML Structure Setup

Create the basic HTML structure with a hidden PayPal button and required script dependencies including Braintree Client SDK, Braintree PayPal Checkout component, and PayPal Web SDK v6.

    1<!doctype html>
    2<html lang="en">
    3 <head>
    4 <meta charset="UTF-8" />
    5 <title>Vault Payments - Braintree Integration with PayPal Web SDK</title>
    6 <meta name="viewport" content="width=device-width, initial-scale=1" />
    7 </head>
    8 <body>
    9 <h1>Vault Payments - Braintree Integration with PayPal Web SDK</h1>
    10
    11 <div>
    12 <paypal-button id="paypal-button" hidden></paypal-button>
    13 </div>
    14
    15 <script src="app.js"></script>
    16 <script src="https://js.braintreegateway.com/web/3.124.0/js/client.min.js"></script>
    17 <script src="https://js.braintreegateway.com/web/3.124.0/js/paypal-checkout.min.js"></script>
    18 <script
    19 async
    20 src="https://www.sandbox.paypal.com/web-sdk/v6/core"
    21 onload="onPayPalWebSdkLoaded()"
    22 ></script>
    23 </body>
    24</html>

    PayPal and Braintree Initialization

    Initialize both PayPal and Braintree instances using the client token from your server, create the PayPal instance with billing agreements component, and set up the Braintree PayPal checkout component.

      1async function onPayPalWebSdkLoaded() {
      2 try {
      3 const braintreeClientToken = await getBraintreeBrowserSafeClientToken();
      4
      5 // Create PayPal instance
      6 const paypalInstance = await window.paypal.createInstance({
      7 clientToken: braintreeClientToken,
      8 components: ['paypal-legacy-billing-agreements'],
      9 pageType: 'checkout',
      10 });
      11
      12 // Create Braintree instance
      13 const braintreeInstance = await window.braintree.client.create({
      14 authorization: braintreeClientToken,
      15 });
      16
      17 // Create PayPal checkout component
      18 const braintreeCheckout = await window.braintree.paypalCheckout.create({
      19 client: braintreeInstance,
      20 });
      21
      22 setupPayPalButton({ paypalInstance, braintreeCheckout });
      23 } catch (error) {
      24 console.error(error);
      25 }
      26}

      PayPal Button Configuration

      Set up the PayPal button with billing agreement session, configure callback handlers for approval, cancellation, and errors, and implement the click handler to start the save payment flow.

        1async function setupPayPalButton({ paypalInstance, braintreeCheckout }) {
        2 const paypalPaymentSession = paypalInstance.createPayPalBillingAgreementWithoutPurchase({
        3 async onApprove(data) {
        4 // Tokenize the payment method
        5 const { nonce } = await braintreeCheckout.tokenizePayment({
        6 billingToken: data.billingToken,
        7 payerID: data.payerId,
        8 paymentID: data.orderId,
        9 vault: true,
        10 });
        11
        12 // Save payment method
        13 const orderData = await completePayment(nonce);
        14 console.log('Save result', orderData);
        15 },
        16 onCancel(data) {
        17 console.log('Payment cancelled', data);
        18 },
        19 onError(error) {
        20 console.log('Payment error', error);
        21 },
        22 });
        23
        24 // Show button and add click handler
        25 const paypalButton = document.querySelector('#paypal-button');
        26 paypalButton.removeAttribute('hidden');
        27
        28 paypalButton.addEventListener('click', async () => {
        29 await paypalPaymentSession.start(
        30 { presentationMode: 'auto' },
        31 createOrder(braintreeCheckout)
        32 );
        33 });
        34}

        Payment Order Creation

        Create a Braintree payment with vault flow configuration, set billing agreement description, and optionally configure shipping address collection and override settings.

          1async function createOrder(braintreeCheckout) {
          2 const billingToken = await braintreeCheckout.createPayment({
          3 flow: 'vault', // Required for save payment
          4 billingAgreementDescription: 'Your agreement description',
          5 enableShippingAddress: true,
          6 shippingAddressEditable: false,
          7 shippingAddressOverride: {
          8 recipientName: 'Customer Name',
          9 line1: '1234 Main St.',
          10 city: 'Chicago',
          11 countryCode: 'US',
          12 postalCode: '60652',
          13 state: 'IL',
          14 phone: '123.456.7890'
          15 }
          16 });
          17
          18 return { billingToken };
          19}

          Client Token Endpoint

          Implement a server endpoint to generate and return Braintree client tokens for frontend authentication and authorization with proper error handling.

            1// GET /api/braintree/browser-safe-client-token
            2app.get('/api/braintree/browser-safe-client-token', (req, res) => {
            3 gateway.clientToken.generate({}, (err, response) => {
            4 if (err) {
            5 res.status(500).json({ error: err.message });
            6 } else {
            7 res.json({ accessToken: response.clientToken });
            8 }
            9 });
            10});

            Save Payment Method Endpoint

            Implement a server endpoint to save payment methods using the payment method nonce from the frontend, associate with customer ID, and return success confirmation.

              1// POST /api/braintree/payment-method/save
              2app.post('/api/braintree/payment-method/save', (req, res) => {
              3 const { paymentMethodNonce } = req.body;
              4
              5 gateway.paymentMethod.create({
              6 customerId: 'customer_id', // Your customer ID
              7 paymentMethodNonce: paymentMethodNonce
              8 }, (err, result) => {
              9 if (err || !result.success) {
              10 res.status(500).json({ error: err?.message || 'Payment method save failed' });
              11 } else {
              12 res.json({
              13 success: true,
              14 paymentMethod: result.paymentMethod
              15 });
              16 }
              17 });
              18});

              Client Token Retrieval Function

              Implement a frontend function to fetch the Braintree client token from your server endpoint with proper error handling and response parsing.

                1async function getBraintreeBrowserSafeClientToken() {
                2 const response = await fetch('/api/braintree/browser-safe-client-token', {
                3 method: 'GET',
                4 headers: {
                5 'Content-Type': 'application/json',
                6 },
                7 });
                8
                9 if (!response.ok) {
                10 throw new Error('Failed to fetch client token');
                11 }
                12
                13 const { accessToken } = await response.json();
                14 return accessToken;
                15}

                Complete Payment Function

                Implement the function to send the payment method nonce to your server for saving, handle the response, and provide user feedback on the save operation status.

                  1async function completePayment(nonce) {
                  2 const response = await fetch('/api/braintree/payment-method/save', {
                  3 method: 'POST',
                  4 headers: {
                  5 'Content-Type': 'application/json',
                  6 },
                  7 body: JSON.stringify({
                  8 paymentMethodNonce: nonce
                  9 }),
                  10 });
                  11
                  12 if (!response.ok) {
                  13 throw new Error('Failed to save payment method');
                  14 }
                  15
                  16 const result = await response.json();
                  17 return result;
                  18}

                  Next Steps After Implementation

                  After successfully saving a payment method, store the payment method token securely, use the token for future transactions, implement payment method management UI, and add customer notification features for saved payment methods.

                  Additional Resources

                  Access comprehensive documentation through Braintree Developer Documentation, PayPal v6 Web SDK Documentation, PayPal Developer Dashboard, and Braintree Control Panel for testing and management of saved payment methods.

                  Please follow this link to our public Github examples.