Skip to content

Cart Lifecycle ​

A Commerce cart progresses through distinct stages: creation, mutation, rendering, and completion.

States ​

StateDescription
openActive cart, can be modified
completedCart has been completed (order created)
rejectedNot 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:

bash
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.

Captured client context ​

At creation time, Commerce captures request context from standard headers and stores it on the cart. These are forwarded onto the resulting order on completion (as cart:* dynamic fields) for conversion tracking and auditing:

HeaderCart fieldOrder field
User-Agentclient:userAgentcart:client:userAgent
X-Hantera-Client-IPclient:ipcart:client:ip
Origin / RefererstorefrontUrlcart:storefrontUrl

The client IP is the resolved shopper IP (see HTTP Ingress Parameters → Client IP Address). It is deliberately captured at cart creation rather than completion, because completion may be triggered by a PSP from a different remote address. The order exposes it as the queryable graph field clientIp, so orders can be filtered by originating shopper IP.

Mutating a Cart ​

Cart mutations are performed via the Commerce ingresses. Most mutations return the rendered cart.

Adding and Managing Items ​

bash
# 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 ​

bash
# Set email
POST /ingress/commerce/carts/{cartId}/email
{ "email": "[email protected]" }

# 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:

bash
# 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/paymentProvider

Custom fields appear in the rendered cart under the fields property, and are projected onto the created order as cart:<key>. Apps store their own state on the cart the same way, using key prefixes to control what reaches the order — see Cart Dynamic Fields.

Rendering ​

Every mutation endpoint returns the rendered cart — a normalized structure with computed prices, totals, and tax. The rendering pipeline:

  1. Sends a complete message to the cart actor in preview mode (no persistent changes)
  2. This triggers all order creation rules (including price lookup, discounts, shipping)
  3. Queries the preview result for order totals and line items
  4. Maps the data into the rendered cart structure

The rendered cart includes:

  • orderTotal, orderTaxTotal, shippingTotal, productTotal — computed totals
  • items[] — each item with unitPrice, total, tax, discount
  • fields — custom fields set via the set-field endpoint
  • cartState — 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:

javascript
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:

  1. Creates a Payment actor with an authorization
  2. Links the payment to the cart via a createRelation command
  3. Sends a complete message to the cart ticket actor

When a cart is completed:

  • The cart-to-order rule fires, creating a real order from the cart's preview, and projecting the cart's prefixed dynamic fields onto the order and its delivery
  • The cart state changes to completed
  • The orderId and orderNumber become 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:

SettingDescription
currencyCodeCurrency for the cart (e.g., SEK, EUR)
defaultCountryCodeDefault shipping country
allowedCountriesList of allowed shipping country codes
channelKeySales channel key for the order

Retrieve available profiles via the Get Cart Profiles endpoint.

© 2026 Hantera AB. Org. no.: 559242-9582