Learn how to prevent overselling and improve the checkout experience by reserving items on demand while freezing all prices.
In this tutorial, you will learn how to combine reserving stock with freezing Cart prices. This approach ensures that customers can complete their checkout with the products they want, at the prices they expect.
You will learn to:
- Enable reservation functionality in your Project.
- Create a Cart with unreserved Line Items.
- Reserve stock by changing the inventory mode of each Line Item.
- Check for warnings indicating unsuccessful reservations.
- Freeze the prices, discounts, and shipping costs of Line Items.
Prerequisites
Before you begin, you should be familiar with:
- Composable Commerce concepts such as Products, Carts, and Inventory.
- Using a REST API client such as Postman or Insomnia to interact with the Composable Commerce API.
- General concepts around Project setup and API Client management in the Merchant Center.
- The
ReserveOnCartinventory mode, including how reservations work and their implications.
- A Product: Create a Product with at least one Product Variant. Note the
SKUof the variant. - API Client: An API Client with the following scopes:
manage_orders:{projectKey}to create and update Carts and Orders.manage_project_settings:{projectKey}to update reservation-related Project settings.manage_products:{projectKey}to create and update Inventory Entries.
Instructions
Consider a scenario in which you want to ensure a customer successfully completes the checkout of their Cart. You can use the following two features together to achieve this:
-
Freezing a Cart: prevents price changes to the Cart during checkout, depending on the chosen freeze strategy.
-
ReserveOnCartInventoryMode: reserves items in the Cart. Reservations remain active until the Cart is ordered or the reservation expires.
You can apply this inventory mode in one of two ways:
- On the Cart: all Line Items are reserved automatically. This is useful when you want to reserve stock for all items as soon as they are added to the Cart.
- On individual Line Items: some or all Line Items are reserved, but at a specific point in time that you choose. This approach gives you more control over when to reserve stock during your checkout flow.
This tutorial focuses on setting the inventory mode on individual Line Items, allowing you to reserve stock on demand.
Benefits of combining freezing with reservations
Without freezing, a customer's Cart total can change between adding items and completing checkout. For example, a price promotion could end, a discount could be removed, or shipping costs could increase. This creates an unpredictable checkout experience.
Similarly, without reserving stock, items can become unavailable during checkout. For example, a customer has an item in their Cart and is actively checking out. Another customer comes along and purchases the last available item, causing the first customer's order to fail.
By combining both features, you ensure that:
- The Cart total remains the same during the entire checkout flow.
- Stock is guaranteed to be available when you create the Order.
This gives customers confidence that Cart prices and items remain accurate throughout checkout.
setLineItemInventoryMode update action to reserve stock on individual Line Items, then freeze prices with freezeCart. Before doing that, enable reservations on your Project, then create an Inventory Entry and a Cart.Set the Project-level expiration
ReserveOnCart InventoryMode.This is a mandatory step to ensure that stock is not held indefinitely, which could lead to it being unavailable for other customers. You only have to set this once per Project.
curl -X POST "https://api.europe-west1.gcp.commercetools.com/{{project-key}}" \
-H "Authorization: Bearer {{auth-token}}" \
-H "Content-Type: application/json" \
-d '{
"version": {{project-version}},
"actions": [
{
"action": "setReservationExpirationInMinutes",
"reservationExpirationInMinutes": 30
}
]
}'
Create an Inventory Entry
sku as your Product Variant (SKU-1 in this example). Set the quantityOnStock to 10.curl -X POST "https://api.europe-west1.gcp.commercetools.com/{{project-key}}/inventory" \
-H "Authorization: Bearer {{auth-token}}" \
-H "Content-Type: application/json" \
-d '{
"sku": "SKU-1",
"quantityOnStock": 10
}'
Create a Cart
inventoryMode property so that Line Items use the default mode: None.curl -X POST "https://api.europe-west1.gcp.commercetools.com/{{project-key}}/carts" \
-H "Authorization: Bearer {{auth-token}}" \
-H "Content-Type: application/json" \
-d '{
"currency": "USD",
"lineItems": [
{
"sku": "SKU-1",
"quantity": 1
}
]
}'
Verify no reservation was made
ReserveOnCart, no stock has been reserved. Verify stock availability by checking the availableQuantity of the Inventory Entry. It will still be equal to 10.curl -X GET "https://api.europe-west1.gcp.commercetools.com/{{project-key}}/inventory/{{inventory-id}}" \
-H "Authorization: Bearer {{auth-token}}"
Reserve stock
When the customer reaches a desired point in the checkout flow, you can reserve stock for the items in the Cart. After that, you can freeze the Cart to lock in prices, discounts, and shipping costs. Reserve stock before freezing to ensure that stock is actually available.
setLineItemInventoryMode update action.setLineItemInventoryMode update action for each Line Item that you want to reserve.curl -X POST "https://api.europe-west1.gcp.commercetools.com/{{project-key}}/carts/{{cart-id}}" \
-H "Authorization: Bearer {{auth-token}}" \
-H "Content-Type: application/json" \
-d '{
"version": {{cart-version}},
"actions": [
{
"action": "setLineItemInventoryMode",
"lineItemId": "{{line-item-id}}",
"inventoryMode": "ReserveOnCart"
}
]
}'
Verify the reservation
inventoryMode of each Line Item will be ReserveOnCart. The absence of any warnings is also a good indicator that everything worked as expected.ReserveOnCart and the Cart's warnings field contains a CannotCreateReservationWarning, then the reservation was unsuccessful. You'll need to handle these warnings before proceeding to freeze the Cart.When a reservation fails, you have several options:
- Increase the quantity of the low stock inventory entry and retry the
setLineItemInventoryModeupdate action. - Set the
inventoryModeof the low stock line item toTrackOnly. Using this inventory mode, an Order can be created even if there is insufficient stock. The line itemquantitywill be deducted from the inventory entry quantity when ordering, which means the inventory can go negative. This is the intended behavior when usingTrackOnlyas a fallback. - Remove the low stock line item from the Cart. You can alternatively use this same update action to reduce the
quantityto a value that doesn't exceed the inventory entry'savailableQuantity. - Set
restockableInDayson the inventory entry and retrysetLineItemInventoryMode. Reservations usingReserveOnCartorReserveOnOrderwill succeed, even when there is insufficient stock, ifrestockableInDaysis defined.
Freeze the Cart
SoftFreeze or HardFreeze. Using the HardFreeze strategy ensures shipping costs and all discounts are frozen, which guarantees that the Cart total doesn't change during checkout.curl -X POST "https://api.europe-west1.gcp.commercetools.com/{{project-key}}/carts/{{cart-id}}" \
-H "Authorization: Bearer {{auth-token}}" \
-H "Content-Type: application/json" \
-d '{
"version": {{cart-version}},
"actions": [
{
"action": "freezeCart",
"strategy": "HardFreeze"
}
]
}'
cartState field should be set to Frozen. At this point, stock is reserved for your specified Line Items and all prices, discounts, and shipping costs are frozen.Create the Order
Before the reservations expire, you must create an Order from the Cart. When you do this, the reserved stock is permanently deducted from inventory. If you don't create an Order before the reservation expiration time, the stock will be released and become available for other Carts to reserve.
Best practices
To ensure a smooth checkout process, you should:
- Handle unsuccessful reservations before ordering: if any Line Item's
inventoryModewas not updated toReserveOnCart, the inventory entry's stock will not be deducted when you create the Order. - Set appropriate expiration times: to prevent Denial of Stock attacks, all reservations have a mandatory expiration time between 1 and 44640 minutes (31 days). Configure a
reservationExpirationInMinutesvalue that gives customers enough time to complete checkout without holding stock unnecessarily long. When a Line Item reservation expires, the stock becomes available again for other Carts to reserve. - Extend expiration times proactively: if a customer's checkout takes longer than expected, extend the expiration of every Line Item reservation in the Cart before they expire. This prevents the Cart from becoming unorderable.
- Check reservation status: before ordering a Cart, check for reservations that have expired or are about to expire. Use reference expansion on the
reservationfield of a Line Item to check the reservation validity. - Handle re-reservation failures: the Cart will automatically attempt to re-reserve stock when creating an Order. If the stock is no longer available, then creating the Order will fail with an
OutOfStockerror. Use the same logic to handle reservation failures that can occur when renewing expired Line Item reservations. - Account for eventual consistency: changes to the
availableQuantityandquantityOnStockfields resulting from reservation operations are eventually consistent and may take up to 10 seconds to be reflected. See Inventory checks and consistency for details on how this affects your implementation.
Summary
You have learned how to:
- Enable reservation functionality in your Project.
- Reserve stock on demand, at any stage during your checkout process.
- Check for warnings indicating unsuccessful reservations.
- Handle failures when reserving stock.
- Freeze prices, discounts, and shipping costs to ensure a consistent checkout experience.
This approach gives you flexibility in when to commit inventory, allowing you to balance customer experience with inventory management needs. When implementing this in a real project, consider your specific checkout flow and adjust the timing of reservations accordingly.
Further reading
To learn more about implementing reservations, see the following resources:
-
Reserve stock on Cart: prevent overselling and improve the checkout experience by automatically reserving items in a Cart.
-
Inventory overview: information about managing inventory, reservations, and stock levels.