# Shipping and Delivery Overview Overview of the concepts related to shipping and delivery of Orders in your Project. Learn more about how to implement shipping information collection as part of a custom checkout flow in our self-paced [Implement a custom checkout](/learning-implement-checkout/custom-checkout/overview.md) module. ## Shipping versus Delivery We differentiate conceptually between the shipping addresses of the Cart and the delivery addresses of the Order. - The shipping addresses captured during checkout represent the request of the customer as to where the individual items should be shipped. - The delivery information captured for the Order represent how the Order is actually fulfilled. Therefore, the delivery information is **not automatically set** on the [Order](/search.md?urn=ctp:api:type:Order) based on which shipping addresses are set on the [Cart](/search.md?urn=ctp:api:type:Cart). To map a shipping address to delivery information, use the [Add Delivery](/api/projects/orders.md#add-delivery) update action. ### Multiple deliveries Multiple [Deliveries](/api/projects/orders.md#delivery) can be added to the same Order to represent split or partial shipments. A single Line Item or Custom Line Item quantity can be distributed across several Deliveries, and further split into multiple [Parcels](/api/projects/orders.md#parcel) within a Delivery. The API does not validate that the cumulative quantities of Line Items or Custom Line Items across all Deliveries match or stay within the originally ordered quantities. Preventing overshipment is the responsibility of the integrating system. Typical scenarios include: **Large items shipped as one Delivery but with multiple Parcels**: A single Line Item is fulfilled in one Delivery, but due to size, it is packaged into several Parcels. For example, a wardrobe that is too large to send in a single box and must be split up. **Line Items with multiple units fulfilled across multiple Deliveries**: A Line Item with quantity greater than one is shipped in stages, with each Delivery sending part of the total quantity. For example, an order of 5 T-shirts where the first Delivery ships 2 T-shirts, and a later Delivery ships the remaining 3 T-shirts. **Single large or complex items fulfilled across multiple Deliveries**: A single Line Item is shipped in stages, with each Delivery sending different components of that item. For example, custom furniture where the initial Delivery ships core components, and a subsequent Delivery ships remaining parts. ## Shipping addresses If you are using the default [ShippingMode](/search.md?urn=ctp:api:type:ShippingMode) `Single`, you must set a `shippingAddress` for the Cart before it can be converted into an Order. The address stored in the `shippingAddress` field of the [Cart](/search.md?urn=ctp:api:type:Cart) determines the following: - The Shipping Methods that are available and their shipping rates - The Tax Rate applied to each (Custom) Line Item and the shipping rate For more information on how tax is calculated using the `shippingAddress` field, see [Cart tax rate selection](/api/carts-orders-overview.md#taxes). ### Ship to a single address To ship all (Custom) Line Items of the Cart to the same address using the same fulfillment method, use a [single Shipping Method](/api/shipping-delivery-overview.md#single-shipping-method). To ship all (Custom) Line Items of the Cart to the same address, using more than one fulfillment method, use [multiple Shipping Methods](/api/shipping-delivery-overview.md#multiple-shipping-methods). ### Ship to multiple addresses To ship individual items to different addresses while using a single [Shipping Method](/api/projects/shippingMethods.md#shippingmethod), set the Cart's [ShippingMode](/search.md?urn=ctp:api:type:ShippingMode) to `Single` on [CartDraft](/search.md?urn=ctp:api:type:CartDraft). Once set, the `ShippingMode` field can not be changed. This setup uses one shipping and tax context for the Cart. Because the Cart-level `shippingAddress` determines the matching Shipping Methods, shipping rates, and tax rates for the Cart, this pattern is suitable only when the item-level addresses stay within the same country or regional context. If the items must ship to addresses in different countries or regions, use [ShippingMode](/search.md?urn=ctp:api:type:ShippingMode) `Multiple` instead. The `shippingAddress` field of the Cart is used for taxation purposes and must be set in the [CartDraft](/search.md?urn=ctp:api:type:CartDraft) or with the [Set Shipping Address](/api/projects/carts.md#set-shipping-address) update action. Any address that is bound to a Line Item or sub-quantity of a Line Item must be added to the `itemShippingAddresses` field, which contains the complete set of addresses available for use by the Cart. If a Line Item, or quantity of a Line Item is associated with an address listed in `itemShippingAddresses`, this address can not be deleted. To delete the address, you must first update the Line Item shipping details and remove the reference. Each address that you provide must have a `key` that is unique to the Cart. The `key` is required when assigning the respective shipping address to a Line Item in the [ItemShippingTarget](/search.md?urn=ctp:api:type:ItemShippingTarget) (used with the [Set LineItem ShippingDetails](/api/projects/carts.md#set-lineitem-shippingdetails) update action). #### Shipping sub-quantities to different addresses You can also ship sub-quantities of a Line Item to different addresses. For example, if you have a Cart that contains `100` paper bags that must be shipped to three point-of-sale locations, you can specify the sub-quantities of the [LineItem](/search.md?urn=ctp:api:type:LineItem) `quantity` for each address. | Shipping address | Sub-quantity | | --- | --- | | address\_1 | `10` | | address\_2 | `40` | | address\_3 | `50` | ```json title="Example Line Item with sub-quantities delivered to multiple shipping addresses" { "id": "e38a6110-fc74-4095-bde5-9898375e6904", "productId": "ed7f5333-6f5d-4d07-a44f-2a24885bae0c", "name": { "en": "Branded paper bag" }, "variant": { "id": 1, "sku": "sku_4002" }, "price": { "value": { "currencyCode": "USD", "centAmount": 4200 }, "id": "278af989-688a-4b60-a26f-bee2a2e40920" }, "quantity": 100, "priceMode": "Platform", "totalPrice": { "currencyCode": "USD", "centAmount": 630000 }, "lineItemMode": "Standard", "shippingDetails": { "targets": [ { "addressKey": "address_1", "quantity": 10 }, { "addressKey": "address_2", "quantity": 40 }, { "addressKey": "address_3", "quantity": 50 } ], "valid": true } } ``` When you set the Line Item shipping address, there is no enforcement that the sum of the shipping address quantities equals the [LineItem](/search.md?urn=ctp:api:type:LineItem) `quantity`. This allows the shipping addresses to be gathered and added to the Cart in a piecemeal way. However, to ensure data integrity, a boolean field called `valid` exists to determine whether the sum of the shipping address quantities equal the [LineItem](/search.md?urn=ctp:api:type:LineItem) `quantity`. A Cart is still considered valid even if `valid` is `false`. However, during Order creation, all `valid` flags must be `true`, otherwise the Order creation will be rejected. For a working API example, see [Multiple Shipping Addresses and Methods](/tutorials/multiple-shipping-addresses-methods.md#use-multiple-shipping-addresses). ## Shipping Methods [Shipping Methods](/api/projects/shippingMethods.md#shippingmethod) model the fulfillment option that you assign to a Cart or, in `Multiple` shipping mode, to individual Line Items. A Shipping Method combines the delivery option, tax category, predicate-based eligibility, and Zone-based shipping rates for options such as standard delivery, express delivery, or in-store collection. Shipping Methods can optionally be scoped to specific [Stores](/api/projects/stores.md) using the `stores` field. If no Stores are assigned, the Shipping Method is global and available to all Carts. If one or more Stores are assigned, the Shipping Method is Store-scoped and the following validation applies whenever it is used on a Cart: - A Cart that belongs to a Store can use Shipping Methods scoped to that Store, as well as global Shipping Methods. - A Cart that belongs to a Store cannot use Shipping Methods scoped to a different Store. If a mismatched Store-scoped Shipping Method is used, an [InvalidOperation](/search.md?urn=ctp:api:type:InvalidOperationError) error is returned. - A Cart that does not belong to a Store can only use global Shipping Methods. If a Store-scoped Shipping Method is used, an [InvalidOperation](/search.md?urn=ctp:api:type:InvalidOperationError) error is returned. When an Order is created from a [frozen Cart](/api/projects/carts.md#freeze-cart), Store scoping validation for the Shipping Method is bypassed and the Order is created even if the Shipping Method would otherwise be rejected due to Store scoping. You can define a default Shipping Method for a Project by setting the `isDefault` boolean inside an individual Shipping Method. When a Shipping Method has `isDefault` set to `true`, it appears as the first item in the array when retrieving [matching Shipping Methods](/search.md?urn=ctp:api:endpoint:/{projectKey}/shipping-methods/matching-cart:GET). This flag does not automatically apply the Shipping Method to Carts; instead, you can use it to identify which Shipping Method should be pre-selected during checkout. You can set the shipping rates and the geographical area(s) covered by a Shipping Method using [Zones](/api/projects/zones.md). ### Single Shipping Method To ship all of the items in the Cart using a single [Shipping Method](/api/projects/shippingMethods.md#shippingmethod), and therefore also the same tax rate selection criteria, set the Cart's [ShippingMode](/search.md?urn=ctp:api:type:ShippingMode) to `Single` on [CartDraft](/search.md?urn=ctp:api:type:CartDraft). Once set, the `ShippingMode` field can not be changed. When using [ShippingMode](/search.md?urn=ctp:api:type:ShippingMode) `Single`, tax is calculated and applied to the contents of the Cart based on the address in the `shippingAddress` field. ```mermaid sequenceDiagram actor Application participant Cart activate Cart Application->>Cart: Add LineItem Cart->>Cart: select lineItem.price Application->>Cart: Set shipping address loop for each LineItem Cart->>Cart: get tax rate for shippingAddress.country Cart->>Cart: set lineItem.taxRate Cart->>Cart: calculate and set lineItem.taxedPrice end Cart->>Cart: calculate and set taxedPrice Application->>Cart: Set Shipping Method Cart->>Cart: get shipping rate for shippingAddress Cart->>Cart: set shippingInfo Cart->>Cart: calculate and set taxedPrice ``` ### Multiple Shipping Methods To ship individual items of an Order using different [Shipping Methods](/api/projects/shippingMethods.md#shippingmethod), use [ShippingMode](/search.md?urn=ctp:api:type:ShippingMode) `Multiple` on [CartDraft](/search.md?urn=ctp:api:type:CartDraft). For example, a customer wants to collect some items in person and have the rest sent by express delivery. If the items ship to different countries or regions but should still use the same logical fulfillment option, use `Multiple` as a workaround. Add the same Shipping Method resource to the Cart more than once with [Add Shipping Method](/api/projects/carts.md#add-shippingmethod), then assign the corresponding `shippingKey` values to the relevant Line Items or sub-quantities. To add and assign Shipping Methods, do the following: 1. Specify any shipping addresses to be used by the Line Items in your Cart. For new Carts, you can specify addresses in the `itemShippingAddresses` field on [CartDraft](/search.md?urn=ctp:api:type:CartDraft). For existing Carts, you can use the [Add ItemShippingAddress](/api/projects/carts.md#add-itemshippingaddress) update action, which adds the addresses to the `itemShippingAddresses` field. The `itemShippingAddresses` field is the complete set of addresses available for use by the Cart. 2. Use the [Add Shipping Method](/api/projects/carts.md#add-shippingmethod) or [Add Custom Shipping Method](/api/projects/carts.md#add-custom-shippingmethod) (for externally managed Shipping Methods) update action to add Shipping Methods to a Cart. In the update action, you need to specify a `shippingAddress` for the Shipping Method. We recommend that you provide a `key` for the `shippingAddress` that matches the `key` of the corresponding address listed in `itemShippingAddresses`. The `shippingAddress` is used later to calculate tax for any associated (Custom) Line Item(s), or sub-quantities of a (Custom) Line Item. Both internal and external (outside commercetools commerce API platform) Shipping Methods can coexist in a single Cart. 3. Assign a Shipping Method to each Line Item using the [Set LineItemShippingDetails](/api/projects/carts.md#set-lineitem-shippingdetails) update action. ```mermaid sequenceDiagram actor App participant Cart activate Cart App->>Cart: Add LineItem Cart->>Cart: select lineItem.price Cart->>Cart: calculate and set totalPrice App->>Cart: Add ItemShippingAddress Cart->>Cart: append Address to itemShippingAddresses App->>Cart: Add ShippingMethod Cart->>Cart: append Shipping Method to shipping Cart->>Cart: get shipping rate for shippingAddress Cart->>Cart: set shippingInfo Cart->>Cart: calculate and set taxedPrice App->>Cart: Set LineItem ShippingDetails Cart->>Cart: update lineItem.shippingDetails Cart->>Cart: get shipping rate and tax rate for Line Item shipping address Cart->>Cart: set lineItem.perMethodTaxRate Cart->>Cart: calculate and set lineItem.taxedPricePortions Cart->>Cart: calculate and set taxedShippingPrice ``` You can also ship items (or sub-quantities of an item) to different addresses located in other states, countries, or regions using **multiple** Shipping Methods, however, the following applies: - The [LineItem's](/api/projects/carts.md#lineitem) or [CustomLineItem's](/api/projects/carts.md#lineitem) `perMethodTaxRate` field contains the individual Tax Rates applied within a single Line Item together with the Shipping Methods assigned to it. This field is equivalent to the `taxRate` field when using the default ShippingMode `Single`. - The [LineItem's](/api/projects/carts.md#lineitem) or [CustomLineItem's](/api/projects/carts.md#lineitem) `taxedPricePortions` field contains individual taxed prices of each Shipping Method. This is automatically calculated when `perMethodTaxRate` is set. For a working API example, see [Set up multiple shipping addresses and methods on a Cart](/tutorials/multiple-shipping-addresses-methods.md#use-multiple-shipping-methods). For broader modeling guidance, see the [Shipping Methods](/learning-model-your-product-catalog/shipping-methods/overview.md) self-learning module. ### Predicates Predicates allow you to define rule-based logic to determine which [Shipping Methods](/api/projects/shippingMethods.md#shippingmethod) are eligible for a Cart during checkout. To do this, add your predicate text to the `predicate` field directly on each Shipping Method. For example: - Shipping Method "Express" should only be offered for Carts with Line Items that are eligible for express shipping. - Shipping Method "Overnight" should not be offered to a certain segment of the customers. - Shipping Method "Ground" is the only method available for Carts with bulky items weighing more than 10 kg. - Shipping Method "Scandinavia" is the only method available for Carts in the [Store](/api/projects/stores.md) for Sweden. ```json title="Predicate examples" // matches a cart when at least one Line Item has the Custom Field attribute "eligible_for_express_shipping" set to TRUE lineItemExists(attributes.eligible_for_express_shipping = true) // matches a cart for all customer group except one customerGroup.id != "f6a19a23-14e3-40d0-aee2-3e612fcb1bc7" // matches a cart when at least one Line Item has the Custom Field attribute "bulky" set to TRUE and when at least one Line Item has the Custom Field attribute "weightInKilograms" set to a value greater than 10 lineItemExists(attributes.bulky = true) and lineItemExists(attributes.weightInKilograms > 10) // matches a cart with Store key "sweden-store" store.key = "sweden-store" ``` Shipping predicates take into account the entire scope of the Cart, regardless of associations to Line Items. For example, a Shipping Method with a predicate `totalPrice > "100.00 USD"` will be applicable even if only $10 worth of goods is associated with it, so long as total Cart price satisfies the predicate. Similarly, this also applies to the Shipping Method's `freeAbove` price. The [predicate language](/api/projects/predicates.md) contains a list of logical operators and functions that can be used to express the conditions of a Shipping Method rule. Each Shipping Method predicate is evaluated when a Cart is created and when a Shipping Method is checked for eligibility or assigned to that Cart, using the Cart fields referenced by the predicate. If Cart changes cause the selected Shipping Method to stop matching, the Cart must be updated before you can create the Order. If you use the [Set ShippingMethod](/api/projects/carts.md#set-shippingmethod) update action with a Shipping Method that does not match the conditions of the Cart, the call will be perceived as an invalid operation and be rejected. If the Cart is updated and its conditions no longer match the criteria of the selected Shipping Methods, the parameter `shippingMethodState` found under the Cart's [ShippingInfo](/search.md?urn=ctp:api:type:ShippingInfo) changes from `MatchesCart` to `DoesNotMatchCart`. If you attempt to create an Order from a Cart that has [ShippingMethodState](/search.md?urn=ctp:api:type:ShippingMethodState) with `DoesNotMatchCart`, the Order creation will be rejected. For business-rule design examples, see the [Predicates](/learning-model-your-product-catalog/shipping-methods/predicates.md) self-learning page. For operator and syntax reference, see [Predicates](/api/projects/predicates.md) and [Predicate operators](/api/predicates/predicate-operators.md). ## Shipping Rates A shipping rate is the price configuration inside a [Shipping Method](/api/projects/shippingMethods.md#shippingmethod) for a specific Zone and currency. Shipping rates are defined in the Shipping Method's [Zones](/api/projects/zones.md), and they determine the shipping price that applies when that Shipping Method matches the Cart. ### Fixed shipping rates A fixed shipping rate is a rate assigned to a Shipping Method that never changes, even if the content or the conditions of a Cart is modified. ### Tiered shipping rates The alternative to fixed shipping rates is tiered shipping rates. This allows you to set shipping rates that increase or decrease, based on the tiers that you define. For example, you might want the shipping rate to decrease based on the Cart value, meaning the more money the customer is spending, the cheaper the shipping becomes. You can enable tiered shipping rates by setting the optional parameter [ShippingRateInputType](/search.md?urn=ctp:api:type:ShippingRateInputType) in [Project Settings](/api/projects/project.md). The [ShippingRateInputType](/search.md?urn=ctp:api:type:ShippingRateInputType) parameter requires one of three [ShippingRatePriceTiers](/api/projects/shippingMethods.md#shippingratepricetier): - [CartValueType](/search.md?urn=ctp:api:type:CartValueType): the shipping rate maps to the sum of all Line Item totals and Custom Line Item totals (after discounts have been applied). - [CartClassificationType](/search.md?urn=ctp:api:type:CartClassificationType): the shipping rate maps to an abstract Cart categorization expressed through a string (for example, `Light`, `Medium`, `Heavy`). - [CartScoreType](/search.md?urn=ctp:api:type:CartScoreType): the shipping rate maps to an abstract Cart categorization expressed through an integer (for example, a cart score or weight range). When you create a Cart, you can set the parameter `shippingRateInput` on [CartDraft](/search.md?urn=ctp:api:type:CartDraft) which is used as look-up value to determine the shipping rate according to the defined tiers. If no value is set, or there is no tier for the value, the default shipping rate is used. An exception to this is when the [ShippingRateInputType](/search.md?urn=ctp:api:type:ShippingRateInputType) is set to [CartValueType](/search.md?urn=ctp:api:type:CartValueType). In this case, the shipping rate is determined by the sum of all Line Item totals and Custom Line Item totals (via the `totalPrice` field) after discounts have been applied. #### Define shipping tiers After you set the [ShippingRateInputType](/search.md?urn=ctp:api:type:ShippingRateInputType) parameter, specify the tiers and the shipping rate they should map to. To do this, define the array called `tiers` within the [ShippingRate](/search.md?urn=ctp:api:type:ShippingRate) object. The following examples illustrate tiered shipping rates for each input type. ##### CartValueType In this example, the shipping rate gradually decreases until it becomes free of charge when the Cart value exceeds $100. | Shipping Rate Tier | Shipping Rate | | --- | --- | | Default | $4 | | > $50 | $3 | | > $75 | $2 | | > $100 | $0 | ##### CartClassificationType In this example, if you don't provide a classification for a given Cart during checkout, the shipping rate defaults to $10. If you classify the Cart as Medium, the shipping rate is $25. | Shipping Rate Tier | Shipping Rate | | --- | --- | | Default | $10 | | Medium | $25 | | Heavy | $50 | ##### CartScoreType In this example, the score represents the total weight of the Cart expressed in grams. A Cart with a combined weight of 50 grams or less, will have a shipping rate of $1.75. As the weight increases, the shipping rate increases. | Shipping Rate Tier | Shipping Rate | | --- | --- | | Default | $1.75 | | > 50 | $2.50 | | > 100 | $4.75 | | > 500 | $7.25 | | > 1000 | $10.50 | In the following example, we'll use [CartScoreType](/search.md?urn=ctp:api:type:CartScoreType) again, but we'll express the shipping rate as a linear [PriceFunction](/search.md?urn=ctp:api:type:PriceFunction). When a score is 35 or less, the shipping rate increases in set intervals. For scores higher than 35, the shipping rate is calculated based on the defined function. For example, a cart score of 40 results in a shipping rate of $10. | Shipping Rate Tier | Shipping Rate | | --- | ---: | | Default | $2 | | > 5 | $3 | | > 15 | $6 | | > 25 | $8 | | > 35 | x - 30 | ### Free shipping The following free-shipping mechanisms are supported: **Free above:** Set a `freeAbove` value on [ShippingRateDraft](/search.md?urn=ctp:api:type:ShippingRateDraft). This threshold belongs to a fixed shipping rate on a specific Shipping Method. The **Free above** option is only available with [fixed shipping rates](/api/shipping-delivery-overview.md#fixed-shipping-rates). Free shipping is applied if the `totalPrice` of the Cart (minus any previously added shipping costs) equals or exceeds the `freeAbove` price. - If the (Custom) Line Items' prices do not include taxes, the `totalPrice` value is calculated from the net total price of the (Custom) Line Items. - If the (Custom) Line Items' prices include taxes, the `totalPrice` is calculated from the gross total price of the (Custom) Line Items. **Cart discounts:** This option applies the same free shipping threshold amount across all Shipping Methods by default. However, it is possible to restrict a Cart Discount to only certain Shipping Methods using Cart Predicates. To use this method, set the `target` property of the [CartDiscountDraft](/search.md?urn=ctp:api:type:CartDiscountDraft) to [CartDiscountShippingCostTarget](/search.md?urn=ctp:api:type:CartDiscountShippingCostTarget). We strongly recommend that you choose **only one of these methods** and not use both at the same time. Learn more about free-shipping strategy and discount trade-offs in our self-paced [Apply discounts to shipping](/learning-price-and-discount-your-products/shipping-discounts/overview.md) module. ### Shipping rate calculation The shipping rate is calculated when at least one of the following occurs: - The `shippingRateInput` field on the Cart is updated. - The `shippingMethod` is updated on [ShippingInfo](/search.md?urn=ctp:api:type:ShippingInfo). - The [ShippingRateInputType](/search.md?urn=ctp:api:type:ShippingRateInputType) is [CartValueType](/search.md?urn=ctp:api:type:CartValueType) and the total price of the Cart changes. - The `freeAbove` [free shipping](/api/shipping-delivery-overview.md#free-shipping) threshold value exists and the total price of the Cart changes. ### Tax calculation The [TaxMode](/search.md?urn=ctp:api:type:TaxMode) of the Cart determines how tax is applied. #### Platform tax mode When only one Shipping Method is used on the Cart, the address specified in the Cart's `shippingAddress` field is used for determining the eligible Shipping Methods and their shipping rates, as well as the tax rates that are applied to (Custom) Line Items and shipping rate. When a Cart contains multiple Shipping Methods, its `taxedShippingPrice` field represents the sum of taxed prices across all Shipping Methods. Individual Shipping Method prices are contained within their respective [ShippingInfo](/search.md?urn=ctp:api:type:ShippingInfo) objects under `shipping`. #### External tax mode [TaxModes](/api/projects/carts.md#taxmode) `External` and `ExternalAmount` require the tax rate/amount to be manually set on each (Custom) Line Item and Shipping Method. This requirement also applies to Carts with [ShippingMode](/search.md?urn=ctp:api:type:ShippingMode) `Multiple`, with the added constraint that the rates/amounts must be present for each Shipping Method associated with a given (Custom) Line Item. Update actions [SetLineItemTaxRate](/api/projects/carts.md#set-lineitem-taxrate), [SetLineItemTaxAmount](/api/projects/carts.md#set-lineitem-taxamount), [SetCustomLineItemTaxRate](/api/projects/carts.md#set-customlineitem-taxrate), and [SetCustomLineItemTaxAmount](/api/projects/carts.md#set-customlineitem-taxamount) contain a `shippingKey` parameter that you can use to define which method/address combination the rate is referring. ## Related pages - [Area overview page with navigation](/api.md) - [Next page: Shipping Methods](/api/projects/shippingMethods.md) - [Search documentation and API specs](/search.md)