Checkout with PayPal Commerce

This plugin enables payments with a customers PayPal account or with credit card.

Set up

To configure PayPal Commerce plugin in Centra go to store plugins, select desirable plugin and you should see similar screen to the screenshot below.

paypal-commerce-setup.png

To connect your account just click Connect with PayPal button and follow steps on PayPal page. This operation will bind your account with Centra. After this you can start using PayPal Commerce.

If the plugin is setup on your Q/A server it will talk to the PayPal sandbox, or for the production server it will talk to PayPal's production.

Override Shipping Address can only be used with the redirect mode and allows you to set the address to use in your checkout.

You can also restrict PayPal to only work for specified markets, pricelists, countries or languages.

Limitations

We require the customer to select the correct country and state before starting the PayPal checkout process.

Usage

This plugin can be used in 2 ways: either the checkout redirects to PayPal, or you render what PayPal calls smart buttons on the checkout page, which enables payments with either credit card or PayPal account.

Redirect

This method is identical to how Centra's previous PayPal plugin worked. It works by responding with a URL that you will redirect the customer to, and once the customer is done with the payment they will be redirected back to the webshop, where you can call our payment-result endpoint just as described in our Payment method flows documentation.

Smart Buttons

Includes buttons generated by PayPal on the checkout page which launches PayPal in a popup.

Flow

The flow works like this:

  1. Customer adds products to their cart. The country is either selected by the customer or selected by Geo-IP (based on the IP-address of the customer).
  2. The website makes a POST /payment request with the address.country (and address.state, if state is selected) for the customer, together with a paymentInitiateOnly:true-parameter. This tells Centra not to set the payment option as the selected one (since the payment button is selected opt-in by the customer when pressing it). This call can be made directly when the user accesses the checkout page.
  3. Centra will return a snippet that will try to launch the payment request button inside its own <div> provided in the snippet. You can also set the selector of the payment button by setting the window.paypalSmartButtonSelector-variable in the DOM.
  4. If the customer changes anything in their selection, such as the quantity for a product, a similar POST /payment call as explained in #2 needs to be run to reload the payment button snippet with the proper amount set.

Events

Since Centra does not know how you make requests to the API, you need to listen to events from the payment button and trigger API-calls to Centra based on what they are used for. PayPal commerce currently have one event centra_checkout_payment_callback which is triggered when a payment is completed.

Payment Initialization

To get the buttons, start by making a call to POST /payment:

{
    "address": {
        "country": "SE"
    },
    "paymentMethod": "paypal-commerce",
    "paymentInitiateOnly": true,
    "termsAndConditions": true,
}

This will result in a response with action form and the formHtml field which will contain HTML + JavaScript that is expected to run on your website. It will include the PayPal JavaScript code and initialize the buttons in the <div> element provided in the formHtml code. Alternatively, you can choose to decide where these buttons go by specifying a selector by setting the window.paypalSmartButtonSelector-variable.

Response example:

{
    "action": "form",
    "formType": "paypal_commerce",
    "formFields": {
        "id": "<paypal-token>"
    },
    "formHtml": "<div id=\"paypal-button-yrdjjofjruuxuqhlr2vznlxumqgw0v1t97qhbpm\"></div>\n<script src=\"https://www.paypal.com/sdk/js?client-id=<client-id>&merchant-id=<merchant-id>&currency=SEK&intent=authorize&integration-date=2021-03-01\"></script>\n<script id=\"paypal-script-yrdjjofjruuxuqhlr2vznlxumqgw0v1t97qhbpm\" data-payment-method=\"paypal_commerce\">\n    var randomId = \"yrdjjofjruuxuqhlr2vznlxumqgw0v1t97qhbpm\";\n    var country = \"SE\";\n    var buttonElement = window.paypalSmartButtonSelector || \"#paypal-button-\" + randomId;\n    var scriptObject = document.getElementById(\"paypal-script-\" + randomId);\n    var paymentMethod = scriptObject.dataset.paymentMethod;\n    paypal.Buttons({\n        createOrder: function (data, actions) {\n          return \"<paypal-token>\";\n        },\n        onApprove: function (data, actions) {\n            var eventObject = {\n              paymentMethod: paymentMethod,\n              paymentMethodSpecificFields: {\n                  payment_method_id: data.orderID\n              },\n              responseEventRequired: false,\n              addressIncluded: false,\n              shippingAddress: {\n                country: country,                                      \n              },\n              billingAddress: {\n                country: country,                                      \n              },\n            };\n            \n            paymentCompleteEvent = new CustomEvent(\"centra_checkout_payment_callback\", {detail:eventObject});\n            document.dispatchEvent(paymentCompleteEvent);\n            \n            return true;\n        }\n      }).render(buttonElement);\n</script>"
}

Payment finalization

We will now handle the final event happening when payment is completed in PayPal by the customer. We previously registered the following handler:

document.addEventListener('centra_checkout_payment_callback', this.paymentSelected);

Which is the one that will trigger now.

The following data is returned in this event:

.. list-table::
   :widths: auto
   :class: small-table
   :header-rows: 1

   * - Field
     - Type
     - Comment
   * - ``responseEventRequired``
     - boolean
     - Always ``false`` for PayPal.
   * - ``addressIncluded``
     - boolean
     - Always ``false`` for PayPal.
   * - ``paymentMethodSpecificFields``
     - object
     - | This data should be sent to the ``POST /payment`` call
       | in Centra for the payment to be validated.
   * - ``paymentMethod``
     - string
     - The selected payment method used.
   * - ``billingAddress``
     - object
     - Data containing the address for billing. for PayPal just contains country and state
   * - ``billingAddress.state``
     - string
     - Optional, can be empty for countries not supporting states.
   * - ``billingAddress.country``
     - string
     - Country code
   * - ``shippingAddress``
     - object
     - Data containing the address for shipping. For PayPal just contains country and state
   * - ``shippingAddress.state``
     - string
     - Optional, can be empty for countries not supporting states.
   * - ``shippingAddress.country``
     - string
     - Country code

We would take the event data, and create a checkoutRequest based on the data provided. This data would then be sent to the POST /payment in the Centra API.

paymentSelected = (event: any) => {
    const { checkoutRequest: checkout } = this.props;
    const { paymentMethodSpecificFields, paymentMethod } = event.detail;
    const { billingAddress: billingAddressData, shippingAddress: shippingAddressData } = event.detail;
    const billingAddress: IAddress = Address.create(billingAddressData);
    const shippingAddress: IAddress = Address.create(shippingAddressData);
    checkout({
        paymentMethodSpecificFields,
        paymentMethod: paymentMethod,
        billingAddress: billingAddress,
        shippingAddress: shippingAddress,
    });
}

This request would then result in the common PaymentActionResponse, explained in the Swagger UI and in Payment Method flows.

Testing

Make sure to test towards the centra QA server to ensure you are talking to the PayPal sandbox.

Previous article: Centra Plugins
Next article: Stripe checkout