Upgrade your Checkout integration

This page describes the process that existing PayPal Checkout merchants can follow to upgrade to the latest PayPal Checkout integration (checkout.js v4). The new code keeps you current with the latest button styles and payment features.

Note: If you're integrating PayPal Checkout for the first time, follow the steps in the PayPal Express Checkout Integration Guide.

These steps are required to complete the upgrade process:

1 Understand the new PayPal Checkout flow.
2 Include the JavaScript.
3 Add the button.
4 Configure payment callback.
5 Test your integration.

1. Understand the new PayPal Checkout flow

Before you start the upgrade, PayPal recommends that you first understand the new PayPal Checkout flow.

These are the new key concepts in the checkout flow:

  • Rather than using a static image, you are now required to use the checkout.js script to render the PayPal button.
  • The PayPal Checkout flow now launches in a popup window, rather than in a full-page redirect.
  • After the buyer authorizes the transaction, the PayPal Checkout flow calls your pre-defined JavaScript callback, rather than redirecting the buyer to a return URL.

2. Include the JavaScript

Include the Checkout JavaScript on the page:

<script src="https://www.paypalobjects.com/api/checkout.js"></script>

To boost performance, include the script asynchronously on a prior page so that the script is cached when needed:

<script src="https://www.paypalobjects.com/api/checkout.js" async></script>

3. Add the button

Add the following HTML on the page where you want to render the new PayPal button:

<div id="paypal-button">
<script>
  (function() {
    paypal.Button.render({
        env: 'production', // Or 'sandbox',
        payment: function(data, actions) {
            // You'll configure this in the following steps.
        },
          onAuthorize: function(data, actions) {
            return actions.redirect();
          },
          onCancel: function (data, actions) {
            return actions.redirect();
          },
          onError: function (error) {
            // You will want to handle this differently
            return alert(error);
          }
      }, '#paypal-button');
  })();
</script>

4. Configure payment callback

The payment callback must return the PayPal token from your existing integration.

Form integration

Note: Alternatively, try the Redirect upgrade script.

If your current integration uses a form similar to this example:

<form id="paypalForm" method="post" action="/classic/setexpresscheckout">
    <input type="hidden" name="action" value="Sale" />
    <input type="image" src="https://www.paypalobjects.com/webstatic/en_US/i/buttons/checkout-logo-large.png" />
</form>

Add this code to your script tag above the button render call:

var paypalForm = document.getElementById('paypalForm');
paypalForm.style.display = 'none';
function formEncode(form) {
  var ret = {};
  Object.keys(form.elements).forEach(function (key) {
    ret[form.elements[key].name] = form.elements[key].value;
  });
  return ret;
}

Then use this code in your payment callback:

payment: function (data, actions) {
  return paypal.request.post(paypalForm.getAttribute('action'), formEncode(paypalForm), {
    headers: {
        'Accept': 'application/paypal-json-token',
    }
  })
  .then(function (response) {
    if (!response || !response.token) {
      throw new Error('There was an error fetching the PayPal token');
     }
      return response.token;
  })
  .catch(function (err) {
    throw err;
  });
}

Note: Alternatively, try the Redirect upgrade script.

If your current integration uses the GET method with a link tag similar to this example:

<a id="paypalLink" href="/classic/setexpresscheckout">
    <img src="https://www.paypalobjects.com/webstatic/en_US/i/buttons/checkout-logo-large.png"/>
</a>

Add the following code above your render call:

var paypalLink = document.getElementById('paypalLink');
paypalLink.style.display = 'none';

Then use this code in your payment callback:

payment: function (data, actions) {
  return paypal.request.get(paypalLink.getAttribute('href'), {
    headers: {
      'Accept': 'application/paypal-json-token',
    }
  })
  .then(function (response) {
     if (!response || !response.token) {
      throw new Error('There was an error fetching the PayPal token');
   }
     return response.token;
    })
    .catch(function (err) {
      throw err;
    });
}

AJAX integration

If your integration uses a web service and AJAX similar to this example:

<div id="paymentMethods">
    <button id="paypalButton">Pay with PayPal</button>
</div>

<script>
    document.querySelector('#paypalButton').addEventListener('click', function(event) {
      jQuery.post('/create-paypal-token', function(data) {
        window.location = 'https://www.paypal.com/checkoutnow?token=' + data.token;
      });
    });
</script>

Simply place your AJAX call into the payment callback:

payment: function(data, actions) {
    return new paypal.Promise(function(resolve, reject) {
        jQuery.post('/create-paypal-token', function(data) {
          resolve(data.token);
      });
  });
}

5. Test your integration

You're now ready to test your integration.

302 Redirect upgrade script

Note: You can use this script to easily upgrade a 302 redirect integration. This script simplifies the upgrade process as much as possible, but is not guaranteed to work in every situation. If you are an advanced developer, use this script as a template to upgrade your specific integration.

<script>
  (function() {
      // Change me!
      var currentIntegrationId = 'paypalForm'; // DOM id of your current integration.
      var integrationType = "FORM";  // Set to FORM or LINK
      var newIntegrationId = "paypal-button"; // DOM id of the new integration container where the button renders
      var errorCallback = function (error) {
          return alert('There was an error');
      }

      // You should not have to change anything below

      function formEncode(form) {
          var ret = {};
          Object.keys(form.elements).forEach(function (key) {
            ret[form.elements[key].name] = form.elements[key].value;
          });
          return ret;
      }
      var currentIntegration = document.getElementById(currentIntegrationId);
      currentIntegration.style.display = "none";
      paypal.Button.render({
        env: 'production', // Or 'sandbox',
        payment: function(data, actions) {
          var paypalRequest;
            if (integrationType === "FORM") {
              if (currentIntegration.getAttribute('method').toLowerCase() === 'post') {
                 paypalRequest = paypal.request.post(currentIntegration.getAttribute('action'), formEncode(currentIntegration), {
                   headers: {
                     'Accept': 'application/paypal-json-token',
                    }
                    });
                  } else if (currentIntegration.getAttribute('method').toLowerCase() === 'get') {
                      var formObj = formEncode(currentIntegration);
                      var queryString = Object.keys(formObj).map(function(key) {
                        return key + '=' + formObj[key]
                      }).join('&');
                      paypalRequest = paypal.request.get(currentIntegration.getAttribute('action') + '?' + queryString, {
                        headers: {
                          'Accept': 'application/paypal-json-token',
                        }
                      });
                  }
              } else if (integrationType === 'LINK') {
                  paypalRequest = paypal.request.get(currentIntegration.getAttribute('href'), {
                    headers: {
                      'Accept': 'application/paypal-json-token',
                    }
                  });
                }

              return paypalRequest
                  .then(function (response) {
                    if (!response || !response.token) {
                        throw new Error('There was an error fetching the PayPal token');
                    }
                    return response.token;
                  })
                    .catch(function (err) {
                      // throw the error to the onError callback
                      throw err;
                  });
              
          },
          onAuthorize: function(data, actions) {
            return actions.redirect();
          },
          onCancel: function (data, actions) {
            return actions.redirect();
          },
          onError: errorCallback

      }, '#' + newIntegrationId);
  })();
  </script>