# Working with baskets A core part to the shopping experience using Norce Commerce Services is the Basket. This is the container to the list of items the visitor is interested in. The basket in Norce contains a lot of functionality and is dependent on many business rules that are evaluated and applied for every action the visitor does from your commerce application. Aside from the most common use of the basket object (the cart), there is also other ways to use it. Like wish lists, approval/attests, saved for later, sent to punch out, subscriptions/recurring orders, etc. These functions are not addressed in this document. - [The full Basket Schema](/api-reference/schemas/shopping#basket) - Check out the examples in [Postman](https://documenter.getpostman.com/view/2973406/2sA35MzK14#d8eb437c-32b1-4dc3-a867-1bab2f923d2d) as well. details summary An example basket ```JSON { "Id": 6600304, "CustomerId": null, "CompanyId": null, "SalesContactId": null, "StatusId": 3, "CurrencyId": 2, "CurrencyCode": "SEK", "Comment": null, "OrderReference": null, "DiscountCode": null, "ReferId": null, "ReferUrl": null, "ValidTo": null, "IsEditable": true, "Items": [ { "Id": 16030464, "LineNo": 1, "ParentLineNo": null, "ProductId": 31234584, "PartNo": "PRD0001270", "ManufacturerPartNo": "T540XP", "Name": "T540XP", "SubHeader": "

Detta är en kort beskrivning.

", "ThumbnailImage": "2/thumb_p31234584.jpg", "FlagIdSeed": "915,1884", "Type": 1, "PriceDisplay": 5743.20, "Price": 0.00, "PriceOriginal": 5743.20, "Cost": 5734.34, "VatRate": 1.2500, "Quantity": 1.000, "UOM": "st", "UOMCount": 1.000, "Comment": null, "PriceListId": 4654, "ReferId": null, "ReferUrl": null, "IsEditable": true, "IsDiscountable": true, "Info": [ { "TypeId": 209, "Value": "", "Code": "bit_size" }, { "TypeId": 241, "Value": "", "Code": "bit_del_time" }, { "TypeId": 95, "Value": "", "Code": "bit_additionalinformation" } ], "OptionalItems": [], "OnHandValue": 0.000, "IncomingValue": 0.000, "NextDeliveryDate": null, "LeadtimeDayCount": null, "PromotionIdSeed": "", "ImageKey": "39e4b7ec-12d8-4f6e-b9c1-cbd7334190e1", "ManufacturerName": "Husqvarna", "CategoryId": 41722, "OnHand": { "Value": 0.000, "IncomingValue": 0.000, "NextDeliveryDate": null, "LeadtimeDayCount": null, "LastChecked": null, "IsActive": false, "IsReturnable": true, "Info": null }, "OnHandSupplier": { "Value": 200.000, "IncomingValue": 0.000, "NextDeliveryDate": null, "LeadtimeDayCount": 7, "LastChecked": null, "IsActive": true, "IsReturnable": true, "Info": null }, "PriceRecommended": 7000.00, "ManufacturerId": 1685, "UniqueName": "t540xp", "StatusId": 1, "StockDisplayBreakPoint": null, "PriceCatalog": null, "IsBuyable": true, "SubDescription": null, "CategoryIdSeed": "41722", "RecommendedQuantity": 4.000, "IsRecommendedQuantityFixed": false, "AppliedPromotions": [], "RequirementPromotionIdSeed": "5093", "IsSubscribable": false, "DescriptionHeader": "Husqvarna T540XP", "IsPriceManual": false, "PriceStandard": 6375.20, "EanCode": "123123123123123", "CostUnit": 0.00, "PriceDisplayIncVat": 7179.00 }, { "Id": 16030465, "LineNo": 2, "ParentLineNo": null, "ProductId": 24706222, "PartNo": "PRD0001212", "ManufacturerPartNo": "FREIGHT01", "Name": "Freight", "SubHeader": null, "ThumbnailImage": null, "FlagIdSeed": "915", "Type": 3, "PriceDisplay": 0.00, "Price": 0.00, "PriceOriginal": 0.00, "Cost": 0.00, "VatRate": 1.25, "Quantity": 1.000, "UOM": "st", "UOMCount": 1.000, "Comment": null, "PriceListId": 1, "ReferId": null, "ReferUrl": null, "IsEditable": true, "IsDiscountable": true, "Info": [ { "TypeId": 209, "Value": "", "Code": "bit_size" }, { "TypeId": 241, "Value": "", "Code": "bit_del_time" }, { "TypeId": 95, "Value": "", "Code": "bit_additionalinformation" } ], "OptionalItems": [], "OnHandValue": 0.000, "IncomingValue": 0.000, "NextDeliveryDate": null, "LeadtimeDayCount": 0, "PromotionIdSeed": null, "ImageKey": null, "ManufacturerName": "Miscellaneous", "CategoryId": null, "OnHand": { "Value": 0.000, "IncomingValue": 0.000, "NextDeliveryDate": null, "LeadtimeDayCount": 0, "LastChecked": "/Date(1325504774807+0100)/", "IsActive": true, "IsReturnable": true, "Info": null }, "OnHandSupplier": { "Value": 0.000, "IncomingValue": 0.000, "NextDeliveryDate": null, "LeadtimeDayCount": null, "LastChecked": null, "IsActive": false, "IsReturnable": true, "Info": null }, "PriceRecommended": null, "ManufacturerId": 4335, "UniqueName": "freight", "StatusId": 1, "StockDisplayBreakPoint": null, "PriceCatalog": null, "IsBuyable": true, "SubDescription": null, "CategoryIdSeed": "", "RecommendedQuantity": 1.000, "IsRecommendedQuantityFixed": false, "AppliedPromotions": [], "RequirementPromotionIdSeed": null, "IsSubscribable": false, "DescriptionHeader": null, "IsPriceManual": false, "PriceStandard": 0.00, "EanCode": "", "CostUnit": 0.00, "PriceDisplayIncVat": 0.00 }, { "Id": 0, "LineNo": 3, "ParentLineNo": 1, "ProductId": 31234588, "PartNo": "PRD0001274", "ManufacturerPartNo": "Underhållskit", "Name": "Underhållskit Motorsåg", "SubHeader": null, "ThumbnailImage": "2/thumb_p31234588.png", "FlagIdSeed": "915", "Type": 1, "PriceDisplay": 111.20, "Price": 0.00, "PriceOriginal": 111.20, "Cost": 100.25, "VatRate": 1.25, "Quantity": 1, "UOM": "st", "UOMCount": 1.000, "Comment": null, "PriceListId": 1, "ReferId": null, "ReferUrl": null, "IsEditable": false, "IsDiscountable": true, "Info": [ { "TypeId": 209, "Value": "", "Code": "bit_size" }, { "TypeId": 241, "Value": "", "Code": "bit_del_time" }, { "TypeId": 95, "Value": "", "Code": "bit_additionalinformation" } ], "OptionalItems": [], "OnHandValue": 12.000, "IncomingValue": 0.000, "NextDeliveryDate": null, "LeadtimeDayCount": 0, "PromotionIdSeed": "", "ImageKey": null, "ManufacturerName": "Husqvarna", "CategoryId": 41722, "OnHand": { "Value": 12.000, "IncomingValue": 0.000, "NextDeliveryDate": null, "LeadtimeDayCount": 0, "LastChecked": null, "IsActive": true, "IsReturnable": true, "Info": null }, "OnHandSupplier": { "Value": 133.000, "IncomingValue": 0.000, "NextDeliveryDate": null, "LeadtimeDayCount": 5, "LastChecked": "/Date(1487085555163+0100)/", "IsActive": true, "IsReturnable": true, "Info": null }, "PriceRecommended": null, "ManufacturerId": 1685, "UniqueName": "underhallskit-motorsag", "StatusId": 1, "StockDisplayBreakPoint": null, "PriceCatalog": null, "IsBuyable": true, "SubDescription": null, "CategoryIdSeed": "41722", "RecommendedQuantity": 1.000, "IsRecommendedQuantityFixed": false, "AppliedPromotions": [], "RequirementPromotionIdSeed": "", "IsSubscribable": false, "DescriptionHeader": null, "IsPriceManual": false, "PriceStandard": 0.00, "EanCode": "345345345345345", "CostUnit": 0.00, "PriceDisplayIncVat": 139.00 } ], "Info": [ { "TypeId": 169, "Value": "", "Code": "bit_expecteddeliverydate" }, { "TypeId": 293, "Value": "", "Code": "bit_additionalorderinfo" }, { "TypeId": 445, "Value": "", "Code": "Norce_Gender" }, { "TypeId": 493, "Value": "", "Code": "recurring" } ], "Summary": { "Items": { "Amount": 5854.40, "Vat": 1463.60, "AmountIncVat": 7318.00 }, "Freigt": { "Amount": 0.00, "Vat": 0.00, "AmountIncVat": 0.00 }, "Fees": { "Amount": 0.00, "Vat": 0.00, "AmountIncVat": 0.00 }, "Total": { "Amount": 5854.40, "Vat": 1463.60, "AmountIncVat": 7318.00 } }, "AppliedPromotions": [ { "Id": 5093, "Name": "Add service", "Header": "", "ShortDescription": "", "Description1": "", "Description2": "", "StartDate": null, "EndDate": null, "ImageKey": null, "RequirementSeed": "3", "DiscountCode": null, "IsExcludedFromPriceCalculation": false, "AllowProductListing": false, "Images": [], "ProductFilters": [ { "ManufacturerId": null, "CategorySeed": null, "TypeId": null, "ProductId": null, "VariantProductId": null, "PartNo": "PRD0001274", "PricelistId": 1, "FlagId": null }, { "ManufacturerId": null, "CategorySeed": null, "TypeId": null, "ProductId": null, "VariantProductId": null, "PartNo": null, "PricelistId": null, "FlagId": 1884 } ], "AppliedAmount": 0.00, "EffectSeed": "5", "FreightDiscountPct": null, "IsStackable": true, "AppliedAmountIncVat": 0.00 } ], "IpAddress": "151.236.200.213", "AttestedBy": null, "TypeId": 1, "DoHold": false, "IsBuyable": true, "InvoiceReference": null, "PaymentMethodId": null, "DeliveryMethodId": 1, "SalesAreaId": 1 } ``` ```XML 6600304 3 2 SEK true 16030464 1 31234584 PRD0001270 T540XP T540XP <p>Detta är en kort beskrivning.</p> 2/thumb_p31234584.jpg 915,1884 1 5743.20 0.00 5743.20 5734.34 1.25 1 st 1.000 4654 true true 209 bit_size 241 bit_del_time 95 bit_additionalinformation 0.000 0.000 39e4b7ec-12d8-4f6e-b9c1-cbd7334190e1 Husqvarna 41722 0.000 0.000 false true 200.000 0.000 7 true true 7000.00 1685 t540xp 1 true 41722 4.000 false 5093 false Husqvarna T540XP false 6375.20 123123123123123 0.00 7179.00 16030465 2 24706222 PRD0001212 FREIGHT01 Freight 915 3 0.00 0.00 0.00 0.00 1.25 1 st 1.000 1 true true 209 bit_size 241 bit_del_time 95 bit_additionalinformation 0.000 0.000 0 Miscellaneous 0.000 0.000 0 2012-01-02T12:46:14.807 true true 0.000 0.000 false true 4335 freight 1 true 1.000 false false false 0.00 0.00 0.00 0 3 1 31234588 PRD0001274 Underhållskit Underhållskit Motorsåg 2/thumb_p31234588.png 915 1 111.20 0.00 111.20 100.25 1.25 1 st 1.000 1 false true 209 bit_size 241 bit_del_time 95 bit_additionalinformation 12.000 0.000 0 Husqvarna 41722 12.000 0.000 0 true true 133.000 0.000 5 2017-02-14T16:19:15.163 true true 1685 underhallskit-motorsag 1 true 41722 1.000 false false false 0.00 345345345345345 0.00 139.00 169 bit_expecteddeliverydate 293 bit_additionalorderinfo 445 Norce_Gender 493 recurring 5854.40 1463.60 7318.00 0.00 0.00 0.00 0.00 0.00 0.00 5854.40 1463.60 7318.00 5093 Add service
3 false false PRD0001274 1 1884 0.00 5 true 0.00 151.236.200.213 1 false true 1 1 ``` ## The basket data model ![Basket data model](/assets/the-basket-data-model-new.05f55cdd8f64c0fd9ee920f3bdcf5d3940f779d6a10b472465d6fffee31063b9.afe294b5.png) The basket contains many properties, here are some important ones. - `Id`, the identifier of the basket. For the visitors active basket, this is usually stored in a persisted cookie - `Status`, basket can have different statuses, depending on the usage. For a cart the most common are *"Basket"* (3), *"Ready for payment"* (7), *"Payment pending"* (12), *"Payment Accepted"* (8), *"Order"* (10). - `Currency`, if the application allowed for different currencies this field can be changed. The basket will the convert the prices and amounts to the chosen currency. - `IsEditable` and `IsBuyable`, in some instances the basket is locked and cannot be updated by the visitor or not able to be processed through a checkout. Some examples are when the basket has become an order, or during the checkout process. - `Summary`, this contains summary information on the total amount and freight. - `Items`, are a collection of all the products added to the basket, with - `Id`, the identifier of the `BasketItem` (this is required for the update calls) - `LineNo`, a friendly number of the row - `ParentLineNo`, for complex items (like packages), or for user-friendly grouping of items - `ProductId` and `PartNo`, identifiers of the product. A basket item must be connected to a product in Norce Commerce - `Type`, the product type - `PriceDisplay`, the price in a friendly format, for read only - `Quantity`, number of items in the basket - `PriceListId`, the price list the price is based from - `IsEditable`, in some instances the basket item cannot be updated by the visitor Restrictions Norce handles quite a lot of the basket business logic behind the scenes. For example if you add an item to the basket that already exists, Norce does not increment the existing row´s quantity, instead a new line is added to the basket. This is because many solutions needs to have this flexibility, for example: A B2B sales model often needs to separate items into rows and add delivery or invoice references separately for each item. *A common practice is to add these simplifications in your own backend in a service layer where your Norce Commerce requests pass through. This lets you simplify the workflow specific to your needs.* ## The update pattern When working with baskets there is a lot of possible changes that will happen to the basket for every action the visitor does. Therefore, Norce Commerce Shopping Service always return the whole basket object whenever a change is done. A good common practice is to have the basket stored in a cache, or (if concurrency is an issue i.e. if many clients work with the same lists) ask for the basket first before mapping in your changes and then call the update in the API. ![Update pattern](/assets/the-update-pattern-new.60a8d0d1003b08db1ceb0159814cd2ec3bcf64ebece14cdd16aa5210aa0e2d40.afe294b5.png) 1. A user action has occurred. 2. A basket object is fetched, either from Norce Commerce or from a local cache 3. The changes are mapped into the basket item (from the model object) 4. The update is called ([UpdateBasket](/api-reference/services/shoppingservice/openapi/basket/updatebasket2), [UpdateBasketItem](/api-reference/services/shoppingservice/openapi/basket/updatebasketitem) or similar) 5. The whole basket is returned from Norce 6. The returned basket is mapped to a model object, written to a local cache and returned to the front end A basket can change even without user action. For example the state of an item can change so that it is not buyable anymore (not in stock anymore, status set to inactive, etc.) or a campaign or a promotion can stop being valid. This is something that your application needs to take into consideration in the fault and exception handling. ### Context There is a lot of contextual information on all gets and updates that you need to make sure to always send in to Norce Commerce Services if you are using them, for example: `pricelistSeed`, `cultureCode`, `currencyId`. They are optional but if you use any one of them in your application, they need to be passed in on all calls. Another input variable of note is the `createdBy`, that should be passed in when a known user is working with their baskets, if user is a guest/unknown set this to `1`. ## Lifecycle ### Create Basket A basket is created when the [CreateBasket](/api-reference/services/shoppingservice/openapi/basket/createbasket) method is called. Preferably this is done when the first item(s) are added to the visitors' basket. You can create a basket with default values, by passing in a whole basket object. A good idea is to pass in `CustomerId` and `CompanyId` for logged-in users, default `PaymentMethodId` and default `DeliveryMethodId`. Then you don't need to make these update calls in the checkout later. ### Add Items There are several methods to add items to the basket - `InsertBasketItem`, `InsertBasketItems`, `InsertBasketItemsWithChildren`, but also the `UpdateBasketItem` calls can increment the quantity on an existing item. - [InsertBasketItem](/api-reference/services/shoppingservice/openapi/basket/insertbasketitem), takes a basketitem as payload and appends it to the basket items collection, generating a LineNo and a unique Id to the line. - [InsertBasketItems](/api-reference/services/shoppingservice/openapi/basket/insertbasketitems), takes a collection of basketitems as payload and appends them to the basket items collection. - [InsertBasketItemWithChildren](/api-reference/services/shoppingservice/openapi/basket/insertbasketitems), takes a collection of basketitems as its payload and appends them to the basket items collection. The first item in the collection is assigned as the parent of all the others. - If you instead of appending wants to increment the quantity on already existing items you need to resolve it yourself before calling a basket method. Use [UpdateBasketItem](/api-reference/services/shoppingservice/openapi/basket/updatebasketitem) or its sibling methods. Recommended Quantity Norce has a setting called `RecommendedQuantity` on the product, which suggest how many of the item that should automatically be added to the cart, check this field when calling `InsertBasketItem`. Note that this field is not *enforced* by Norce unless it is used in combination with the setting `IsRecommendedQuantityFixed` . In that case, it is not possible to break a multiple of the `RecommendedQuantity` value. Note that this field is not *enforced* by Norce unless it is also followed with the setting `IsRecommendedQuantityFixed` - then it is not possible to break up a multiple of the `RecommendedQuantity` value. ### Remove Items Use [DeleteBasketItem](/api-reference/services/shoppingservice/openapi/basket/deletebasketitem) to removes one whole row, [UpdateBasketItem](/api-reference/services/shoppingservice/openapi/basket/updatebasketitem) calls can decrement quantity on existing items and [ClearBasket](/api-reference/services/shoppingservice/openapi/basket/clearbasket) removes all items on the basket. Note [UpdateBasketItem](/api-reference/services/shoppingservice/openapi/basket/updatebasketitem) with quantity = 0 is the same as calling [DeleteBasketItem](/api-reference/services/shoppingservice/openapi/basket/deletebasketitem). ### Change Basket Use [UpdateBasket2](/api-reference/services/shoppingservice/openapi/basket/updatebasket2) to change information on the header of the basket, like status, comment fields, etc. (mostly this is done in the checkout process, see the [checkout guide](/developer-portal/app-development/working-with-the-checkout-process) ) ### Change BasketItems [UpdateBasketItem](/api-reference/services/shoppingservice/openapi/basket/updatebasketitem), [UpdateBasketItems](/api-reference/services/shoppingservice/openapi/basket/updatebasketitems) lets you update item information on one or several items at the same time. A required field to send in to Norce Commerce Shopping Service is the `Id` on the item, without it the update won't take. Make sure to keep it in your cache. Most common field to update is the `Quantity` of course, but other fields are `Comment` and `Price`, read more about this in [the checkout process](/developer-portal/app-development/working-with-the-checkout-process). Read also about some common scenarios under common business logic [below](#common-business-logic). ### Remove or reopen the basket When a basket has been successfully processed through the checkout the status is changed to *"Payment Accepted"* or a bit later to *"Order"*. Then the basket is locked and should be removed from the active basket slot in session and cookie. If a basket is still there your application should remove it silently and create a new basket when the end customer needs it. If anything happened on a basket that has moved further in the process, you might not be allowed to continue to make changes on it. An easy way to keep the items and information on the basket is to create a new one passing in the old. Everything that is allowed to be updated to the new one will be. You clone an old basket by calling [CreateBasket](/api-reference/services/shoppingservice/openapi/basket/createbasket) with the old one as payload. See a postman example [here](https://documenter.getpostman.com/view/2973406/2sA35MzK14#232bbe75-de6d-4949-814f-75bf1aeb6493). ## Common business logic There are some more common business logic that is handled from the basket management code on your side. ### Overriding the price In some scenarios, you might want to manually override the calculated price from Norce. This might be if you create a sales quotation, or want to add an offer to the item from a 3rd party. To do this you must add your new price in the [InsertBasketItem](/api-reference/services/shoppingservice/openapi/basket/insertbasketitem) or [UpdateBasketItem](/api-reference/services/shoppingservice/openapi/basket/updatebasketitem) in the field `Price`, and confirm this by specifically adding `IsPriceManual : true` as well. > Note that the `Price` field takes the *unit price*, not the row amount. Here is an example: ```json { "PartNo": "TestPartNo", "Price": 160.00, "Quantity": 1.000, "Comment": "This is an insert of a manual price to a new row in the basket", "PriceListId": 1, "IsPriceManual": true } ``` Then the returned basket item looks like this (shortened): ```json { "LineNo": 1, "PartNo": "TestPartNo", "PriceDisplay": 160.00, "Price": 0.00, "PriceOriginal": 160.00, "Quantity": 1.000, "PriceListId": 1, "IsPriceManual": true, "PriceDisplayIncVat": 200.00 } ``` Note that the field `Price` is 0 in the result, instead, the manual price is on `PriceDisplay`, just as with any normal price, to recognize this price as a manual price you must check the `IsPriceManual` field. ### Lock the item to a price list In some scenarios, you might want to lock the price to a specific price list. This will override any default "best price validations" that Norce normally do on the basket items. This makes it possible to override Norce's best price calculation and point to a specific price list that should be used. Some use cases: 1. The solution should use a price list (agreement) that has a higher price than the current campaign, but might give additional warranties or other prefered value to the customer. 2. The solution should set the reservation to a specific warehouse/location. Lock the item to a price list, connected to this warehouse. Read about [connected warehouses and reservation](/solution-portal/detailed-design/availability-structure#reservations), for more info. To lock the price to a price list, you must add `PriceListLocked : true` to the basket item in the [InsertBasketItem](/api-reference/services/shoppingservice/openapi/basket/insertbasketitem) or [UpdateBasketItem](/api-reference/services/shoppingservice/openapi/basket/updatebasketitem). Here is an example: ```json { "PartNo": "TestPartNo", "Quantity": 1.000, "Comment": "This is an insert of locked price list to a new row in the basket", "PriceListId": 15320, "PriceListLocked": true } ``` Then the returned basket item looks like this (shortened): ```json { "LineNo": 1, "PartNo": "TestPartNo", "PriceDisplay": 6000.00, "Price": 0.00, "PriceOriginal": 6000.00, "Quantity": 1.000, "PriceListId": 15320, "PriceStandard": 5900.00, "PriceDisplayIncVat": 7500.00, "PriceListLocked": true } ``` Note that the `PriceStandard` amount might be lower than the current `PriceDisplay` here, since this is a locked price. `PriceListLocked` might return to false if - You call an update to the shoppingservice, or - The price list is no longer active on the product ### Additional isEditable and isBuyable logic Some clients want to have more restrictions on what the basket than Norce provides, this could foe example be when a basket is buyable and not. This could be a validation on products that they should be in-stock for example. Or even more complex logic than that. ```csharp public bool Buyable(Basket basket) { if (basket.isBuyable) { //Check my custom logic as well (for example, that all products are in stock) return true; } else return false; } ``` ### Streamline basket processes Event though Norce Commerce is flexible, some client solutions could benefit from a simplified view that is tailored to their needs. Examples: - Add item with RecommendedQuantity set - Add an already existing item as +1 to quantity - Handle certain flagged products differently - Handle overrides of prices as manual prices ### Extend the basket model Many cases the client has need of extending the basket model adding properties as info types in Norce Commerce Shopping Service. A common practice is to map these additional field to an extension to your basket model, so make it easier to use. ## Promotions Baskets apply promotions automatically if the requirements are valid. This means that prices or new items can suddenly be shown in a basket depending on the effects. All applied promotions are listed in the `AppliedPromotions` list on the basket and on the basket item as well. Some promotions are applied using a code. Use `UpdateBasket` and set the `DiscountCode` property to enable these kind of promotions. If no such promotion exists or if it isn't valid, the basket will simply not show a discount code after update. See a Postman example [here](https://documenter.getpostman.com/view/2973406/2sA35MzK14#91bf4fcb-48da-4fd3-8399-4db8291f6957). ## Complex items Norce Commerce allowes for more complex items to be added to the basket. By that we mean items containing other items. Use the `ParentLineNo` to display these items in an appropriate manner in the UI. To simplify handling of these items there are some additional methods: - [InsertBasketItemWithChildren](/api-reference/services/shoppingservice/openapi/basket/insertbasketitemwithchildren), takes a list of Basketitems to insert. The first is the parent. - [UpdateBasketItemQuantityWithChildren](/api-reference/services/shoppingservice/openapi/basket/updatebasketitemquantitywithchildren), lets you change the quantity of the parent and will also calculate the quantity change on its children. Examples of items that use this functionality is products of type `ManagedStructure`, `ManagedErpPackage` and `ManagedErpPackageWithCalc` and their Unmanaged counterparts. ## Samples in Postman We have some good samples on how to work with baskets [here](https://documenter.getpostman.com/view/2973406/2sA35MzK14#d8eb437c-32b1-4dc3-a867-1bab2f923d2d). ## Suggested further reading - [Checkout process](/developer-portal/app-development/working-with-the-checkout-process)