📍 Bolt Help / Developers / API Recipes / Complex Shipping Implementation Guide

Complex Shipping Implementation Guide

This feature enables your shoppers to ship items in their cart to multiple addresses.

This implementation guide describes how to restructure the way your server expects, handles, and transmits data so you can implement the complex shipping feature.

Before You Start

Set Up Merchant Callback API

Refer to About the Merchant Callback API to build out this endpoint on your ecommerce server.

Complex Shipping Endpoints

Send the following endpoints to your CSM:

Division Features

Contact your CSM and request that they set up your merchant account for complex shipping.

A Bolt administrator must enable the following feature flags for your merchant division:

  • Multi-step Checkout
  • Pre-auth Order Creation
  • Webhooks V2
  • Separate endpoints for shipping & tax calls
  • Enable per-item shipping

A Bolt administrator must disable the following feature flag for your merchant division:

  • Enable shipping/tax updateCart endpoint

Implementation Overview

When a cart includes multiple addresses, Bolt requests shipping options for each address and tax calculations for each shipment.

You should expect multiple calls of /order_shipping and /order_tax per cart when you enable complex shipping.

The request bodies for /order_create and /webhooks_transaction also vary from the standard structure when using complex shipping.

The examples in this document illustrate portions of the requests and responses. Refer to Bolt’s API Reference documentation for full request and response bodies.

Fetch Shipping for Each Address

Bolt sends a request to the Order Shipping endpoint /order_shipping for each address.

Given the following cart:

"cart": {
   "total_amount": "6896",
   "items": [
       {
            "name": "Sunglasses",
            "quantity": 2
       }
       {
           "name": "Blue hat",
           "quantity": 1
       }
       {
            "name": "Pink purse",
            "quantity": 1
        }
    ]
}
"shipping_addresses": [
    {
        "street_address1":"42 Wallaby Way",
        "postal_code":"11209",
        "id":"address-1"
    }
    {
        "street_address1":"77 Geary Street",
        "postal_code":"91210",
        "id":"address-2"
    }
]

Request

One request to /order_shipping includes the first address:

"cart": {
   "total_amount": "6896",
   "items": [
       {
            "name": "Sunglasses",
            "quantity": 2
       }
       {
           "name": "Blue hat",
           "quantity": 1
       }
       {
            "name": "Pink purse",
            "quantity": 1
        }
    ]
}
"shipping_address": {
    "street_address1":"42 Wallaby Way",
    "postal_code":"11209",
    "id":"address-1"
}

A second request to /order_shipping includes the second address:

"cart": {
   "total_amount": "6896",
   "items": [
       {
            "name": "Sunglasses",
            "quantity": 2
       }
       {
           "name": "Blue hat",
           "quantity": 1
       }
       {
            "name": "Pink purse",
            "quantity": 1
        }
    ]
}
"shipping_address": {
    "street_address1":"77 Geary Street",
    "postal_code":"91210",
    "id":"address-2"
}

Response

The response includes all options for the requested address:

   "shipping_options":[  
      {  
         "service":"Priority",
         "cost": 770,
         "reference": "option-1"
      }
      {  
         "service":"Ground",
         "cost": 239,
         "reference": "option-2"
      }
   ]

Note: Complex shipping supports information returned in the shipping_options array. To return pickup or ship-to-store options, use shipping_option objects.

Fetch Tax for Each Shipment

Bolt sends a request to the Order Tax endpoint /order_tax for each shipment.

Given the following cart:

"cart": {
   "total_amount": "6896",
   "items": [
       {
            "name": "Sunglasses",
            "quantity": 2
       }
       {
           "name": "Blue hat",
           "quantity": 1
       }
       {
            "name": "Pink purse",
            "quantity": 1
        }
    ]
}
"shipping_addresses": [
    {
        "street_address1":"42 Wallaby Way",
        "postal_code":"11209",
        "id":"address-1"
    }
    {
        "street_address1":"77 Geary Street",
        "postal_code":"91210",
        "id":"address-2"
    }
]
"shipping_options":[  
    {  
        "service":"Priority",
        "cost": 770,
        "reference": "option-1"
    }
    {  
        "service":"Ground",
        "cost": 239,
        "reference": "option-2"
    }
]

Request

  • items only includes the items assigned to that shipment
  • shipping_address only includes the address for this shipment
  • total_amount always represents the value of all items in the cart

One request to /order_tax includes the address and each item assigned to the first delivery:

"cart": {
   "total_amount": "6896",
   "items": [
       {
            "name": "Sunglasses",
            "quantity": 2
       }
    ]
}
"shipping_option": {
    "shipping_method": "Priority",
    "cost": 770,
    "reference":"option-1"
}
"shipping_address": {
    "street_address1":"42 Wallaby Way",
    "postal_code":"11209",
    "id":"address-1"
}

A second request to /order_tax includes the address and each item assigned to the second delivery:

"cart": {
   "total_amount": "6896",
   "items": [
       {
           "name": "Blue hat",
           "quantity": 1
       }
       {
            "name": "Pink purse",
            "quantity": 1
        }
    ]
}
"shipping_option": {
    "shipping_method": "Ground",
    "cost": 239,
    "reference":"option-2"
}
"shipping_address": {
    "street_address1":"77 Geary Street",
    "postal_code":"91210",
    "id":"address-2"
}

Response

Each response contains the tax amount for the items included in that shipment.

First response:

"shipping_option": {  
    "service":"Priority",
    "cost": 770,
    "reference":"option-1"
},
"tax_result":{  
    "subtotal_amount":385
}

Second response:

"shipping_option": {  
    "service":"Ground",
    "cost": 239,
    "reference":"option-2"
},
"tax_result":{  
    "subtotal_amount":500
}

Transformation

Bolt sums up the retrieved tax amounts for each shipment to display the total tax amount in checkout. This calculation occurs on the backend.

Pre-authorize Transaction

Bolt sends a request to the Order Create endpoint /order_create for the entire cart.

Request

Each item in the request also includes a shipment_id, which corresponds with a value in shipments.id.

"cart": {
   "total_amount": "6896",
   "items": [
       {
            "name": "Sunglasses",
            "quantity": 2,
            "shipment_id":"1111"
       }
       {
           "name": "Blue hat",
           "quantity": 1,
           "shipment_id":"2222"
       }
       {
            "name": "Pink purse",
            "quantity": 1,
            "shipment_id":"2222"
        }
    ],
    "shipments":[
        {
            "id":"1111",
            "shipping_address": {
                "street_address1":"42 Wallaby Way",
                "postal_code":"11209",
                "id":"address-1"
            }
        }
        {
            "id":"2222",
            "shipping_address": {
                "street_address1":"77 Geary Street",
                "postal_code":"91210",
                "id":"address-2"
            }
        }
    ]
}

Response

  1. Parse the request and map each item to its corresponding shipment.

    Shipment ID 1111:
    - 2 Sunglasses
    
    Shipment ID 2222:
    - 1 Blue hat
    - 1 Pink purse
    
  2. Confirm the order fulfillment details and respond with success.

Webhooks

Bolt sends a request to the Transaction Webhooks endpoint /webhooks_transaction for each change in transaction status.

Request

The following webhook types relate to complex shipping:

  • pending: The payment pre-authorization was successful, and the transaction is now pending fraud review.
  • auth: If you use manual capture, the transaction passed authorization and fraud review, and you can begin the capture process.

Each item in the request also includes a shipment_id, which corresponds with a value in shipment.id.

"type":"pending",
"data": {
    "order": {
        "cart": {
        "total_amount": "6896",
        "items": [
            {
                    "name": "Sunglasses",
                    "quantity": 2,
                    "shipment_id":"1111"
            }
            {
                "name": "Blue hat",
                "quantity": 1,
                "shipment_id":"2222"
            }
            {
                    "name": "Pink purse",
                    "quantity": 1,
                    "shipment_id":"2222"
                }
            ],
            "shipments":[
                {
                    "id":"1111",
                    "shipping_address": {
                        "street_address1":"42 Wallaby Way",
                        "postal_code":"11209",
                        "id":"address-1"
                    }
                }
                {
                    "id":"2222",
                    "shipping_address": {
                        "street_address1":"77 Geary Street",
                        "postal_code":"91210",
                        "id":"address-2"
                    }
                }
            ]
        }
    }
}

Response

  1. Set up transaction webhook notifications for pending and auth, and any other webhook types you want to be notified about.

  2. Parse the request and map each item to its corresponding shipment.

    Shipment ID 1111:
    - 2 Sunglasses
    
    Shipment ID 2222:
    - 1 Blue hat
    - 1 Pink purse
    
  3. Respond with success.

📖On This Page