Configure Checkout
Why checkout configuration matters
Section titled “Why checkout configuration matters”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.
What you will do
Section titled “What you will do”- Manage cart operations (add, update, remove items)
- Build a checkout flow with validation
- Integrate a payment gateway
- Process orders after payment
Manage the cart
Section titled “Manage the cart”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.
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.
Build the checkout flow
Section titled “Build the checkout flow”A typical checkout has four stages: shipping, payment, review, and confirmation. Each stage validates the cart before allowing the customer to proceed.
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:
| Check | When | What happens on failure |
|---|---|---|
| Cart has items | Entry to checkout | Redirect to cart page |
| All items in stock | Before shipping step | Show which items are unavailable, offer alternatives |
| Shipping address valid | After address entry | Show validation errors inline |
| Shipping method selected | Before payment step | Prompt to select a method |
| Payment authorized | After payment submission | Show payment error, allow retry |
| Prices unchanged | Before order creation | Recalculate and show updated total |
Integrate a payment gateway
Section titled “Integrate a payment gateway”Commerce Customized uses a payment gateway abstraction. You implement a payment gateway class that handles authorization, capture, and refund operations for your chosen provider.
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.
Process orders
Section titled “Process orders”After successful payment, convert the cart to a purchase order. This is the final step of checkout.
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:
- Send confirmation — Email the customer with order details and expected delivery
- Notify fulfillment — Push the order to your warehouse or ERP system
- Update inventory — Commerce decrements inventory automatically if tracking is enabled
- Capture payment — Capture the authorized payment when you ship the order
Common issues
Section titled “Common issues”| Issue | Cause | Fix |
|---|---|---|
| Cart total is $0 after adding items | Prices not configured for current market | Add prices for the active market and currency |
| Payment always fails | Gateway not registered in Commerce configuration | Register your gateway class in the Commerce admin |
| Order created but cart not deleted | Missing _orderRepository.Delete(cart.OrderLink) | Add cart deletion after successful order creation |
| Promotions not applying | Promotion engine not called before checkout | Call _promotionEngine.Run(cart) during validation |