Skip to content

Configure Checkout

⏱ 30 minutes intermediate
📜Corecommerce

The checkout flow is where browsing becomes revenue. A poorly configured checkout leads to abandoned carts, failed payments, and lost orders. A well-configured checkout handles edge cases gracefully — out-of-stock items, expired promotions, payment failures, address validation — and guides the customer through each step with minimal friction.

Commerce Customized gives you full control over every step of the checkout process. This guide covers the core building blocks: cart management, checkout flow design, payment integration, and order processing.

  1. Manage cart operations (add, update, remove items)
  2. Build a checkout flow with validation
  3. Integrate a payment gateway
  4. Process orders after payment

The cart is a server-side object that persists for the duration of a customer’s session and beyond. Commerce uses the IOrderRepository and IOrderGroupFactory to create and manage carts.

Cart operations
csharp
using EPiServer.Commerce.Order;
using Mediachase.Commerce;

public class CartService
{
    private readonly IOrderRepository _orderRepository;
    private readonly IOrderGroupFactory _orderGroupFactory;
    private readonly ICurrentMarket _currentMarket;

    public CartService(
        IOrderRepository orderRepository,
        IOrderGroupFactory orderGroupFactory,
        ICurrentMarket currentMarket)
    {
        _orderRepository = orderRepository;
        _orderGroupFactory = orderGroupFactory;
        _currentMarket = currentMarket;
    }

    public ICart GetOrCreateCart(Guid customerId)
    {
        var cart = _orderRepository
            .LoadCart<ICart>(customerId, "Default",
                _currentMarket.GetCurrentMarket());

        if (cart == null)
        {
            cart = _orderGroupFactory.CreateCart(
                customerId, "Default");
            cart.Currency =
                _currentMarket.GetCurrentMarket()
                    .DefaultCurrency;
        }
        return cart;
    }

    public void AddToCart(ICart cart,
        string variantCode, decimal quantity)
    {
        var lineItem = cart.GetAllLineItems()
            .FirstOrDefault(x => x.Code == variantCode);

        if (lineItem != null)
        {
            lineItem.Quantity += quantity;
        }
        else
        {
            var shipment = cart.GetFirstShipment();
            if (shipment == null)
            {
                shipment = _orderGroupFactory
                    .CreateShipment(cart);
                cart.AddShipment(shipment);
            }

            lineItem = _orderGroupFactory
                .CreateLineItem(variantCode, cart);
            lineItem.Quantity = quantity;
            shipment.LineItems.Add(lineItem);
        }

        _orderRepository.Save(cart);
    }

    public void RemoveFromCart(ICart cart,
        string variantCode)
    {
        var shipment = cart.GetFirstShipment();
        var lineItem = shipment?.LineItems
            .FirstOrDefault(x => x.Code == variantCode);

        if (lineItem != null)
        {
            shipment.LineItems.Remove(lineItem);
            _orderRepository.Save(cart);
        }
    }
}

Key decisions for cart management:

  • Cart name — Use “Default” for the primary shopping cart. You can create named carts for wishlists or saved-for-later functionality.
  • Validation timing — Validate inventory and pricing when items are added and again at checkout. Prices and stock can change between those points.
  • Guest carts — For anonymous visitors, associate the cart with a temporary GUID. Merge it with their account cart when they sign in.

A typical checkout has four stages: shipping, payment, review, and confirmation. Each stage validates the cart before allowing the customer to proceed.

Checkout flow with validation
csharp
using EPiServer.Commerce.Order;

public class CheckoutService
{
    private readonly IOrderRepository _orderRepository;
    private readonly IOrderGroupCalculator _orderCalculator;
    private readonly IPromotionEngine _promotionEngine;

    public CheckoutService(
        IOrderRepository orderRepository,
        IOrderGroupCalculator orderCalculator,
        IPromotionEngine promotionEngine)
    {
        _orderRepository = orderRepository;
        _orderCalculator = orderCalculator;
        _promotionEngine = promotionEngine;
    }

    public CheckoutValidation ValidateCart(ICart cart)
    {
        var result = new CheckoutValidation();

        // Check for empty cart
        if (!cart.GetAllLineItems().Any())
        {
            result.AddError("Cart is empty.");
            return result;
        }

        // Validate inventory for each item
        foreach (var item in cart.GetAllLineItems())
        {
            // Check stock availability
            // Remove or adjust items that are
            // no longer available
        }

        // Apply promotions and recalculate totals
        _promotionEngine.Run(cart);
        _orderRepository.Save(cart);

        result.OrderTotal =
            _orderCalculator.GetOrderGroupTotals(cart);
        return result;
    }

    public void SetShippingAddress(ICart cart,
        AddressModel address)
    {
        var shipment = cart.GetFirstShipment();
        shipment.ShippingAddress =
            CreateOrderAddress(cart, address);
        _orderRepository.Save(cart);
    }
}

Checkout validation checklist:

CheckWhenWhat happens on failure
Cart has itemsEntry to checkoutRedirect to cart page
All items in stockBefore shipping stepShow which items are unavailable, offer alternatives
Shipping address validAfter address entryShow validation errors inline
Shipping method selectedBefore payment stepPrompt to select a method
Payment authorizedAfter payment submissionShow payment error, allow retry
Prices unchangedBefore order creationRecalculate and show updated total

Commerce Customized uses a payment gateway abstraction. You implement a payment gateway class that handles authorization, capture, and refund operations for your chosen provider.

Payment gateway integration
csharp
using EPiServer.Commerce.Order;
using Mediachase.Commerce.Orders;
using Mediachase.Commerce.Plugins.Payment;

public class StripePaymentGateway
    : AbstractPaymentGateway
{
    public override bool ProcessPayment(
        IPayment payment, ref string message)
    {
        var cart = payment.Parent as IOrderGroup;
        var amount = payment.Amount;

        try
        {
            // Call your payment provider's API
            // to authorize the payment
            var result = AuthorizePayment(
                payment.Properties["Token"] as string,
                amount,
                cart.Currency.CurrencyCode);

            if (result.Success)
            {
                payment.TransactionID =
                    result.TransactionId;
                payment.Status =
                    PaymentStatus.Processed.ToString();
                message = "Payment authorized.";
                return true;
            }

            message = result.ErrorMessage;
            payment.Status =
                PaymentStatus.Failed.ToString();
            return false;
        }
        catch (Exception ex)
        {
            message = "Payment processing failed.";
            payment.Status =
                PaymentStatus.Failed.ToString();
            return false;
        }
    }

    private PaymentResult AuthorizePayment(
        string token, decimal amount, string currency)
    {
        // Implement provider-specific API call
        throw new NotImplementedException();
    }
}

Payment integration considerations:

  • Tokenization — Never send raw card numbers through your server. Use your payment provider’s client-side SDK to tokenize card details, then send only the token to Commerce.
  • Authorization vs capture — Authorize at checkout, capture at fulfillment. This protects you from charging for items you cannot ship.
  • Error handling — Payment failures are common (insufficient funds, expired cards, fraud checks). Always provide a clear error message and let the customer retry.

After successful payment, convert the cart to a purchase order. This is the final step of checkout.

Create an order from cart
csharp
using EPiServer.Commerce.Order;

public class OrderService
{
    private readonly IOrderRepository _orderRepository;

    public OrderService(
        IOrderRepository orderRepository)
    {
        _orderRepository = orderRepository;
    }

    public IPurchaseOrder CreateOrder(ICart cart)
    {
        // Final validation
        var totals = ValidateAndRecalculate(cart);

        // Convert cart to purchase order
        var orderRef = _orderRepository
            .SaveAsPurchaseOrder(cart);
        var order = _orderRepository
            .Load<IPurchaseOrder>(orderRef.OrderGroupId);

        // Set initial order status
        order.OrderStatus = OrderStatus.InProgress;

        // Add order number for customer reference
        var orderNumber = GenerateOrderNumber();
        order.Properties["OrderNumber"] = orderNumber;

        _orderRepository.Save(order);

        // Delete the cart
        _orderRepository.Delete(cart.OrderLink);

        return order;
    }

    private string GenerateOrderNumber()
    {
        return $"ORD-{DateTime.UtcNow:yyyyMMdd}-"
            + $"{Guid.NewGuid().ToString("N")[..8]"
                .ToUpper()}";
    }
}

After order creation:

  1. Send confirmation — Email the customer with order details and expected delivery
  2. Notify fulfillment — Push the order to your warehouse or ERP system
  3. Update inventory — Commerce decrements inventory automatically if tracking is enabled
  4. Capture payment — Capture the authorized payment when you ship the order
IssueCauseFix
Cart total is $0 after adding itemsPrices not configured for current marketAdd prices for the active market and currency
Payment always failsGateway not registered in Commerce configurationRegister your gateway class in the Commerce admin
Order created but cart not deletedMissing _orderRepository.Delete(cart.OrderLink)Add cart deletion after successful order creation
Promotions not applyingPromotion engine not called before checkoutCall _promotionEngine.Run(cart) during validation