# Reserve stock on Cart Learn how to prevent overselling and improve the checkout experience by automatically reserving items in a Cart. In this tutorial, you will learn how to temporarily reserve products for a customer, giving them time to complete their checkout. By the end, you will have created a Cart with reserved Line Items and will understand how to manage these reservations. You will learn to: - Create a Cart that automatically reserves items. - Extend the duration of a reservation. - Understand and handle different reservation-related warnings. ## Prerequisites Before you begin, you should be familiar with: - Concepts such as [Products](/api/projects/products.md#product), [Carts](/api/projects/carts.md#cart), and [Inventory](/api/projects/inventory.md#inventoryentry). - Using a REST API client such as Postman or Insomnia to interact with the Composable Commerce API. - General concepts around [Project setup](/merchant-center/organizations-teams-projects.md#manage-projects) and [API Client management](/merchant-center/developer-settings.md#api-clients) in the Merchant Center. You should also have a [commercetools Project](/api/projects/project.md#project) with the following: - **A Product**: Create a [Product](/search.md?urn=ctp:api:type:Product) with at least one [Product Variant](/api/projects/products.md#productvariant). Note the `SKU` of the variant. - **API Client**: An [API Client](/api/projects/api-clients.md#apiclient) with the following [scopes](/api/scopes.md): - `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. All examples in this tutorial use [cURL](https://curl.se/), but you can adapt them to your preferred tool. ## Instructions The following instructions walk through creating and managing stock reservations. The scenario follows a customer who adds a popular, limited-stock item to their cart. To ensure they have a chance to purchase it, the item is reserved for them for a limited time. ### Set the Project-level expiration Before you can use reservations, you must set the Project-level reservation expiration time. After you set this default, you'll be able to use the `ReserveOnCart` [InventoryMode](/search.md?urn=ctp:api:type:InventoryMode), which automatically reserves Line Items when they are added to the Cart. 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. To do this, use the [Set Reservation Expiration in Minutes](/api/projects/project.md#set-reservation-expiration-in-minutes) update action on the [Project](/api/projects/project.md) and specify a value between 1 and 44640 minutes (31 days). This value will be the fallback for any inventory entry that doesn't have a specific expiration set. The next section covers how to create a reservation and override the Project-level reservation expiration time for individual SKUs. ### Create a reservation First, create a Cart with a product to be reserved. #### Create an Inventory Entry Ensure you have an [Inventory Entry](/api/projects/inventory.md#inventoryentry) for your Product Variant (`SKU-1` in this example) with stock available. In this example, `reservationExpirationInMinutes` is set to 30 minutes. If you omit this value, the Project-level default will be used. Both the Project-level and InventoryEntry-level `reservationExpirationInMinutes` values must be at least 1 minute and at most 44640 minutes (31 days). ```bash title="Create an Inventory Entry for SKU-1" 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, "reservationExpirationInMinutes": 30 }' ``` #### Create a Cart Now, create a Cart that supports reservations, and add the Product. By setting the Cart [`inventoryMode`](/api/projects/carts.md#inventorymode) to `ReserveOnCart`, you instruct commercetools to create a reservation for all the Line Items in the Cart. You can specify a different `inventoryMode` for each Line Item, allowing for mixed reservation behaviors within a single Cart. ```bash title="Create a Cart with ReserveOnCart inventory mode" 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", "inventoryMode": "ReserveOnCart", "lineItems": [ { "sku": "SKU-1", "quantity": 1 } ] }' ``` After this call, a Cart is created, and a [Reservation](/api/projects/reservations.md) is automatically created for `SKU-1`. The reservation expiration time is the same one that was set in the associated Inventory Entry. In this case, the reservation is valid for 30 minutes. The `availableQuantity` for this SKU is reduced by 1, while `quantityOnStock` remains unchanged until the Order is placed. This change is [eventually consistent](/api/general-concepts.md#eventual-consistency) and may take up to 10 seconds to appear. For more details, see [Inventory checks and consistency](/api/inventory-overview.md#inventory-checks-and-consistency). #### Verify the reservation You can verify that the reservation was successful by checking the response. You will see a `reservation` field on the Line Item, containing a reference to the created `Reservation` object. The absence of any warnings is also a good indicator that everything worked as expected. ```json { "lineItems": [ { "id": "...", "productId": "...", "name": { "...": "..." }, "variant": { "...": "..." }, "quantity": 1, "reservation": { "typeId": "reservation", "id": "..." } } ], "inventoryMode": "ReserveOnCart", "warnings": [] } ``` As with any reference in the commercetools Platform, you can [expand](/api/general-concepts.md#reference-expansion) it to get more details about the reservation. ### Extend a reservation Cart interactions can be complex. Payments might fail or additional validation steps can delay checkout. To prevent a reservation from expiring while the customer is completing their purchase, you can extend its duration. #### Extend the reservation Before the reservation expires, you can extend it by sending the [Set Reservation Expiration in Minutes](/api/projects/carts.md#set-reservation-expiration-in-minutes) update action to the Cart. You will need to provide a new expiration duration in minutes. ```bash title="Extend the reservation for the Cart" 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": 1, "actions": [ { "action": "setReservationExpirationInMinutes", "reservationExpirationInMinutes": 30 } ] }' ``` This will update the underlying `Reservation` object, setting its expiration time to 30 minutes from now. The [Set Reservation Expiration in Minutes](/api/projects/carts.md#set-reservation-expiration-in-minutes) Cart update action extends all existing reservations for the Cart, meaning **all Line Items in the Cart will now expire at the same time**. #### Verify the extension From the response, you should see no warnings, indicating the extension was successful. The `reservation` field remains present. To see the details, you can [expand](/api/general-concepts.md#reference-expansion) the reservation reference. ## Handle reservation warnings When creating or updating a Cart, a reservation can potentially fail. When this happens, commercetools ensures that the Cart remains orderable by adjusting its contents and provides a warning for each failure. The behavior depends on whether you are creating or updating a Cart: - When **creating** a Cart, if all Line Items with `inventoryMode: "ReserveOnCart"` fail to be reserved, the entire operation fails with a `400 Bad Request` (InvalidOperation) error. If only some items fail, the Cart is created, but the failed Line Items are removed from it and mentioned in a warning (see [Scenario 1](/tutorials/reserve-stock-on-cart.md#scenario-1-cannotcreatereservation)). - When **updating** a Cart, if a reservation update for a Line Item cannot be fulfilled (for example, when increasing its quantity), a warning is added to the response (see [Scenario 2](/tutorials/reserve-stock-on-cart.md#scenario-2-cannotupdatereservation)) and the quantity is not updated. In all cases of partial success or adjustment, a warning is added to the response. This gives you the information needed to create the experience you want for your customers, like notifying them about the changes in their Cart. The following diagram summarizes the different reservation scenarios: ```mermaid sequenceDiagram participant Customer participant Your Application participant commercetools Carts API participant Inventory rect rgb(239, 240, 241) note over Customer, Inventory: Cart 1: Successful reservation Note over Customer, Inventory: Initial State: 5 items available. Customer->>Your Application: Add 2 items Your Application->>commercetools Carts API: Create Cart (qty: 2) commercetools Carts API->>Inventory: Reserve 2 items (Available: 5) Inventory-->>commercetools Carts API: Reservation OK (Reserved: 2, Available: 3) commercetools Carts API-->>Your Application: Cart created (qty: 2, reserved: 2) end rect rgb(239, 240, 241) note over Customer, Inventory: Cart 2: Failed reservation update Note over Customer, Inventory: Initial State: Cart with 2 items reserved, 3 available. Customer->>Your Application: Increase quantity to 6 (add 4) Your Application->>commercetools Carts API: Update Cart (change qty to 6) commercetools Carts API->>Inventory: Try to reserve 4 more items (Available: 3) Inventory-->>commercetools Carts API: Insufficient stock. Reservation stays at 2. note right of commercetools Carts API: Reservation update fails, original reservation kept. Exceeding quantity is removed. commercetools Carts API-->>Your Application: Cart updated (qty: 2, reserved: 2) with 'CannotUpdateReservation' warning end rect rgb(239, 240, 241) note over Customer, Inventory: Cart 3: Failed reservation on creation (all items) Note over Customer, Inventory: Initial State: 5 items available. Customer->>Your Application: Add 6 items Your Application->>commercetools Carts API: Create Cart (qty: 6) commercetools Carts API->>Inventory: Reserve 6 items (Available: 5) Inventory-->>commercetools Carts API: Insufficient stock for 6 note right of commercetools Carts API: Reservation creation fails for the only Line Item. commercetools Carts API-->>Your Application: 400 Bad Request (InvalidOperation) end rect rgb(239, 240, 241) note over Customer, Inventory: Cart 4: Failed reservation on creation (partial) Note over Customer, Inventory: Initial State: SKU-1 has 5 items available, SKU-2 has 0. Customer->>Your Application: Add SKU-1 (qty: 3) and SKU-2 (qty: 1) Your Application->>commercetools Carts API: Create Cart (SKU-1 qty: 3, SKU-2 qty: 1) commercetools Carts API->>Inventory: Reserve SKU-1 (qty: 3) and SKU-2 (qty: 1) Inventory-->>commercetools Carts API: SKU-1 OK, SKU-2 Insufficient stock. note right of commercetools Carts API: Reservation for SKU-2 fails. It is removed from the cart. commercetools Carts API-->>Your Application: Cart created with SKU-1 (qty: 3, reserved: 3), with 'CannotCreateReservation' warning for SKU-2. end ``` #### Scenario 1: `CannotCreateReservation` This warning is returned when a Line Item with [InventoryMode](/search.md?urn=ctp:api:type:InventoryMode) `ReserveOnCart` is added to a Cart, but the reservation fails due to lack of stock. When this happens, the Line Item is not added to the Cart, ensuring the Cart remains orderable. **To trigger this warning**: Create a Cart with two Line Items. One with a quantity that can be fulfilled, and another with a quantity greater than its availability. The Cart is created, but only with the Line Items that were successfully reserved. The Cart response will contain a [CannotCreateReservationWarning](/api/types.md#cannotcreatereservation-warning) for the failed Line Item. ```json { "warnings": [ { "code": "CannotCreateReservation", "message": "Failed to create a reservation for product 987fcdeb-51a2-43d1-9c4f-123456789abc (SKU: SAMPLE-SKU-001, Supply Channel: channel-123) with quantity 5.", "productId": "987fcdeb-51a2-43d1-9c4f-123456789abc", "sku": "SAMPLE-SKU-001", "supplyChannel": "channel-123", "quantity": 5 } ] } ``` **Resolution**: The Line Item was not added to the Cart. You should inform the customer that the item could not be added due to insufficient stock and was not reserved for them. #### Scenario 2: `CannotUpdateReservation` This warning is returned when you update a Line Item's quantity, but the reservation cannot be updated to match the new quantity. This is usually due to insufficient stock. The quantity of the Line Item remains the same. **To trigger this warning**: 1. Ensure `SKU-1` has a stock of 5. 2. Create a Cart with `SKU-1`, `quantity: 2`, and `inventoryMode: "ReserveOnCart"`. A reservation for 2 items is created. - Available quantity: 5 (initial) - 2 (reserved) = 3 3. Update the Cart to change the quantity of the Line Item to 6 (that is, adding 4 more items). This requires 4 additional items to be reserved, but only 3 are available. The reservation update fails, and the Line Item quantity in the Cart remains at 2 (the original quantity). - Available quantity: 3. Additional items requested: 4. Reservation update fails. The Cart response will contain a [CannotUpdateReservationWarning](/api/types.md#cannotupdatereservation-warning) warning. ```json { "warnings": [ { "code": "CannotUpdateReservation", "message": "Failed to update the reservation for line item 123e4567-e89b-12d3-a456-426614174000 (Product ID: 987fcdeb-51a2-43d1-9c4f-123456789abc, SKU: SAMPLE-SKU-001, Supply Channel: channel-123) to a quantity of 6. The reserved amount is still 2.", "lineItemId": "123e4567-e89b-12d3-a456-426614174000", "requestedQuantity": 6, "reservedQuantity": 2, "productId": "987fcdeb-51a2-43d1-9c4f-123456789abc", "sku": "SAMPLE-SKU-001", "supplyChannel": "channel-123" } ] } ``` **Resolution**: The line item quantity was not updated. You should inform the customer that only part of their desired quantity is reserved. #### Scenario 3: `CannotChangeReservationExpiry` This warning appears if you try to extend a reservation that has already expired or is in a state that doesn't allow extension. **To trigger this warning**: 1. Use the [Set Reservation Expiration In Minutes](/api/projects/inventory.md#set-reservation-expiration-in-minutes) update action on the Inventory Entry and specify a short duration, for example, 1 minute. 2. Create a Cart with `SKU-1` and `inventoryMode: "ReserveOnCart"`. 3. Wait for the reservation to expire. 4. Try to extend the Cart's reservations using the [Set Reservation Expiration in Minutes](/api/projects/carts.md#set-reservation-expiration-in-minutes) update action on the Cart. The action succeeds, but the response includes a [CannotChangeReservationExpiryWarning](/api/types.md#cannotchangereservationexpiry-warning) warning because the underlying reservation could not be extended. ```json { "warnings": [ { "code": "CannotChangeReservationExpiry", "message": "The reservation expiration for line item 448085fc-fe34-484a-8d77-ad6b9148ef59 cannot be changed.", "lineItemId": "448085fc-fe34-484a-8d77-ad6b9148ef59" } ] } ``` **Resolution**: The reservation has expired, and the stock has been released. You should inform the customer that the item is no longer reserved for them. They might need to add it to the Cart again to create a new reservation, provided stock is still available. ## Summary You have learned how to: - Use the `ReserveOnCart` inventory mode to create temporary stock reservations. - Extend reservations to give customers more time to check out. - Understand and handle warnings related to reservation mismatches and expirations. This feature helps improve the customer experience for high-demand products by providing a fair window for purchase. When implementing this in a real project, remember to build user-facing notifications for the various warning scenarios to keep your customers informed. ## Further reading To learn more about implementing reservations, see the following resources: - [Reserve stock on demand and freeze prices](/tutorials/reserve-stock-on-demand.md): prevent overselling by reserving items on demand while freezing prices. - [Inventory overview](/api/inventory-overview.md): information about managing inventory, reservations, and stock levels. ## Related pages - [Area overview page with navigation](/tutorials.md) - [Previous page: Implement guest checkout](/tutorials/anonymous-session.md) - [Next page: Reserve stock on demand and freeze prices](/tutorials/reserve-stock-on-demand.md) - [Search documentation and API specs](/search.md)