Cart Lifecycle
A Commerce cart progresses through distinct stages: creation, mutation, rendering, and completion.
States
| State | Description |
|---|---|
open | Active cart, can be modified |
completed | Cart has been completed (order created) |
rejected | Not actively used. Carts are generally retained for a limited time before automatically removed |
Creating a Cart
Carts are created via the Create Cart endpoint with a profile key and locale:
POST /ingress/commerce/carts
Content-Type: application/json
{
"profileKey": "default",
"locale": "sv_SE"
}The profile key determines the cart's currency, default country, and allowed shipping countries. The locale must be configured in the system registry.
The response contains the new cartId — all subsequent operations use this ID.
Mutating a Cart
Cart mutations are performed via the Commerce ingresses. Most mutations return the rendered cart.
Adding and Managing Items
# Add an item
POST /ingress/commerce/carts/{cartId}/add-item
{ "productNumber": "TSHIRT-001", "quantity": 2 }
# Change quantity
POST /ingress/commerce/carts/{cartId}/set-quantity
{ "cartItemId": "...", "quantity": 3 }
# Remove an item
POST /ingress/commerce/carts/{cartId}/remove-item
{ "cartItemId": "..." }Setting Customer Details
# Set email
POST /ingress/commerce/carts/{cartId}/email
{ "email": "customer@example.com" }
# Set shipping address
POST /ingress/commerce/carts/{cartId}/address
{ "address": { "countryCode": "SE", "city": "Stockholm", ... } }Custom Fields
Custom fields allow PSP apps and other integrations to store metadata on the cart:
# Set a custom field
POST /ingress/commerce/carts/{cartId}/set-field/paymentProvider
{ "value": "stripe" }
# Remove a custom field
POST /ingress/commerce/carts/{cartId}/remove-field/paymentProviderCustom fields appear in the rendered cart under the fields property.
Rendering
Every mutation endpoint returns the rendered cart — a normalized structure with computed prices, totals, and tax. The rendering pipeline:
- Sends a
completemessage to the cart actor in preview mode (no persistent changes) - This triggers all order creation rules (including price lookup, discounts, shipping)
- Queries the preview result for order totals and line items
- Maps the data into the rendered cart structure
The rendered cart includes:
orderTotal,orderTaxTotal,shippingTotal,productTotal— computed totalsitems[]— each item withunitPrice,total,tax,discountfields— custom fields set via theset-fieldendpointcartState— current state (open,completed,rejected)
After rendering, the OnCartMutation hook fires, enabling other apps to react. See Hooks.
Real-Time Updates
Subscribe to the Cart Events SSE endpoint to receive the rendered cart in real-time whenever the cart state changes:
const eventSource = new EventSource(
`${baseUrl}/ingress/commerce/carts/${cartId}/events`
)
eventSource.onmessage = (event) => {
const cart = JSON.parse(event.data)
updateUI(cart)
}This is essential for checkout flows where the cart may be modified by background processes (e.g., PSP synchronization).
Completing a Cart
Cart completion is typically triggered by a PSP app after payment authorization. The PSP app:
- Creates a Payment actor with an authorization
- Links the payment to the cart via a
createRelationcommand - Sends a
completemessage to the cart ticket actor
When a cart is completed:
- The
cart-to-orderrule fires, creating a real order from the cart's preview - The cart state changes to
completed - The
orderIdandorderNumberbecome available in the rendered cart - SSE subscribers receive the final cart state
See PSP Integration for the recommended completion pattern.
Cart Profiles
Cart profiles are configured in the Commerce app registry under apps/commerce/profiles/{key}. Each profile defines:
| Setting | Description |
|---|---|
currencyCode | Currency for the cart (e.g., SEK, EUR) |
defaultCountryCode | Default shipping country |
allowedCountries | List of allowed shipping country codes |
channelKey | Sales channel key for the order |
Retrieve available profiles via the Get Cart Profiles endpoint.