Payment lifecycle

Understand how Payments flow in commercetools Checkout, what Checkout handles for you, and what business logic you must implement (Order State, retries, reconciliation).

Ask about this Page
Copy for LLM
View as Markdown

After completing this page, you should be able to:

  • Describe the key stages of the Payment lifecycle.

  • Explain what Checkout handles versus what you must implement.

  • Apply best practices for using Checkout in production.

You can control when Payments are captured, canceled, or refunded by using the Checkout Payment Intents API. Although Checkout handles Payment authorization and creates Orders, you must implement the business logic for triggering captures, cancellations, and refunds based on your fulfillment workflow.

This page covers the key Payment lifecycle operations that you need to implement and the actions that Checkout handles automatically.

Key lifecycle operations

The Payment lifecycle consists of the following important operations:

Authorization and capture

After an Order is successfully created, Checkout authorizes only the Payment method. This means that funds are reserved, but aren't 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 the following two ways:

  • Automated capture: configure your payment service provider (PSP) to automatically capture Payments based on pre-defined rules or timelines. Verify whether your PSP supports automatic capture. Automatic capture isn't recommended for Adyen due to compatibility issues.
  • Manual capture: use the Checkout Payment Intents API to trigger the capturePayment action in response to specific business events. For example, you might capture the Payment when the following events occur:
    • The Order is picked and is ready to be shipped.
    • Stock is allocated for the Order within your enterprise resource planning or Order management system.
Capture payment when order shipstypescript
import { checkoutApiRoot } from "./apiClient.js";

async function capturePayment(paymentId, amount) {
  try {
    const response = await checkoutApiRoot
      .paymentIntents()
      .withPaymentId({ paymentId })
      .post({
        body: {
          actions: [
            {
              action: "capturePayment",
              amount,
            },
          ],
        },
      })
      .execute();

    console.log("Payment captured successfully:", response.body);
    return response;
  } catch (error) {
    console.error("Failed to capture payment:", error.message);
    throw error;
  }
}

// Trigger capture when order ships
// Capturing might happen directly on the PSP from a backend system e.g. ERP or OMS
await capturePayment(
  order.paymentInfo.payments[0].id,
  {centAmount: 50000, currencyCode: "EUR"}
);

Authorization cancellation

If an Order is canceled before Payment capture, then you must void the authorization. This releases the reserved funds back to the Customer.

Here are a few common reasons for authorization cancellation:

  • Customer-requested cancellations
  • Fulfillment issues preventing Order completion
  • Fraudulent activity detected
Use the Checkout Payment Intents API to request a cancellation from your PSP. Checkout updates the Order by adding a CancelAuthorization Transaction to the existing Payment. For more information about the detailed API documentation, see Cancel Payment.
Cancel authorization for canceled ordertypescript
import { checkoutApiRoot } from "./apiClient.js";

async function cancelAuthorization(paymentId) {
  try {
    const response = await checkoutApiRoot
      .paymentIntents()
      .withPaymentId({ paymentId })
      .post({
        body: {
          actions: [
            {
              action: "cancelPayment",
            },
          ],
        },
      })
      .execute();

    console.log("Authorization canceled successfully:", response.body);
    return response;
  } catch (error) {
    console.error("Failed to cancel authorization:", error.message);
    throw error;
  }
}

// Cancel authorization when customer cancels order
await cancelAuthorization(order.paymentInfo.payments[0].id);

Refund

Refunds become necessary when you need to return captured funds to Customers. This can occur due to the following scenarios:

  • Customer returns
  • Damaged or incorrect goods received
  • Other situations requiring reimbursement
Refunds can be either partial or full, but the total refund amount can't exceed the initially captured amount. You can initiate refunds through the Checkout Payment Intents API by using the refundPayment action.
Issue partial refund for returned itemstypescript
import { checkoutApiRoot } from "./apiClient.js";

async function refundPayment(paymentId, amount) {
  try {
    const response = await checkoutApiRoot
      .paymentIntents()
      .withPaymentId({ paymentId })
      .post({
        body: {
          actions: [
            {
              action: "refundPayment",
              amount,
            },
          ],
        },
      })
      .execute();

    console.log("Payment refunded successfully:", response.body);
    return response;
  } catch (error) {
    console.error("Failed to refund payment:", error.message);
    throw error;
  }
}

// Refund €20.00 for returned item (original order was €50.00)
await refundPayment(
  order.paymentInfo.payments[0].id,
  {centAmount: 2000, currencyCode: "EUR"} // €20.00
);

Automated reversals

Checkout lets you set predicates to define conditions for automatically canceling or refunding a Payment if the Order creation fails.

Automated Reversal Predicates operate by using a true/false logic and can use the values of the Cart fields, including Custom Fields. If the Automated Reversal predicate evaluates as true, then the Automated Reversal is processed for the relevant Payment.
Automated Reversal Predicates are set on the application during or after Order creation. For more information about configuring predicates, see Set predicates for automated reversals.

Requirements to implement business logic

Checkout creates the Order and manages the Payment lifecycle, including updating the Payment record with transactions and Payment status.

You must implement the business logic for the following:

  • Managing orderState transitions: Checkout doesn't update the orderState field. You can determine when to transition Orders between Open, Confirmed, Complete, or Canceled States based on your fulfillment workflow.
  • Triggering payment captures: decide when to capture authorized Payments, such as when Inventory is allocated, Order is picked, or shipment is dispatched.
  • Handling cancellations and refunds: implement the logic to cancel authorizations or issue refunds in response to business events like Order cancellation and returns processing.
  • Reconciliation and monitoring: track Payment States, handle failed transactions, and implement retry logic for transient failures.
You can view Payments created by Checkout in the Merchant Center from an Order's detail page. Go to Orders > Order list, select the Order, and then click the Payments tab to view the Payment method, PSP, Payment provider ID, amount planned, and all Payment Transactions.
Payment field mapping:

The following table shows how Payment fields in Composable Commerce map to the Merchant Center Payment UI:

Composable Commerce Payment fieldMerchant Center Payment UI
interfaceIdPayment provider ID
transactions[0].idTransaction ID in Transactions list
transactions[0].interactionIdInteraction ID in Transactions list
The Payment Provider ID represents the main identifier for the Payment on the PSP side (mapped to interfaceId). In the Transactions list, the Interaction ID displays the reference returned by the PSP for that specific operation. Depending on the PSP's logic, this value may match the Payment Provider ID (common for Authorizations) or differ for subsequent operations like Charges or Refunds.

The following example shows a complete workflow that combines Payment capture with Order State management:

Update orderState after successful capturetypescript
import { apiRoot } from "./apiClient.js"; // Your Composable Commerce API client

async function confirmOrderAfterCapture(orderId, version) {
  const order = await apiRoot
    .orders()
    .withId({ ID: orderId })
    .post({
      body: {
        version: version,
        actions: [
          {
            action: "changeOrderState",
            orderState: "Confirmed",
          },
        ],
      },
    })
    .execute();

  return order.body;
}

// Workflow: Capture payment, then update orderState
try {
  // 1. Capture the payment
  await capturePayment(
    order.paymentInfo.payments[0].id,
    { centAmount: 5000, currencyCode: "EUR" }
  );

  // 2. Update orderState to Confirmed
  await confirmOrderAfterCapture(order.id, order.version);

  console.log("Order confirmed and payment captured");
} catch (error) {
  console.error("Failed to capture payment or update order", error);
  // Implement your error handling and retry logic
}

Key takeaways

  • Checkout authorizes Payments and creates Orders, but you can control when Payments are captured by using the Checkout Payment Intents API.
  • Use manual capture to align Payment capture with your fulfillment workflow, such as when Inventory is allocated or the shipment is dispatched.
  • Cancel authorizations by using the cancelPayment action when Orders are canceled before capture.
  • Issue full or partial refunds by using the refundPayment action for returns or other refund scenarios.
  • Configure Automated Reversal predicates to automatically cancel or refund Payments if Order creation fails.
  • You are responsible for managing orderState transitions—Checkout doesn't update this field.
  • Implement error handling and retry logic for Payment operations to handle transient failures.
  • Track Payment States and reconcile transactions between Checkout, your PSP, and your Order management system.

Test your knowledge