The Shopping Cart app is a paragraph app that turns a page into a checkout flow. On every request it:
- Loads the current cart and keeps a record of the products added to it
- Saves whatever the customer just posted (address, payment & shipping selection, custom fields, voucher/gift card codes …) onto the cart
- Recalculates prices, discounts and taxes
- Validates the input and decides which step to render
- At the checkout step, converts the cart into a real order (or a quote), hands it to a payment gateway, sends notification e-mails, and finally shows a receipt
This article explains how the app works at runtime and then documents every setting in the app editor. Two companion articles cover the rest of the implementation surface:
- Cart commands – manipulate cart content (add/remove/update lines, set quantities …) from any template
- Submitting to cart – the form fields and conventions used to move the customer through the flow
Note
The shopping cart does not currently expose a ViewModel, so its templates use template tags, not Razor view models.
How it works
The cart is rendered by the eCom_CartV2 content module. Each time the cart page is requested, the module runs the same pipeline. Understanding this pipeline is the key to implementing the cart correctly, because almost every setting in the editor simply tweaks one step of it.
flowchart TD
start((" ")) --> ctx["Resolve cart & context<br/>(channel / order context)"]
ctx --> empty{"Is the cart<br/>empty?"}
empty -- yes --> emptyaction["Run the configured<br/>empty-cart action"]
empty -- no --> clean["Remove products that<br/>no longer exist"]
clean --> post["Apply posted values<br/>(address, method, fields,<br/>vouchers, gift cards …)"]
post --> calc["Recalculate prices,<br/>discounts & taxes"]
calc --> resolve["Resolve next step<br/>(GotoStepN / re-enter rule)"]
resolve --> validate{"Is the step<br/>valid & fields OK?"}
validate -- no --> rerender["Re-render previous step<br/>with validation errors"]
validate -- yes --> ischeckout{"Is the next step<br/>the checkout step?"}
ischeckout -- no --> render["Render the step template"]
ischeckout -- yes --> convert["Convert cart → order / quote<br/>send mails · pass to gateway"]
convert --> receipt["Show receipt<br/>(post-checkout step)"]
classDef decision fill:#5ba85b,stroke:#3d8b3d,color:#fff
class empty,validate,ischeckout decision
style start fill:#888,stroke:#888,color:#888
style convert fill:#1a6fb5,stroke:#145a93,color:#fff
Steps are a state machine
The flow is driven by an ordered list of steps. The cart remembers which step it is on (the step index is stored on the order), and the customer moves between steps by submitting a form button named CartV2.GotoStepN, where N is the target step index. The app then:
- Works out the requested next step (from the
GotoStepNbutton, or — if the customer simply returned to the page — from the re-enter rule). - Checks the move is legal. You can move forward and backward through the pre-checkout steps, but you cannot reach a post-checkout step (the receipt) unless the order has actually completed. Likewise, once an order is complete only the receipt steps are reachable.
- Validates the fields posted on the step (and, on the checkout step, the order as a whole). If validation fails, the previous step is re-rendered with the errors so the customer can correct them.
The checkout step is the pivot
Exactly one step must be marked as the checkout step. Reaching it is what turns a cart into something permanent:
- For a normal cart it generates an order number, hands the order to the relevant payment gateway / checkout handler, and (on success) marks the order complete, rewards loyalty points, redeems gift cards and sends the notification e-mails.
- For a quote cart it converts the cart to a quote and sends the mails immediately, without a gateway.
The checkout step itself does not need its own template — when configured without one, the customer moves straight from the previous step to the next step (typically the receipt).
Things the app does automatically
Several behaviours are not settings — the app always handles them when the corresponding fields are posted. Knowing the field names is what lets you build the templates:
| Behaviour | Triggered by | See |
|---|---|---|
| Voucher / discount codes | EcomOrderVoucherCode |
Vouchers |
| Gift cards | EcomOrderGiftCardCode |
Gift cards |
| Loyalty points payment | EcomOrderPointsToUse |
Loyalty points |
| Subscription / recurring orders | EcomRecurringOrderCreate (+ interval fields) |
Submitting to cart |
| Create a user during checkout | EcomUserCreateNew / EcomUserCreateNewOrUpdate |
User management |
| Newsletter opt-in | EcomOrderSubscribeToNewsletter |
Newsletter |
Throughout the pipeline the app raises a large number of notifications (before/after payment method set, country changed, order validation, checkout done …), which is the supported way to hook in custom logic without modifying the cart.
Note
The cart page is always served with no-cache response headers, because its content is request- and session-specific. Don't rely on output caching for cart pages.
Settings
The rest of this article documents the app editor. When you add the app to a paragraph you get the settings below, grouped into sections. The Steps are the most important because they define the flow; most other sections refine behaviour around it.
The Settings section sets the channel/context and turns the cart into a quote cart:

| Setting | Use | Notes |
|---|---|---|
| Channel | Select a channel | Overrides the value set on the website Ecommerce settings. If left empty, the website's channel is used. |
| Context cart | Select an order context | Lets this cart use a separate order context (e.g. a secondary basket). |
| Checkout to quote | Make this a quote cart | The checkout step converts the cart to a quote and sends mails instead of passing it to a gateway. |
Steps
The Steps section defines the steps in the checkout flow – e.g. Show Cart, Checkout and Receipt. Each step consists of a label and a template that renders what happens on that step.
Click a step to edit it. Exactly one step must be designated the checkout step – this is the step that converts a cart into an order (see The checkout step is the pivot).
The checkout step doesn't need a template; when it has none, the customer moves directly from the previous step to the next step (typically Receipt).
Notification e-mails
The Notification e-mails section creates e-mail notifications for customers and staff – most commonly an order confirmation. They are sent when the checkout step completes.
To create a notification:
- Click Add
- Specify recipients – in one or more of these ways:
- Check send to billing email and/or send to shipping email
- Check send to custom email field and select the custom field holding the address
- Manually specify an address in the Recipient field
- Fill in the e-mail details:
- Specify a Subject. The token
{OrderID}is replaced with the order id (case-insensitive), soOrder {OrderID} confirmedbecomes e.g.Order ORDER42 confirmed. - Select mail content – Page or Template – and select the relevant page or template (see below)
- Specify a sender name and sender email (the sender e-mail must be a valid address or the mail is skipped)
- Select an encoding (default is UTF-8)
- Optionally select an attachment
- Specify a Subject. The token
The body is always sent as HTML. The difference between the two content sources is what context they get:
- Template – an order e-mail template, rendered with the full set of order template tags (
Ecom:Order.*, theOrderLinesloop, gift card and voucher loops, …) – the same tags you use on the receipt step. - Page – an internal page, rendered with the order made available as context values
OrderandOrderID, so an item on the page can render order details.
A single notification can resolve to several recipients (billing + shipping + every address in a custom field); each unique address receives its own copy. {OrderID} and the body are evaluated per send.
Note
Notification e-mails are sent when the checkout step completes – for a normal cart after the gateway confirms the order, and for a quote cart immediately on conversion. Sending is wrapped so that a mail failure is logged but does not break the customer's checkout.
Field validation
The Field validation settings apply validation during checkout:
Using these settings you can:
- Check customer acceptance to require Terms & Conditions acceptance, and customize the error message rendered when the check fails
- Check stock status to require that products are in stock, and customize its error message
- Select a custom validation group to apply during checkout
Newsletter
The Newsletter setting lets the customer update the standard user e-mail permission field during checkout (via the EcomOrderSubscribeToNewsletter field). It is enabled by default.

Empty cart
The Empty cart settings control what happens when the customer views an empty cart:

- Redirect to an internal page – redirect the customer to a specific page
- Show template – render a chosen template instead of the cart
- Take no special action (default) – render the first step of the flow as normal
User management
The User management section does two things:

- Apply user details to order controls whether a logged-in user's details are applied to the cart on first load. This is on by default.
- Create user in checkout lets an anonymous customer be registered during checkout. When enabled you can:
- Select a group for new users to place them in
- Check Update existing users based on email match to update a matching user instead of failing
- Customize the validation error messages (empty username/password, passwords don't match, password length, username taken, illegal characters)
There is also an option to include delivery addresses from users with the same customer number, so that addresses belonging to other users in the same company/customer account become selectable during checkout.
Payment & delivery
The Payment & delivery section controls which payment methods and shipping methods are available on this cart.

- For each of payment and delivery you can either make all methods available (the default) or select a specific list of methods.
- You can set a default payment method and a default shipping method, which are pre-selected for the customer (see
SetDefaultPaymentAndShippingbehaviour). If no default is set and only one method is available, that method is used.
Additional settings
The Additional settings section tweaks a few behaviours of the flow:

- When re-entering cart controls which step to show when a customer leaves the flow and returns to the cart:
- Show first step (default)
- Show last visited step
- Country for shipping method controls which address is used to fetch shipping methods:
- Always use billing country
- Always use shipping country
- Use delivery/shipping country if a shipping address is set, otherwise billing (default)
- Country for payment method controls which address is used to fetch payment methods. Same three options, but the default is Always use billing country.
- Unavailable products controls what happens when a product becomes unavailable during checkout:
- Remove – silently remove it from the cart (the removed product names are passed to the template so you can inform the customer)
- Ignore – leave it in the cart
Appendix A: two example flows
The same app supports very different checkouts depending purely on how you configure the steps and the surrounding settings. The two flows below are common starting points. They differ in configuration, not in code – the pipeline in How it works runs identically for both.
A1: Anonymous B2C checkout
A typical webshop checkout where the visitor is not logged in and enters their details as they go.
| Step | Label | Checkout step? | Template renders |
|---|---|---|---|
| 0 | Cart | No | Order lines, quantities, voucher/gift card field, Continue button |
| 1 | Information | No | Billing + delivery address fields, shipping & payment selection, terms opt-in |
| 2 | Checkout | Yes | (no template – hands off to the gateway) |
| 3 | Receipt | No | Order confirmation (see Appendix B) |
Relevant settings:
- User management → Apply user details to order: irrelevant (no user), but Create user in checkout is often enabled with Update existing users based on email match so a returning customer isn't duplicated.
- Field validation → customer acceptance: on, to force a Terms & Conditions tick.
- Country for payment/shipping method: the visitor's typed billing country drives method availability, so the address step submits the cart on country change.
Technically, this flow leans on the billing/delivery fields being typed into the form on step 1. The cart carries the values; no user record exists unless create user in checkout fires at the checkout step.
A2: Authenticated B2B checkout
A logged-in business buyer who orders on behalf of a company, picking from saved addresses and paying on account.
| Step | Label | Checkout step? | Template renders |
|---|---|---|---|
| 0 | Cart | No | Order lines, requisition/reference fields, Continue button |
| 1 | Delivery & payment | No | Address picker (saved addresses), shipping & payment (e.g. Invoice) |
| 2 | Checkout | Yes | (no template) |
| 3 | Receipt | No | Order confirmation + "your reference" |
Relevant settings & techniques:
- User management → Apply user details to order: on, so the logged-in user's details populate the order on first load.
- Include delivery addresses from users with the same customer number: on, so the buyer can ship to any address belonging to their company, not just their own.
- Instead of typing an address, the template submits a selected address id –
EcomOrderCustomerSelectedAddressId(billing) andEcomOrderDeliverySelectedAddressId(delivery) – and the cart copies that address onto the order. A delivery address is only accepted if it belongs to the user or to a user with the same customer number. - B2B-oriented order fields such as
EcomCartRequisitionandEcomOrderReferenceare commonly collected and shown again on the receipt and in the order confirmation e-mail. - Payment is typically an Invoice method that needs no gateway interaction, so the checkout step completes the order directly.
Tip
The step count and labels are entirely up to you – a one-page checkout is just step 0 = checkout, and a multi-page wizard is more pre-checkout steps. What must be true in every flow is that exactly one step is the checkout step, and that price/method-affecting fields submit the cart when they change.
Appendix B: a minimal receipt template
A receipt step renders a completed order, so all Ecom:Order.* tags and the OrderLines loop are populated. The smallest useful receipt looks like this:
<h1>Thank you for your order</h1>
<p>Order number: <strong>@GetString("Ecom:Order.ID")</strong></p>
<table>
<thead>
<tr><th>Product</th><th>Qty</th><th>Total</th></tr>
</thead>
<tbody>
@foreach (var line in GetLoop("OrderLines"))
{
<tr>
<td>@line.GetString("Ecom:Order:OrderLine.ProductName")</td>
<td>@line.GetString("Ecom:Order:OrderLine.Quantity")</td>
<td>@line.GetString("Ecom:Order:OrderLine.TotalPrice")</td>
</tr>
}
</tbody>
</table>
<p>Total: <strong>@GetString("Ecom:Order.Price.PriceWithVATFormatted")</strong></p>
@if (GetString("Ecom:Order.HasUsedGiftCards") == "true")
{
<p>Paid partly with gift card(s):</p>
<ul>
@foreach (var card in GetLoop("UsedGiftCards"))
{
<li>@card.GetString("Ecom:Order.UsedGiftCard.Code") – @card.GetString("Ecom:Order.UsedGiftCard.UsedAmountForTheOrder")</li>
}
</ul>
}
The same markup works as a Template-type notification e-mail body, which is why an order confirmation mail and the on-screen receipt usually share one template. For the full set of tags available on the order and order lines, see Submitting to cart.