Checkout Flow Overview¶
Merchello provides a built-in, Shopify-style checkout experience. It is a consistent, mobile-first flow that handles everything from basket to payment confirmation. The checkout is rendered using MVC Razor views from the Merchello RCL (Razor Class Library) and uses Alpine.js for interactivity.
What it is: A drop-in, opinionated checkout that works out of the box with any enabled payment and shipping provider.
Why you use it: You get a fully-tested, mobile-first checkout with multi-currency, abandoned-cart recovery, express checkout, and tax-inclusive display without writing any UI code. You only override views when you need brand-specific customisation (see Customizing Checkout Views).
How it fits together:
| Layer | Responsibility | Source |
|---|---|---|
CheckoutContentFinder |
Resolves /checkout/* URLs into a virtual page |
CheckoutContentFinder.cs |
MerchelloCheckoutController |
Razor-hijacked controller that renders each step | MerchelloCheckoutController.cs |
CheckoutApiController |
Public AJAX surface at /api/merchello/checkout |
CheckoutApiController.cs |
CheckoutPaymentsApiController |
Payment/express-checkout endpoints on the same base path | CheckoutPaymentsApiController.cs |
ICheckoutService |
Business logic: basket math, order grouping, address/shipping saves | ICheckoutService.cs |
ICheckoutSessionService |
Per-basket session state (step, addresses, shipping selections, invoice id) | ICheckoutSessionService.cs |
Invariant: Controllers never touch
DbContext. All persistence and calculation flows through services. Basket totals are always computed byCheckoutService.CalculateBasketAsync()— never in views, controllers, or JS.
Design Philosophy¶
The checkout intentionally mirrors Shopify's checkout patterns. Shoppers who buy online frequently are already familiar with this flow, which means:
- Reduced friction -- customers know what to expect at each step.
- Trust -- recognisable patterns signal a professional, secure checkout.
- Higher conversion -- less cognitive load means fewer abandoned carts.
Checkout Steps¶
The checkout flows through these steps in order:
| Step | URL | Description |
|---|---|---|
| Information | /checkout or /checkout/information |
Email, billing address, shipping address |
| Shipping | /checkout/shipping |
Shipping method selection per warehouse group |
| Payment | /checkout/payment |
Payment method selection and processing |
| Confirmation | /checkout/confirmation/{invoiceId} |
Order summary and download links |
| PaymentReturn | /checkout/return |
Handles return from external payment providers |
| PaymentCancelled | /checkout/cancel |
Handles cancelled external payments |
| PostPurchase | /checkout/post-purchase/{invoiceId} |
Post-purchase upsells |
public enum CheckoutStep
{
Information = 0,
Shipping = 1,
Payment = 2,
Confirmation = 3,
PaymentReturn = 4,
PaymentCancelled = 5,
PostPurchase = 6
}
How Routing Works¶
Checkout URLs are handled by CheckoutContentFinder, which intercepts any /checkout/* URL and creates virtual Umbraco content. This means you do not need to create checkout pages in the Umbraco content tree.
/checkout --> CheckoutStep.Information
/checkout/information --> CheckoutStep.Information
/checkout/shipping --> CheckoutStep.Shipping
/checkout/payment --> CheckoutStep.Payment
/checkout/confirmation/abc-123 --> CheckoutStep.Confirmation (with invoiceId)
The MerchelloCheckoutController then renders the appropriate Razor view from the RCL based on the step.
The Checkout Controller¶
MerchelloCheckoutController is a standard Umbraco RenderController that:
- Determines the current checkout step from the URL.
- Loads the basket and checkout session.
- Builds a
CheckoutViewModelwith all the data the view needs. - Renders the step-specific Razor view from the Merchello RCL.
The controller handles several special cases:
- Confirmation security -- validates a confirmation token cookie to prevent unauthorised access to order details.
- Recovery links -- handles abandoned checkout recovery tokens.
- Custom confirmation redirect -- supports redirecting to a custom URL after payment if configured.
- Display currency enrichment -- converts confirmation amounts to the customer's display currency.
Checkout API¶
The CheckoutApiController at /api/merchello/checkout handles all the AJAX operations the checkout UI needs:
| Method | Endpoint | Description |
|---|---|---|
GET |
/basket |
Get basket with formatted totals |
GET |
/shipping/countries |
Available shipping countries |
GET |
/shipping/regions/{code} |
Regions for a shipping country |
GET |
/billing/countries |
All countries for billing |
GET |
/billing/regions/{code} |
Regions for a billing country |
POST |
/addresses |
Save billing and shipping addresses |
POST |
/discount/apply |
Apply a discount code |
POST |
/initialize |
Initialize single-page checkout |
GET |
/address-lookup/config |
Get address lookup configuration |
POST |
/address-lookup/suggestions |
Get address autocomplete suggestions |
POST |
/address-lookup/resolve |
Resolve an address suggestion |
Single-Page Checkout¶
Merchello supports a single-page checkout mode where all sections (contact, billing, shipping, payment) are visible on one page. This is initialised with the /api/merchello/checkout/initialize endpoint:
const response = await fetch('/api/merchello/checkout/initialize', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
countryCode: 'GB',
stateCode: null,
autoSelectShipping: true,
email: null
})
});
The InitializeCheckout method:
1. Sets the shipping location from the provided country/state.
2. Syncs the basket currency to match the storefront context.
3. Calculates order groups (splits basket items by warehouse).
4. Optionally auto-selects the cheapest shipping option per group.
5. Returns the basket, shipping groups, and combined shipping total.
Express Checkout¶
The checkout supports express payment methods (Apple Pay, Google Pay, PayPal One Touch) that skip the form entirely:
- Customer clicks an express checkout button on the cart or checkout page.
- The payment provider handles authentication (Apple Pay sheet, PayPal popup, etc.).
- The provider returns a payment token plus customer data (email, shipping address).
- The backend creates the order immediately using the provider-returned data.
- Customer goes directly to the confirmation page.
Express checkout methods are identified by IsExpressCheckout = true on the payment method.
Payment Provider Architecture¶
The checkout is provider-agnostic. It works with any enabled payment provider via the IPaymentProvider interface. Each provider declares payment methods with an IntegrationType:
| Integration Type | Behaviour | Examples |
|---|---|---|
Redirect |
Redirect to external payment page | Stripe Checkout |
HostedFields |
Inline card fields via provider SDK | Braintree Cards, Stripe Elements |
Widget |
Provider's embedded widget | Apple Pay, Google Pay |
DirectForm |
Simple form fields (backoffice only) | Manual payments |
Guest Checkout¶
Guest checkout is supported -- customers only need to provide an email address. A customer record is auto-created from the email during checkout. For digital products, however, a customer account is required.
Post-Payment Flow¶
After successful payment:
- Confirmation page -- shows the order summary with line items, totals, and shipping details.
- Basket cleared -- the basket cookie is deleted and per-request cache cleared.
- Download links -- if the order contains digital products, download links are displayed (for
InstantDownloadmethod). - Confirmation token -- a secure cookie ensures only the customer who placed the order can view the confirmation.
- Post-purchase upsells -- optionally redirects to a post-purchase upsell page before final confirmation.
Abandoned Checkout Recovery¶
If IAbandonedCheckoutService is registered, the checkout supports recovery links sent via email. These links contain a token that restores the customer's basket and pre-fills their information.
Key Points¶
- The checkout uses virtual routing via
CheckoutContentFinder-- no Umbraco content pages needed. - All checkout views are served from the Merchello RCL at
~/App_Plugins/Merchello/Views/Checkout/. - The checkout is Shopify-style: familiar, mobile-first, and opinionated.
- Express checkout methods skip the address form and go straight to payment.
- Confirmation pages are secured with a cookie token to prevent unauthorised access.
- The checkout supports both multi-step and single-page modes.