Using Multiple Shipping Addresses for One Cart

This tutorial covers how to provide multiple shipping addresses for one cart. It furthermore explains how multiple shipping addresses relate to the cart's shipping rate and tax rates as well as the deliveries of the order.

Line Item Shipping Address

When multiple shipping addresses are needed for a cart, you do so by associating a line item with one or more addresses. All addresses are to be captured in the cart property called itemShippingAddresses. When creating an address, you have to provide a key which is unique in this cart. The key will become the reference when you associate a line item with a shipping address. The association is achieved with the line item action called setLineItemShippingDetails. Be aware, that should a line item reference an address under itemShippingAddresses, this address cannot be deleted. In this case, the line item shipping details have to first be updated to have the reference removed. Only when this has occurred will the shipping address deletion be successful.

Example of a line item shipping address:

{
"key": "address1"
"company": "commercetools GmbH",
"streetName": "Sonnenallee",
"streetNumber": "223",
"city": "Berlin",
"postalCode": "12059",
"country": "DE"
}

It is possible to tie multiple shipping addresses to one line item. If for example a cart contains 1000 customized paper bags and they have to be shipped across 10 point-of-sale locations, each receiving 100 paper bags, this is achieved by specifying the sub-quantities of the line item quantity for the different addresses.

Example of a line item with multiple shipping addresses:

{
"id": "e38a6110-fc74-4095-bde5-9898375e6904",
"productId": "ed7f5333-6f5d-4d07-a44f-2a24885bae0c",
"name": {
"en": "Test Product 4002"
},
"variant": {
"id": 1,
"sku": "sku_4002"
},
"price": {
"value": {
"currencyCode": "USD",
"centAmount": 4200
},
"id": "278af989-688a-4b60-a26f-bee2a2e40920"
},
"quantity": 150,
"priceMode": "Platform",
"totalPrice": {
"currencyCode": "USD",
"centAmount": 630000
},
"lineItemMode": "Standard",
"shippingDetails": {
"targets": [
{
"addressKey": "address1",
"quantity": 25
},
{
"addressKey": "address2",
"quantity": 50
},
{
"addressKey": "address3",
"quantity": 75
}
],
"valid": true
}
}

When setting the line item shipping address, there is no enforcement that the sum of the shipping address quantities equal the line item quantity. This allows the shipping addresses to be gathered and added to the cart in a piecemeal way. However, as a help to ensure data integrity, a line item boolean called valid exists to determine whether the sum of the shipping address quantities add up to be equal to the line item quantity. A cart is still considered valid even though valid is false. However, when the cart is prompted for order creation, all valid flags has to be true. Otherwise, the order creation will be rejected.

Example of a line item with multiple shipping addresses where valid is false:

{
"id": "e38a6110-fc74-4095-bde5-9898375e6904",
"productId": "ed7f5333-6f5d-4d07-a44f-2a24885bae0c",
"quantity": 150,
"shippingDetails": {
"targets": [
{
"addressKey": "address1",
"quantity": 20
},
{
"addressKey": "address2",
"quantity": 50
},
{
"addressKey": "address3",
"quantity": 75
}
],
"valid": false
}
}

Shipping Rate and Tax Rates

It is important to be aware that the cart still only uses one shipping address for determining the eligible shipping methods and their shipping rates as well as the tax rates that are applied to line items. The address for this is the one found in the cart's shippingAddress property. When line item level shipping addresses are needed, the address found under shippingAddress must also be part of itemShippingAddresses. Thus:

  • shippingAddress is the address that controls everything in relation to the cart's shipping info property as well the tax rate for a line item
  • itemShippingAddresses is the complete set of addresses that line items can be associated with

Shipping versus Delivery

A natural connection between the line item shipping addresses and the deliveries of the order exists. However, 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 on where the individual items should be shipped. The delivery data captured for the order is how the order was actually fulfilled. Thus, the delivery information is not automatically set on the order based on which shipping addresses are set on the cart. You can choose to keep these one to one, but this has to be posted actively by you to the order.

Adding ItemShippingAddresses

Imagine you have the following cart.

{
"id": "01a64001-38c1-4afb-aa08-fc3a41324196",
"version": 1,
"lineItems": [
{
"id": "07b2bdd6-119c-4836-8036-132dc9bd18f1",
"quantity": 100,
"shippingDetails": null
}
],
"itemShippingAddresses": []
}

To specify the various shipping addresses the line items should be sent to, use the update action AddItemShippingAddress per address you want to add in a CartUpdateCommand.

{
"actions": [
{
"action": "addItemShippingAddress",
"address": {
"company": "commercetools Inc",
"streetName": "Blackwell St",
"streetNumber": "318",
"city": "Durham",
"postalCode": "27701",
"state": "NC",
"country": "US",
"key": "DURHAM"
}
},
{
"action": "addItemShippingAddress",
"address": {
"company": "commercetools GmbH",
"streetName": "Adams-Lehmann-Straße",
"streetNumber": "44",
"city": "Munich",
"postalCode": "80797",
"country": "DE",
"key": "MUNICH"
}
},
{
"action": "addItemShippingAddress",
"address": {
"company": "commercetools GmbH",
"streetName": "Sonnenallee",
"streetNumber": "223",
"city": "Berlin",
"postalCode": "12059",
"country": "DE",
"key": "BERLIN"
}
}
],
"version": 1
}

The resulting cart will have the itemShippingAddresses array filled with the addresses.

{
"id": "01a64001-38c1-4afb-aa08-fc3a41324196",
"version": 4,
"lineItems": [
{
"id": "07b2bdd6-119c-4836-8036-132dc9bd18f1",
"quantity": 100,
"shippingDetails": null
}
],
"itemShippingAddresses": [
{
"streetName": "Blackwell St",
"streetNumber": "318",
"postalCode": "27701",
"city": "Durham",
"state": "NC",
"country": "US",
"company": "commercetools Inc",
"key": "DURHAM"
},
{
"streetName": "Adams-Lehmann-Straße",
"streetNumber": "44",
"postalCode": "80797",
"city": "Munich",
"country": "DE",
"company": "commercetools GmbH",
"key": "MUNICH"
},
{
"streetName": "Sonnenallee",
"streetNumber": "223",
"postalCode": "12059",
"city": "Berlin",
"country": "DE",
"company": "commercetools GmbH",
"key": "BERLIN"
}
]
}

Setting the shipping address quantity when the line item is already in the cart

Imagine a cart with a line item and itemShippingAddresses as seen in the previous section.

To distribute the quantity of the line item to different locations use SetLineItemShippingDetails.

{
"actions": [
{
"action": "setLineItemShippingDetails",
"lineItemId": "07b2bdd6-119c-4836-8036-132dc9bd18f1",
"shippingDetails": {
"targets": [
{
"addressKey": "DURHAM",
"quantity": 25
},
{
"addressKey": "MUNICH",
"quantity": 25
},
{
"addressKey": "BERLIN",
"quantity": 50
}
]
}
}
],
"version": 4
}

The resulting cart will contain the request to have the one line item split into different destinations.

{
"id": "01a64001-38c1-4afb-aa08-fc3a41324196",
"version": 5,
"lineItems": [
{
"id": "07b2bdd6-119c-4836-8036-132dc9bd18f1",
"quantity": 100,
"shippingDetails": {
"targets": [
{
"addressKey": "BERLIN",
"quantity": 50
},
{
"addressKey": "DURHAM",
"quantity": 25
},
{
"addressKey": "MUNICH",
"quantity": 25
}
],
"valid": true
}
}
],
"itemShippingAddresses": [
{
"streetName": "Blackwell St",
"streetNumber": "318",
"postalCode": "27701",
"city": "Durham",
"state": "NC",
"country": "US",
"company": "commercetools Inc",
"key": "DURHAM"
},
{
"streetName": "Adams-Lehmann-Straße",
"streetNumber": "44",
"postalCode": "80797",
"city": "Munich",
"country": "DE",
"company": "commercetools GmbH",
"key": "MUNICH"
},
{
"streetName": "Sonnenallee",
"streetNumber": "223",
"postalCode": "12059",
"city": "Berlin",
"country": "DE",
"company": "commercetools GmbH",
"key": "BERLIN"
}
]
}

Setting the shipping address quantity when managing a line item

Add items

To minimize the number of cart updates, it is also possible to set the line item shipping addresses alongside the line item update actions AddLineItem and RemoveLineItem.

Imagine you have a cart with itemShippingAddresses set:

{
"id": "01a64001-38c1-4afb-aa08-fc3a41324196",
"version": 7,
"lineItems": [],
"itemShippingAddresses": [
{
"streetName": "Blackwell St",
"streetNumber": "318",
"postalCode": "27701",
"city": "Durham",
"state": "NC",
"country": "US",
"company": "commercetools Inc",
"key": "DURHAM"
},
{
"streetName": "Adams-Lehmann-Straße",
"streetNumber": "44",
"postalCode": "80797",
"city": "Munich",
"country": "DE",
"company": "commercetools GmbH",
"key": "MUNICH"
},
{
"streetName": "Sonnenallee",
"streetNumber": "223",
"postalCode": "12059",
"city": "Berlin",
"country": "DE",
"company": "commercetools GmbH",
"key": "BERLIN"
}
]
}

Then you can use the update action AddLineItem to set the line item quantity and shipping details in one take:

{
"actions": [
{
"action": "addLineItem",
"quantity": 100,
"productId": "e9d65225-3587-4d1a-b58d-565dd5878988",
"shippingDetails": {
"targets": [
{
"addressKey": "BERLIN",
"quantity": 50
},
{
"addressKey": "DURHAM",
"quantity": 25
},
{
"addressKey": "MUNICH",
"quantity": 25
}
]
}
}
],
"version": 7
}

The resulting cart will have a new line item with the shipping details set:

{
"id": "01a64001-38c1-4afb-aa08-fc3a41324196",
"version": 9,
"lineItems": [
{
"id": "c83a9d43-54e7-43d8-8804-7f4ae769fa80",
"quantity": 100,
"shippingDetails": {
"targets": [
{
"addressKey": "BERLIN",
"quantity": 50
},
{
"addressKey": "DURHAM",
"quantity": 25
},
{
"addressKey": "MUNICH",
"quantity": 25
}
],
"valid": true
}
}
],
"itemShippingAddresses": [
{
"streetName": "Blackwell St",
"streetNumber": "318",
"postalCode": "27701",
"city": "Durham",
"state": "NC",
"country": "US",
"company": "commercetools Inc",
"key": "DURHAM"
},
{
"streetName": "Adams-Lehmann-Straße",
"streetNumber": "44",
"postalCode": "80797",
"city": "Munich",
"country": "DE",
"company": "commercetools GmbH",
"key": "MUNICH"
},
{
"streetName": "Sonnenallee",
"streetNumber": "223",
"postalCode": "12059",
"city": "Berlin",
"country": "DE",
"company": "commercetools GmbH",
"key": "BERLIN"
}
]
}

Remove items

The update action RemoveLineItem can also be used to reduce the quantities of the line item and the shipping details. Be aware that the field to declare how much sub-quantities need to be removed is called shippingDetailsToRemove and not shippingDetails.

{
"actions": [
{
"action": "removeLineItem",
"quantity": 20,
"lineItemId": "c83a9d43-54e7-43d8-8804-7f4ae769fa80",
"shippingDetailsToRemove": {
"targets": [
{
"addressKey": "DURHAM",
"quantity": 15
},
{
"addressKey": "MUNICH",
"quantity": 5
}
]
}
}
],
"version": 9
}

The resulting cart:

{
"id": "01a64001-38c1-4afb-aa08-fc3a41324196",
"version": 11,
"lineItems": [
{
"id": "c83a9d43-54e7-43d8-8804-7f4ae769fa80",
"quantity": 80,
"shippingDetails": {
"targets": [
{
"addressKey": "BERLIN",
"quantity": 50
},
{
"addressKey": "DURHAM",
"quantity": 10
},
{
"addressKey": "MUNICH",
"quantity": 20
}
],
"valid": true
}
}
],
"itemShippingAddresses": [
{
"streetName": "Blackwell St",
"streetNumber": "318",
"postalCode": "27701",
"city": "Durham",
"state": "NC",
"country": "US",
"company": "commercetools Inc",
"key": "DURHAM"
},
{
"streetName": "Adams-Lehmann-Straße",
"streetNumber": "44",
"postalCode": "80797",
"city": "Munich",
"country": "DE",
"company": "commercetools GmbH",
"key": "MUNICH"
},
{
"streetName": "Sonnenallee",
"streetNumber": "223",
"postalCode": "12059",
"city": "Berlin",
"country": "DE",
"company": "commercetools GmbH",
"key": "BERLIN"
}
]
}

Change quantity

The update action ChangeLineitemQuantity does not support changing the shipping details because an empty value could either be interpreted as an instruction to have them removed or to let them be untouched. A combination of ChangeLineitemQuantity and SetLineItemShippingDetails is necessary to update the quantities with absolute values.

{
"actions": [
{
"action": "changeLineItemQuantity",
"quantity": 50,
"lineItemId": "c83a9d43-54e7-43d8-8804-7f4ae769fa80"
},
{
"action": "setLineItemShippingDetails",
"lineItemId": "c83a9d43-54e7-43d8-8804-7f4ae769fa80",
"shippingDetails": {
"targets": [
{
"addressKey": "BERLIN",
"quantity": 25
},
{
"addressKey": "DURHAM",
"quantity": 10
},
{
"addressKey": "MUNICH",
"quantity": 15
}
]
}
}
],
"version": 11
}
{
"id": "01a64001-38c1-4afb-aa08-fc3a41324196",
"version": 14,
"lineItems": [
{
"id": "c83a9d43-54e7-43d8-8804-7f4ae769fa80",
"quantity": 50,
"shippingDetails": {
"targets": [
{
"addressKey": "BERLIN",
"quantity": 25
},
{
"addressKey": "DURHAM",
"quantity": 10
},
{
"addressKey": "MUNICH",
"quantity": 15
}
],
"valid": true
}
}
],
"itemShippingAddresses": [
{
"streetName": "Blackwell St",
"streetNumber": "318",
"postalCode": "27701",
"city": "Durham",
"state": "NC",
"country": "US",
"company": "commercetools Inc",
"key": "DURHAM"
},
{
"streetName": "Adams-Lehmann-Straße",
"streetNumber": "44",
"postalCode": "80797",
"city": "Munich",
"country": "DE",
"company": "commercetools GmbH",
"key": "MUNICH"
},
{
"streetName": "Sonnenallee",
"streetNumber": "223",
"postalCode": "12059",
"city": "Berlin",
"country": "DE",
"company": "commercetools GmbH",
"key": "BERLIN"
}
]
}