Broadleaf Microservices
  • v1.0.0-latest-prod

Flow UI Integration

since Checkout.com Payment Library 2.1.0|Release Train 2.3.1

Frontend Project Setup

First off, you’ll need your Checkout.com public key to be accessible in your frontend integration. If you’re using our starter project, you can add it your .env file under the property, NEXT_PUBLIC_CHECKOUT_COM_PUBLIC_API_KEY.

Additionally, if you plan on using the checkout-web-components library, you’ll need to include it in your project dependencies or load the script via https://checkout-web-components.checkout.com/index.js.

In our starter project, this is already included in package.json project dependencies.

1
2
3
4
5
"dependencies": {
  ...
  "@checkout.com/checkout-web-components": "1.9.0",
  ...
}

HPP Architecture & Redirection with Flow

With Broadleaf’s HPP pattern, there’s an expectation that a redirection URL is provided to the payment gateway, so that the gateway will call the Cart Operation external transaction endpoint to record the transaction results and finalize checkout submission.

Within our Checkout.com integration, this is achieved by providing the URL of the CartOperationServices' endpoint to Checkout.com’s CreatePaymentSession API as the success_url and failure_url.

The Cart Operation endpoint should then be configured to redirect to your storefront, so that it can react to the transaction results.

Example Integration

In our example integration, we used Checkout.com’s React library, Flow, to implement the payment forms in checkout.

  1. First, you must create a payment as specified in ./preparing-pts-payments#_flow_payment_method. The success & failure URLs must be provided.

  2. Then, you should submit checkout, which will validate the cart & run the checkout workflow activities, set the cart to AWAITING_PAYMENT_FINALIZATION status & lock the payments, & fail with PAYMENT_REQUIRES_EXTERNAL_INTERACTION.

  3. From the checkout submission response, the Flow payment session information will be found in the paymentNextAction.

  4. In order to load the payment form, we need to initialize Flow with the Checkout.com public key and the payment session received from submitting checkout.

  5. Finally, the Flow component should be mounted in the container for it to load on the page.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    // 1. Create the payment
    paymentSummary = await handleSubmitPaymentInfo(...);

    // 2. Submit checkout
    const checkoutResponse: CheckoutResponse = await submitCheckout();

    // 3. Hydrate payment session info
    const nextAction = checkoutResponse.paymentNextActions
        .filter(paymentAction => paymentAction.paymentId === paymentSummary.paymentId)[0]
        .nextAction;
    const paymentSession: PaymentSessionResponse = {
        id: nextAction.attributes['payment_session_id'],
        payment_session_secret: nextAction.attributes['payment_session_secret'],
        payment_session_token: nextAction.attributes['payment_session_token'],
        _links: {
            self: {
                href: nextAction.redirectUrl
            }
        }
    };

    // 4. Load CheckoutWebComponents (Flow UI)
    const checkout = await loadCheckoutWebComponents({
        publicKey: CheckoutComConfig.PUBLIC_KEY,
        environment: CheckoutComConfig.ENVIRONMENT,
        translations: translations,
        locale: CheckoutComConfig.LOCALE || 'en',
        paymentSession: paymentSession,
        onPaymentCompleted: () => submitCheckout()
    });

    // 5. Create & mount Flow in container
    const creditCardComponent = checkout.create('flow');

    if (await creditCardComponent.isAvailable()) {
        creditCardComponent.mount('#flow-container');
    }

On success or failure, Checkout.com will respond to the URLs provided in the success or failure URLs. With the improved HPP pattern, the expectation is that on redirection to the Cart Operation external transaction endpoint, the transaction results will be queried, recorded, and checkout submitted. The Cart Operation endpoint should be configured to redirect to the storefront with the appropriate response for a successful or failed checkout.

The full configuration for the Cart Operation callback can be found in this example of the improved pattern.
For resiliency in the checkout interaction, there is an alternate flow to gather transaction results and submit checkout through the payment webhooks received from the Payment Gateway. Details of this alternate flow can be found in the externally executed transaction documentation.

Surfacing Saved Payment Methods

The Checkout.com integration now supports 3 forms of saved payment methods:

  1. Frames-produced, Source-ID-based Broadleaf saved payment methods

    1. Includes any saved payment methods that you may have from the Frames-based integration

    2. Stored in PaymentTransactionService’s BLC_SAVED_PAYMENT_METHOD table

    3. Must be surfaced in the UI outside the Flow UI

    4. Existing saved payment methods can continue to be used as they are today

  2. Checkout.com’s Stored Card Credentials

    1. We choose to store these payments in PaymentTransactionService’s BLC_SAVED_PAYMENT_METHOD table (referenced via a Source ID), so that they can be surfaced with other historical "Frames-produced, Source-ID-based" saved payment methods outside the Flow UI

    2. Must be enabled via the broadleaf.checkout-com.enable-stored-cards property in Broadleaf

  3. Checkout.com’s Remember Me

    1. Must be enabled via your Checkout.com account manager

    2. Stored with Checkout.com

    3. Supports gathering saved payment methods for anonymous users

    4. Users can access saved payment methods that they added with other Checkout.com merchants

    5. Saved payment methods are only surfaced within the Flow UI

It’s recommended to use one of Checkout.com’s Stored Cards or Remember Me concepts, but not both. Otherwise, the customer’s card will be surfaced in multiple locations.

Frames Tokenization Integration (Deprecated)

This is deprecated in favor of the Flow UI Integration.

Frontend Project Setup

First off, you’ll need your Checkout.com public key to be accessible in your frontend integration. If you’re using our starter project, you can add it your .env file under the property, NEXT_PUBLIC_CHECKOUT_COM_PUBLIC_API_KEY.

Additionally, if you plan on using the frames-react library, you’ll need to include the minified javascript package on their CDN. In our starter project, this is already included in pages/_document.tsx.

<script src="https://cdn.checkout.com/js/framesv2.min.js" />

Example Integration

In our example integration, we used Checkout.com’s React wrapper library, frames-react, to implement the payment forms in checkout. When loading the payment form, we need to initialize Frames with the Checkout.com public key.

1
2
3
useEffect(() => {
  Frames.init(CheckoutComConfig.PUBLIC_KEY);
}, []);

The most relevant portion of this frontend integration is the tokenization flow and using that response to create a Payment in PaymentTransactionServices. The frames-react library provides a simple method to attempt tokenization and returns the response as a FrameCardTokenizedEvent, or in the case of a failed tokenization: a FrameCardTokenizationFailedEvent. After getting a successful tokenization response, you’ll need to pass that data to PaymentTransactionServices to create a new Payment. From the FrameCardTokenizedEvent, we’ll extract the following data:

  1. The token (tokenEvent.token) - REQUIRED

  2. The credit card type (tokenEvent.scheme)

  3. The masked card number (tokenEvent.last4)

  4. The expiration month & year (tokenEvent.expiry_month, tokenEvent.expiry_year)

const tokenEvent = (await Frames.submitCard()) as FrameCardTokenizedEvent;

const paymentMethodProperties = {
  token: tokenEvent.token,
};
const displayAttributes = {
  creditCardHolder: nameOnAccount,
  creditCardType: tokenEvent.scheme.toUpperCase(),
  creditCardNumber: maskCardNumber(tokenEvent.last4),
  creditCardExpDateMonth: padStart(`${tokenEvent.expiry_month}`, 2, '0'),
  creditCardExpDateYear: `${tokenEvent.expiry_year}`,
};

Finally, we’ll use this tokenized data to build a PaymentRequest and send it via our payment SDK (useSubmitPaymentRequest()) to build a Payment in PaymentTransactionServices.