PayPal allowed states of a Country

PayPal only allows a defined set of states for a small number of countries. The allowed states are documented here on the PayPal website: State and province codes.

States must only be set for the following countries. For any other country, the state field must be left blank.

Country
Argentina
Brazil
Canada
China
India
Indonesia
Italy
Japan
Mexico
Thailand
USA

PayPal on your checkout page using PayPal JavaScript SDK

This describes how the PayPal payment option can be displayed on your checkout page where a PayPal payment
button is enabled with help of a javascript. The PayPal JavaScript SDK displays PayPal-supported payment
methods on your checkout page to give your buyers a personalized and streamlined checkout experience.

This link gives more details about the PayPal Javascript SDK.

PayPal is available in the menu if the prerequisites are fulfilled.
No additional information is required in the create-request.

This rest of this page covers how to implement PayPal on your own checkout page.

Prerequisites

For PayPal the PayPal payment method has to be enabled on your merchant account.
PayPal button with PayPal Javascript SDK can only be used on your own checkout page after you have been
enrolled as merchant at PayPal via Payment system backoffice.
Please contact our support to get enrolled.

Payment Flow

The following diagram shows the payment flow when using PayPal on your checkout page.

PayPal JavaScript SDK Payment Flow

Creating an Order

An order has to be created before PayPal can be used. (See Create a new order.)

List payment methods to get PayPal payment urls.

The List Payment Methods API call returns the available payment methods which includes the PalPal
details with the required script url, action url and the business code which has to be included as part
of the Javascript SDK. (See List payment methods.)

The result of List payment methods should include the following
details as part of api response.

{
	"method": "PAYPAL_EXPRESS_CHECKOUT",
	"paypal_details": {
		"action_url": "http://localhost:8080/ps/api/public/merchants/0e4c4c10-7b7f-4de5-9640-f5497126836a/orders/4EFCF737B352B8B42FC700F6C09AADC8/paypal",
		"script_url": "https://www.paypal.com/sdk/js?client-id=AaN5v3KZF7zrct8r9cuBCmel6qVh-Svut5kj5MhWSDiH6ozjuTJAN9ppCzL6PTYqfQucFBIBbrKA2I0-&merchant-id=MERCHT-ID-182a402b-4&currency=EUR&intent=capture&enable-funding=paylater&disable-funding=card%2Cbancontact%2Cblik%2Ceps%2Cgiropay%2Cideal%2Cmercadopago%2Cmybank%2Cp24%2Csepa%2Csofort%2Cvenmo&commit=true&vault=false",
		"business_code": "CM_Payments_PPCP"
	}
}

From the response, the paypal_details has all the required details to the PayPal Javascript SDK.

  • The script_url is the url to load the PayPal Javascript SDK from the paypal server.
  • The action_url is the url to connect to the Payment System which actually creates and updates the status of the payment.
  • The business_code is the code that is part of the script attribute which is necessary to do the Payment processing.

Load PayPal JavaScript SDK

Use the script_url to load the PayPal Javascript SDK from the PayPal server. It has all the
necessary parameters like client id, merchant id, currency and the funding methods.

Because of the dynamic nature of the script_url it is recommended to load the PayPal Javascript SDK by using JavaScript
to create an element of type text/javascript.

The business_code must be set as the script attribute data-partner-attribution-id.

Example javascript:

function loadPaypalScript(scriptUrl, businessCode, actionUrl) {
    var head = document.head;
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.setAttribute('data-partner-attribution-id', businessCode);
    script.src = scriptUrl;

    ...
  
    // Fire the loading
    head.appendChild(script);
}

Because the loading of the PayPal JavaScript SDK is done in JavaScript the PayPal buttons must be initialized
in a callback function, which is then bound to the onreadystatechange and onload events.

Example javascript:

    ...

    var callback = function() {
        paypal.Buttons({
            
                ...
            
            }
        ).render(...);
    };

    // Then bind the event to the callback function.
    // There are several events for cross browser compatibility.
    script.onreadystatechange = callback;
    script.onload = callback;

    ...

Style the PayPal buttons

Customize the buttons using the style option as described by PayPal.
PayPal has requirements on the look, size and placement on the PayPal button.

Example javascript:

    paypal.Buttons({
            style: {
                layout: 'vertical', color: 'gold', shape: 'rect', label: 'buynow', height: 40
            },

            ...
        }
    ).render('#paypal-button-container');

The render function shows the payment buttons on your web page in the defined container selector.

Initialize callback functions

The callback functions of the buttons should be initialezed with the action_url to connect to the Payment
System which actually creates and updates the status of the payment.

createOrder callback function

The createOrder callback function is called when the buyer selects the PayPal button. The callback should
use the action_url to notify the Payment System that the buyer selected to pay with PayPal and that a
payment should be created. The Payment System returns the Order Id of the created PayPal payment in the
json response, which should be passed on to the PayPal JavaScript SDK. As a result the PayPal Checkout
window will be launched by the SDK.

Action url details:

HTTP verbPOST
URLaction_url
Headersnot applicable
Bodynot applicable
Response{"order_id": "orderID"}

Example javascript:

    paypal.Buttons({
    
            ...

            createOrder: function (data, actions) {
                return fetch(actionUrl, {
                    method: 'post'
                }).then(function (res) {
                    return res.json();
                }).then(function (data) {
                    return data.order_id;
                });
            },

            ...

onApprove callback function

The onApprove callback function is called after the buyer approves the transaction on the PayPal website.
The callback should use the action url, appended with the Order ID provided by the callback function, to
notify the Payment System that the payment was approved by the buyer. The json body of the request must
contain the action ON_APPROVE.

Action url details:

HTTP verbPOST
URLaction_url/{orderID}
HeadersContent-Type: application/json
Body{"action": "ON_APPROVE"}
Responsenot applicable

Example javascript:

    paypal.Buttons({
    
            ...

            onApprove: function (data, actions) {
                return fetch( actionUrl + '/' + data.orderID, {
                    method: 'POST',
                    headers: {
                        "Content-Type": "application/json",
                    },
                    body: '{"action": "ON_APPROVE"}'
                }).then(function (res) {
                    // Determine the status of the order
                });
            },


            ...

onCancel callback function

The onCancel callback function is called when a buyer cancels the payment on the PayPal website.
The callback should use the action url, appended with the Order ID provided by the callback function, to
notify the Payment System that the payment was canceled by the buyer. The json body of the request must
contain the action ON_CANCEL.

Action url details:

HTTP verbPOST
URLaction_url/{orderID}
HeadersContent-Type: application/json
Body{"action": "ON_CANCEL"}
Responsenot applicable

Example javascript:

    paypal.Buttons({
    
            ...

            onCancel: function (data, actions) {
                return fetch( actionUrl + '/' + data.orderID, {
                    method: 'POST',
                    headers: {
                        "Content-Type": "application/json",
                    },
                    body: '{"action": "ON_CANCEL"}'
                }).then(function (res) {
                    // Determine the status of the order
                });
            },

            ...

onError callback function

The onError callback function is called when an error prevents the buyer from approving or canceling the
payment on the PayPal website. The callback should use the action url, appended with the Order ID provided
by the callback function, to notify the Payment System that an error occured while approving the payment.
The json body of the request must contain the action ON_ERROR.

Action url details:

HTTP verbPOST
URLaction_url/{orderID}
HeadersContent-Type: application/json
Body{"action": "ON_ERROR"}
Responsenot applicable

Example javascript:

    paypal.Buttons({
    
            ...

            onError: function (errorData) {

                try{
                    const response = fetch( actionUrl + '/' + data.orderID, {
                        method: 'POST',
                        headers: {
                            "Content-Type": "application/json",
                        },
                        body: '{"action": "ON_ERROR"}'
                    }).then(function (res) {
                        // Determine the status of the order
                    });

                    if (response.status !== 200) {
                        ...
                    }
                } catch (error) {
                    ...
                }
            }
            
            ...

Determining the status of the order

The Payment System sends status change notifications to the customer service agent application during the authorization of the payment, which should be used to get the order details from the Payment System.

The order details should be used to determine if the shopper has paid the order or that another payment attempt can be made by the shopper.

Full JavaScript example

Below is the full JavaScript that is used by the menu to support PayPal as an example.

<!DOCTYPE html>
<html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
        <!-- The link to javascript content of functions 'loadPaypalScript' and 'addButtons' as given below -->
        <script src="<link to PayPal Js script>"></script>
        <!-- Set up a container element for the PayPal button -->
        <div id="paypal-button-container"></div>
    </body>
</html>
/**
 * Load the Paypal JavaScript SDK
 *
 * @param scriptUrl
 * @param businessCode
 * @param actionUrl The url of the PS Paypal controller to start the payments.
 */
function loadPaypalScript(scriptUrl, businessCode, actionUrl) {
    // Adding the script tag to the head
    var head = document.head;
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.setAttribute('data-partner-attribution-id', businessCode);
    script.src = scriptUrl;

    var callback = function() {
        addButtons(actionUrl)
    };

    // Then bind the event to the callback function.
    // There are several events for cross browser compatibility.
    script.onreadystatechange = callback;
    script.onload = callback;

    script.onerror = function() {
        console.log("Loading the PayPal JavaScript SDK has failed");
        window.onPaypalScriptFailed();
    };

    // Fire the loading
    head.appendChild(script);
}

/**
 * Add Paypal buttons to the menu.
 *
 * @param url The url of the PS Paypal controller to start the payments.
 */
function addButtons(url) {
    paypal.Buttons({
            style: {
                layout: 'vertical', color: 'gold', shape: 'rect', label: 'buynow', height: 40
            },

            createOrder: function (data, actions) {
                return fetch(url, {
                    method: 'post'
                }).then(function (res) {
                    return res.json();
                }).then(function (data) {
                    return data.order_id;
                });
            },

            onApprove: function (data, actions) {
                console.log("PayPal payment approved.");
                return fetch( url + '/' + data.orderID, {
                    method: 'POST',
                    headers: {
                        "Content-Type": "application/json",
                    },
                    body: '{"action": "ON_APPROVE"}'
                }).then(function (res) {
                    window.pollOrderStatus();
                });
            },


            onCancel: function (data, actions) {
                console.log("Customer cancelled the PayPal Checkout Flow");
                return fetch( url + '/' + data.orderID, {
                    method: 'POST',
                    headers: {
                        "Content-Type": "application/json",
                    },
                    body: '{"action": "ON_CANCEL"}'
                }).then(function (res) {
                    window.pollOrderStatus();
                });
            },

            onError: function (errorData) {
                console.log("An Error occurred as part of the PayPal JavaScript SDK." + errorData);

                try{
                    const response = fetch( url + '/' + data.orderID, {
                        method: 'POST',
                        headers: {
                            "Content-Type": "application/json",
                        },
                        body: '{"action": "ON_ERROR"}'
                    }).then(function (res) {
                        window.pollOrderStatus();
                    });

                    //handle when the response has http status code between 400 and 500 i.e response from PS (via actionUrl)
                    if (response.status !== 200) {
                        console.log('Received invalid response while performing ON_ERROR function');
                        window.showPaymentCanceled()
                    }
                } catch (error) {
                    //also handle the error if there are exception while processing the api call.
                    console.log('Error while performing ON_ERROR function',error);
                    window.showPaymentCanceled()
                }
            }
        }
    ).render('#paypal-button-container');
}

The script accepts scriptUrl, businessCode and actionUrl and those details can be found in List Payment Methods.

FunctionPurpose
loadPaypalScriptHelps to load the PayPal payment button using the scriptUrl, businessCode and actionUrl. These details can be found in the List Payment Methods response.
addButtonsThe function addButtons is called internally by the loadPaypalScript function to set the style of the buttons, make them visible visible, and add the callback functions to start and complete payments using the action url. The buttons are added to the div #paypal-button-container.
window.pollOrderStatus()The window.pollOrderStatus(); method is only available in the menu, and used to get the details of the order and redirect the shopper back to the webshop if appropriate.
window.showPaymentCanceled()The window.showPaymentCanceled(); method is only available in the menu to show a message that the authentication or authorization failed.