PayPal
Migrating from checkout.js to the PayPal JS SDK
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.92.1/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.92.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.92.1/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.92.1/js/paypal-checkout.min.js"></script>
- Callback
- Promise
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:
- Callback
- Promise
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.92.1/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.92.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 > Account Settings > 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.
- Callback
- Promise
// 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
.
- JavaScript
- JavaScript
// 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');
// PayPal JS SDK
paypal.Buttons({
onApprove: function (data) {
return paypalCheckoutInstance.tokenizePayment(data).then(function (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:
- Callback
- Promise
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:
- Callback
- Promise
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
.
- Callback
- Promise
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
});
});
});
});