checkout

Upgrade your Checkout Integration

If you have an existing PayPal Checkout integration that uses an older version of checkout.js, follow this guide 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 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, you should understand the new key concepts of the PayPal 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.

Buyer's checkout flow

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 a GET request 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 webservice 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 optionally 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.

(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);
})();
Feedback

Have feedback?

Let us know.