Checkout flow and best practices

Learn how the Checkout and Payment flow operates as well as some of the best practices for utilizing Checkout.

  • After completing this page, you should be able to:

    • Identify Checkout best practices.
  • How to initialize Checkout

    As mentioned in our documentation, you can initialize Checkout in two ways depending on the Checkout mode you use:

    • Complete Checkout mode uses the checkoutFlow method.
    • Payment Only mode uses the paymentFlow method.

    Let's take a look at each in turn.

    Complete Checkout mode

    In the following diagram, we show the typical flow between the browser, Backend For Frontend (BFF), Checkout API, and Checkout Session when creating a Session and initializing the checkout.

    After these steps, the browser should be displaying the checkout with the customer's Cart information. The following image is what we should expect to see in the browser at this stage. This example checkout is using the default styles.

    A default themed checkout example.

    Next, in the browser, the customer will add their shipping and billing information and apply any discount codes.

    Shipping and billing information added.

    Next, let's go through the flow, where the customer requests the payment step and completes the checkout.

    Calling the checkoutFlow method and completing the checkout

    sequence dagram of checkout flows

    Payment Only mode

    The Payment Only mode offers greater flexibility by letting you independently manage the payment information user interface (UI). You choose when and where it appears, using a dedicated method. The rest of the checkout payment flow follows the same process as the Complete Checkout mode.

    Best practices

    To best utilize Checkout, we recommend the following best practices.

    Checkout URL State

    We recommend using the Cart ID as part of the path: example.com/checkout/{cart-id}. We don’t recommend using the Session ID, because the lifetime of this ID is short (1 hour) and it’s not possible to generate a new Session ID from an expired session. However, we can create as many sessions as we may need, so long as we have the Cart ID. The ability to generate a new session for the same Customer is crucial. Customers don't always convert in a single browsing session. By utilizing unique checkout URLs, businesses can leverage marketing tools to target customers and guide them back to the same checkout page multiple times, increasing the likelihood of conversion.

    You should trigger this URL change and update the browser History API when you receive the CheckoutStarted Message (step 1 in the preceding Complete Checkout mode diagram).

    When the checkout is completed, the SDK will emit the checkout_completed Message (see the Complete Checkout mode diagram). This Message includes the Order ID, giving us enough information to query the Order and render the Order confirmation page.

    Using Custom IDs instead of Cart ID's

    Alternatively, you can employ custom identifiers for your checkout. However, if you choose this approach, ensure you have a mechanism to efficiently map your custom ID back to the corresponding Cart ID. This mapping is crucial for instantiating new checkoutFlow or paymentFlow instances with little latency overhead.

    You can take a number of approaches with regards to the URL paths you create:

    Using the same ID for checkout and Order confirmation URL

    Some business requirements may necessitate using the same identifier for both the checkout and order confirmation pages. This could mean that we design our URLs to look like the following:

    • example.com/checkout/{cart-id}
    • example.com/checkout/success/{cart-id}

    Let's explore how to query the newly created Order using the checkout ID (in this case, the Cart ID).

    Querying the Order by Cart ID

    To render the order confirmation page, we need to retrieve the Order from Composable Commerce. To retrieve the Order, you can query the Orders HTTP endpoint using the associated Cart ID. For example:

    HTTP Order resource: GET /orders?where=cart(id="f1b7effe-9718-4e1b-b03f-3ebed5452267")

    GraphQL for Order resource:

    query Orders {
    orders(where: "cart(id = \"f1b7effe-9718-4e1b-b03f-3ebed5452267\")") {
    results {
    id
    customer {
    email
    firstName
    lastName
    middleName
    title
    locale
    salutation
    version
    id
    createdAt
    }
    lineItems {
    productId
    name
    quantity
    }
    }
    }
    }

    Using the Order ID is the simplest option because we can pass the known Order ID to the Order endpoint and get the Order. Remember that the CheckoutCompleted Message tells us what the Order ID is.

    Using a custom ID example.com/checkout/success/{custom-id}

    You may use your own ID generator to have control over how the Order number looks or have another system that generates these values, for example, an Enterprise Resource Planning or Order Management System. Generating this ID will not be as instantaneous as the Composable Commerce Order ID. You will need to consider how you handle this whilst loading the order success page. Consider reading our Foundry guide on Generating a Unique Order Number.

    When using custom order numbers, a critical decision point arises: when to generate and assign the order number to the new Order. This timing significantly impacts your order confirmation flow.

    Let's analyze the two primary approaches:

    Generating and assigning Order number before displying the Confirmation page:

    • Process:

      1. As soon as the customer completes checkout (checkout_completed message emitted), you setOrderNumber on the Order.
      2. Redirect the user to the order confirmation page, including the orderNumber in the URL: example.com/checkout/success/{orderNumber}.
    • Advantages:

      • The order number follows your internal conventions and can be more human readable than a UUID.
    • Disadvantages:

      • The process of setting the Order number will slightly delay the process of displaying the order confirmation page.

    Assigning Order number after confirmation (on demand):

    • Process:

      1. Redirect the user to a generic order confirmation page, for example, example.com/checkout/success after the checkout completion.
      2. On this page, initiate an asynchronous request to your backend.
      3. This backend request generates the custom order number and uses setOrderNumber to assign it to the Order.
    • Advantages:

      • No additional latency in displaying the Order confirmation page.

      • Potential for user perception issues: the first time the customer views the order confirmation page, they will not see the orderNumber. This could cause some confusion for the customer.

    Remember to carefully consider the trade-offs and potential issues associated with each approach. Thoroughly test your implementation to ensure data consistency and a smooth user experience.

    Payment Only mode

    When using the Payment Only mode, you must ensure that it is always the last step in the checkout process. This is because the Payment Only flow creates the Payment and Order.

    Messages as events

    The SDK exposes Messages as events. These events are very helpful for your application, providing insights into the checkout process. For example, you can receive notifications about errors, checkout completion, or any other relevant updates.

    You can also leverage these events to create data layer events for your analytics tools. It is important to understand each of these Messages and handle them in your application code for a smooth customer experience.

    Thus far we have discussed how Messages can be used for knowing when the checkout process starts and ends so that we can update the experience being shown to the customer. Take some time to review all of the Message types.

    Payment lifecycle

    The payment lifecycle within your commerce solution involves several stages, from authorization to potential refunds. Understanding these stages and how to manage them is crucial for a smooth customer experience.

    Authorization and capture

    Upon successful Order creation, Checkout only authorizes the payment method. This means funds are reserved but not yet transferred from the Customer's account. This approach provides flexibility in deciding when to capture the payment. You can control the capture process in two ways:

    • Automated capture: configure your payment service provider (PSP) to automatically capture payments based on predefined rules or timelines. Check if your PSP supports automatic capture. We recommend not using auto-capture for Adyen, due to compatibility issues.
    • Manual capture: utilize the Checkout Payments API to trigger the capturePayment action in response to specific business events. For instance, you might capture the payment when:
      • The order is picked and ready for shipment.
      • Stock is allocated for the order within your enterprise resource planning or order management system.

    Authorization cancellation

    If an order is canceled before payment capture, you need to void the authorization. This releases the reserved funds back to the customer. Common reasons for authorization cancellation include:

    • Customer-requested cancellations
    • Fulfillment issues preventing order completion
    • Fraudulent activity detected

    While Checkout doesn't directly handle authorization cancellations, you can leverage the Checkout Payments API to request a cancellation from your PSP. Upon receiving your request, Checkout updates the Order by adding a CancelAuthorization Transaction to the existing Payment. For detailed API documentation, refer to Cancel Payment.

    Refund

    Refunds become necessary when you need to return captured funds to the customer. This could be due to:

    • Customer returns
    • Damaged or incorrect goods received
    • Other situations requiring reimbursement

    Refunds can be partial or full, but the total refund amount cannot exceed the initially captured amount. You can initiate refunds through the Checkout Payments API using the refundPayment action.

    Your responsibilities

    In the commercetools ecosystem, Checkout creates the Order and manages the payment lifecycle, including updating the Payment record with information such as transactions and payment status.

    However, Checkout does not manage the orderState, which represents the state of the Order in the order processing workflow and indicates whether the Order is in an Open, Confirmed, Complete, or Canceled state. Updating the orderState typically requires explicit actions that are separate from the payment process, such as fulfilling the Order, shipping the goods, or handling returns. Because of this, you are responsible for determining when and how to update orderState.

    Test your knowledge