# Multi-piece shipment Shipments with multiple parcels sent to the same destination can be grouped together in a multi-piece shipment to save money. Multi-piece parcels in a single shipment may receive timeouts at certain thresholds depending on each carrier. * Using UPS, you can request rates for up to 50 parcels in a single shipment. You can purchase labels for up to 40 parcels in a [single shipment](#create-a-multi-piece-shipment). Additionally, you can purchase labels for up to 200 parcels in a single shipment using an [extended multi-piece shipment](#create-an-extended-multi-piece-shipment). * Using FedEx, sending more than 12 parcels within one shipment may result in a timeout. * USPS does not support multi-piece parcels in a single shipment at this time. ### Create a multi-piece shipment To create a multi-piece shipment, add a list of Parcel objects to the `parcels` field in a Shipment. Generating rates and creating transactions works the exact same way as with normal shipments. The limit on the number of parcels depends on each carrier's restrictions. Note For more than 40 labels in a single shipment, create an [extended multi-piece shipment](#create-an-extended-multi-piece-shipment). The Shipment request content should look like: **Request:** ```shell cURL curl https://api.goshippo.com/shipments/\ -H "Authorization: ShippoToken "\ -H "Content-Type: application/json"\ -d '{ "address_from": { "name": "Mr. Hippo", "street1": "215 Clayton St.", "city": "San Francisco", "state": "CA", "zip": "94117", "country": "US", "phone": "+1 555 341 9393", "email": "support@shippo.com" }, "address_to": { "name": "Mrs. Hippo", "street1": "965 Mission St.", "city": "San Francisco", "state": "CA", "zip": "94105", "country": "US", "phone": "+1 555 341 9393", "email": "support@shippo.com" }, "parcels": [ { "length": "5", "width": "5", "height": "5", "distance_unit": "in", "weight": "2", "mass_unit": "lb" }, { "length": "10", "width": "10", "height": "10", "distance_unit": "in", "weight": "2", "mass_unit": "lb" } ], "async": false }' ``` ```Python Python import shippo from shippo.models import components shippo_sdk = shippo.Shippo(api_key_header="") address_from = components.AddressCreateRequest( name="Shawn Ippotle", street1="215 Clayton St.", city="San Francisco", state="CA", zip="94117", country="US", phone="+1 555 341 9393", email="shippotle@shippo.com" ) address_to = components.AddressCreateRequest( name="Mr Hippo", street1="Broadway 1", city="New York", state="NY", zip="10007", country="US", phone="+1 555 341 9393", email="mrhippo@shippo.com", ) parcel_1 = components.ParcelCreateRequest( length="5", width="5", height="5", distance_unit=components.DistanceUnitEnum.IN, weight="2", mass_unit=components.WeightUnitEnum.LB ) parcel_2 = components.ParcelCreateRequest( length="10", width="10", height="10", distance_unit=components.DistanceUnitEnum.IN, weight="2", mass_unit=components.WeightUnitEnum.LB ) shipment = shippo_sdk.shipments.create( components.ShipmentCreateRequest( address_from=address_from, address_to=address_to, parcels=[parcel_1, parcel_2] ) ) ``` ```PHP PHP require_once('lib/Shippo.php'); Shippo::setApiKey(""); $fromAddress = array( 'name' => 'Shawn Ippotle', 'street1' => '215 Clayton St.', 'city' => 'San Francisco', 'state' => 'CA', 'zip' => '94117', 'country' => 'US', 'phone' => '+1 555 341 9393', 'email' => 'shippotle@shippo.com' ); $toAddress = array( 'name' => 'Mr Hippo"', 'street1' => 'Broadway 1', 'city' => 'New York', 'state' => 'NY', 'zip' => '10007', 'country' => 'US', 'phone' => '+1 555 341 9393', 'email' => 'mrhippo@shippo.com' ); $parcel_1 = array( 'length'=> '5', 'width'=> '5', 'height'=> '5', 'distance_unit'=> 'in', 'weight'=> '2', 'mass_unit'=> 'lb', ); $parcel_2 = array( 'length'=> '10', 'width'=> '10', 'height'=> '10', 'distance_unit'=> 'in', 'weight'=> '2', 'mass_unit'=> 'lb', ); $shipment = Shippo_Shipment::create( array( "address_from" => $fromAddress, "address_to" => $toAddress, "parcels" => array($parcel_1, $parcel_2), "async" => false ) ); ``` ```typescript TypeScript const shippo = new Shippo({apiKeyHeader: ''}); const addressFrom: AddressCreateRequest = { name: "Shawn Ippotle", street1: "215 Clayton St.", city: "San Francisco", state: "CA", zip: "94117", country: "US", phone: "+1 555 341 9393", email: "shippotle@shippo.com" }; const addressTo: AddressCreateRequest = { name: "Mr Hippo", street1: "Broadway 1", city: "New York", state: "NY", zip: "10007", country: "US", phone: "+1 555 341 9393", email: "mrhippo@shippo.com" }; const parcel1: ParcelCreateRequest = { length: "5", width: "5", height: "5", distanceUnit: DistanceUnitEnum.In, weight: "2", massUnit: WeightUnitEnum.Lb }; const parcel2: ParcelCreateRequest = { length: "10", width: "10", height: "10", distanceUnit: DistanceUnitEnum.In, weight: "2", massUnit: WeightUnitEnum.Lb }; const shipment = await shippo.shipments.create({ addressFrom: addressFrom, addressTo: addressTo, parcels: [parcel1, parcel2], async: false }); ``` ```Java Java Shippo.setApiKey(''); // To Address HashMap addressToMap = new HashMap(); addressToMap.put("name", "Mr Hippo"); addressToMap.put("company", "Shippo"); addressToMap.put("street1", "215 Clayton St."); addressToMap.put("city", "San Francisco"); addressToMap.put("state", "CA"); addressToMap.put("zip", "94117"); addressToMap.put("country", "US"); addressToMap.put("phone", "+1 555 341 9393"); addressToMap.put("email", "mrhippo@goshipppo.com"); // From Address HashMap addressFromMap = new HashMap(); addressFromMap.put("name", "Ms Hippo"); addressFromMap.put("company", "San Diego Zoo"); addressFromMap.put("street1", "2920 Zoo Drive"); addressFromMap.put("city", "San Diego"); addressFromMap.put("state", "CA"); addressFromMap.put("zip", "92101"); addressFromMap.put("country", "US"); addressFromMap.put("email", "mshippo@goshipppo.com"); addressFromMap.put("phone", "+1 619 231 1515"); addressFromMap.put("metadata", "Customer ID 123456"); List parcelList = new List(); // Parcel One HashMap parcelMapOne = new HashMap(); parcelMapOne.put("length", "5"); parcelMapOne.put("width", "5"); parcelMapOne.put("height", "5"); parcelMapOne.put("distance_unit", "in"); parcelMapOne.put("weight", "2"); parcelMapOne.put("mass_unit", "lb"); // Parcel Two HashMap parcelMapTwo = new HashMap(); parcelMapTwo.put("length", "1"); parcelMapTwo.put("width", "1"); parcelMapTwo.put("height", "1"); parcelMapTwo.put("distance_unit", "in"); parcelMapTwo.put("weight", "2"); parcelMapTwo.put("mass_unit", "lb"); parcelList.add(parcelMapOne); parcelList.add(parcelMapTwo); // Shipment HashMap shipmentMap = new HashMap(); shipmentMap.put("address_to", addressToMap); shipmentMap.put("address_from", addressFromMap); shipmentMap.put("parcels", parcelList); shipmentMap.put("async", false); ``` ```cs C# using Shippo; using Shippo.Models.Components; ShippoSDK sdk = new ShippoSDK(apiKeyHeader: ""); AddressFrom addressFrom = AddressFrom.CreateAddressCreateRequest( new AddressCreateRequest() { Name = "Shawn Ippotle", Street1 = "215 Clayton St.", City = "San Francisco", State = "CA", Zip = "94117", Country = "US", Phone = "+1 555 341 9393", Email = "shippotle@shippo.com", } ); AddressTo addressTo = AddressTo.CreateAddressCreateRequest( new AddressCreateRequest() { Name = "Mr Hippo", Street1 = "Broadway 1", City = "New York", State = "NY", Zip = "10007", Country = "US", Phone = "+1 555 341 9393", Email = "mrhippo@shippo.com", } ); Shippo.Models.Components.Parcels parcel1 = Shippo.Models.Components.Parcels.CreateParcelCreateRequest( new ParcelCreateRequest() { Length = "5", Width = "5", Height = "5", DistanceUnit = DistanceUnitEnum.In, Weight = "2", MassUnit = WeightUnitEnum.Lb, } ); Shippo.Models.Components.Parcels parcel2 = Shippo.Models.Components.Parcels.CreateParcelCreateRequest( new ParcelCreateRequest() { Length = "10", Width = "10", Height = "10", DistanceUnit = DistanceUnitEnum.In, Weight = "2", MassUnit = WeightUnitEnum.Lb, } ); Shipment shipment = await sdk.Shipments.CreateAsync( shipmentCreateRequest: new ShipmentCreateRequest() { AddressFrom = addressFrom, AddressTo = addressTo, Parcels = new List() { parcel1, parcel2 }, } ); ``` As usual, the Shipment request will return a list of Rates for you to select from. The Rate `amount` refers to the cost of the entire Shipment with multiple parcel, not per parcel. **Response:** ```json { "status": "SUCCESS", "object_created": "2013-12-01T06:24:20.121Z", "object_updated": "2013-12-01T06:24:20.121Z", "object_id": "5e40ead7cffe4cc1ad45108696162e42", "object_owner": "shippotle@shippo.com", "address_from": { "object_id": "0943ae4e373e4120a99c337e496dcce8", "validation_results": {}, "is_complete": true, "company": "", "street_no": "", "name": "Mr. Hippo", "street1": "215 Clayton St.", "street2": "", "city": "San Francisco", "state": "CA", "zip": "94117", "country": "US", "phone": "+15553419393", "email": "support@shippo.com", "is_residential": null }, "address_to": { "object_id": "4c7185d353764d0985a6a7825aed8ffb", "validation_results": {}, "is_complete": true, "name":"Mrs. Hippo", "street1":"965 Mission St.", "city":"San Francisco", "state":"CA", "zip":"94105", "country":"US", "phone":"+1 555 341 9393", "email":"support@shippo.com", "is_residential": false }, "address_return": { "object_id": "0943ae4e373e4120a99c337e496dcce8", "validation_results": {}, "is_complete": true, "company": "", "street_no": "", "name": "Mr. Hippo", "street1": "215 Clayton St.", "street2": "", "city": "San Francisco", "state": "CA", "zip": "94117", "country": "US", "phone": "+15553419393", "email": "support@shippo.com", "is_residential": null }, "parcels": [ { "object_id": "ec952343dd4843c39b42aca620471fd5", "object_created": "2013-12-01T06:24:21.121Z", "object_updated": "2013-12-01T06:24:21.121Z", "object_owner": "shippotle@shippo.com", "template": null, "length":"5", "width":"5", "height":"5", "distance_unit":"in", "weight":"2", "mass_unit":"lb", "value_amount": null, "value_currency": null, "metadata": "", "line_items": [], "test": true }, { "object_id": "dbe0260bb2674c709fa45667cf353f27", "object_created": "2013-12-01T06:24:21.121Z", "object_updated": "2013-12-01T06:24:21.121Z", "object_owner": "shippotle@shippo.com", "template": null, "length":"5", "width":"5", "height":"5", "distance_unit":"in", "weight":"2", "mass_unit":"lb", "value_amount": null, "value_currency": null, "metadata": "", "line_items": [], "test": true } ], "shipment_date": "2013-12-03T12:00:00.000Z", "extra": { "insurance": { "amount": "", "currency": "" }, "reference_1": "", "reference_2": "" }, "customs_declaration": "", "rates": [ { "object_created": "2013-12-01T06:24:21.121Z", "object_id": "545ab0a1a6ea4c9f9adb2512a57d6d8b", "object_owner": "shippotle@shippo.com", "shipment": "5e40ead7cffe4cc1ad45108696162e42", "attributes": [], "amount": "65.80", "currency": "USD", "amount_local": "65.80", "currency_local": "USD", "provider": "USPS", "provider_image_75": "https://cdn2.goshippo.com/providers/75/USPS.png", "provider_image_200": "https://cdn2.goshippo.com/providers/200/USPS.png", "servicelevel": { "name": "Ground", "token": "fedex_ground", "terms": "" }, "days": 5, "arrives_by": null, "duration_terms": null, "messages": [], "carrier_account": "078870331023437cb917f5187429b093", "test": false }, ... ], "carrier_accounts": [], "metadata": "Customer ID 123456", "messages": [] } ``` ### Create an extended multi-piece shipment UPS supports up to 200 parcels in a single shipment. * For 40 parcels or less, in a single shipment, you can choose to [create a multi-piece shipment](#create-a-multi-piece-shipment). * For more than 40, you must create an extended multi-piece shipment. Extended multi-piece shipments require an [Instalabel](/docs/guides_general/single_call) where you purchase a label without generating a rate. note Currently, Instalabel is not available for [Shippo FedEx and UPS accounts](/docs/carriers/carrieraccounts#carrier-accounts). If you want use either FedEx or UPS for Instalabel purchases, you must use [your own carrier account](/docs/carriers/carrieraccounts#carrier-accounts). In addition to your shipment details, the following are required to create an Instalabel for a multi-piece shipment. 1. Your chosen [carrier account ID](/docs/shipments/rateshoppingwithcarriers#capture-carrier-object-id). 2. Your chosen [service level token](/shippoapi/public-api/service-levels). 3. Set `async` to `true`. The following examples show an [Instalabel call](/shippoapi/public-api/transactions/createtransaction) for a multi-piece shipment. ```shell curl https://api.goshippo.com/transactions/ \ -H "Authorization: ShippoToken " \ -H "Content-Type: application/json" \ -d '{ "shipment": { "address_from": { "name": "Mr. Hippo", "street1": "215 Clayton St.", "city": "San Francisco", "state": "CA", "zip": "94117", "country": "US", "phone": "+1 555 341 9393", "email": "support@shippo.com" }, "address_to": { "name": "Mrs. Hippo", "street1": "965 Mission St.", "city": "San Francisco", "state": "CA", "zip": "94105", "country": "US", "phone": "+1 555 341 9393", "email": "support@shippo.com" }, "parcels": [ { "length": "5", "width": "5", "height": "5", "distance_unit": "in", "weight": "2", "mass_unit": "lb" }, { "length": "10", "width": "10", "height": "10", "distance_unit": "in", "weight": "2", "mass_unit": "lb" }, { "length": "5", "width": "10", "height": "2", "distance_unit": "in", "weight": "2", "mass_unit": "lb" } ], }, "carrier_account": "b741b99f95e841639b54272834bc478c", "servicelevel_token": "ups_ground", "async":true }' ``` ## How to retrieve labels for each parcel You can purchase a multi-piece shipping rate by POSTing the Rate `object_id` to the Transaction endpoint as usual. A separate transaction will be created for each parcel. ```shell cURL curl https://api.goshippo.com/transactions\ -H "Authorization: ShippoToken "\ -d rate="cf6fea899f1848b494d9568e8266e076" -d label_file_type="PDF" -d async=false ``` ```Python Python # Get the first rate in the rates results. # Customize this based on your business logic. rate = shipment.rates[0] # Purchase the desired rate. transaction = shippo_sdk.transactions.create( components.TransactionCreateRequest( rate=rate.object_id, label_file_type=components.LabelFileTypeEnum.PDF ) ) # Retrieve label url and tracking number or error message if transaction.status == "SUCCESS": print(transaction.label_url) print(transaction.tracking_number) else: print(transaction.messages) ``` ```PHP PHP // Get the first rate in the rates results. // Customize this based on your business logic. $rate = $shipment["rates"][0]; // Purchase the desired rate. $transaction = Shippo_Transaction::create( array( 'rate' => $rate["object_id"], 'label_file_type' => "PDF", 'async' => false ) ); // Retrieve label url and tracking number or error message if ($transaction["status"] == "SUCCESS"){ echo( $transaction["label_url"] ); echo("\n"); echo( $transaction["tracking_number"] ); }else { echo( $transaction["messages"] ); } ``` ```typescript TypeScript // Get the first rate in the rates results. // Customize this based on your business logic. const rate = shipment.rates[0]; // Purchase the desired rate. const transaction = await shippo.transactions.create({ rate: rate?.objectId, labelFileType: LabelFileTypeEnum.Pdf, async: false }); // Retrieve label url and tracking number or error message if (transaction.status == TransactionStatusEnum.Success) { console.log(transaction.labelUrl) console.log(transaction.trackingNumber) } else { console.log(transaction.messages) } ``` ```Java Java // Get the first rate in the rates results. // Customize this based on your own business logic Rate rate = shipment.ratesList[0]; HashMap transactionMap = new HashMap(); transactionMap.put("rate", rate.objectId); transactionMap.put("async", false); // Purchase the desired rate Transaction transaction = Transaction.create(transactionParameters); if (transaction.getStatus().equals("SUCCESS")) { System.out.println(String.format("Label url : %s", transaction.getLabelUrl())); System.out.println(String.format("Tracking number : %s", transaction.getTrackingNumber())); } else { System.out.println(String.format("An Error has occured while generating your label. Messages : %s", transaction.getMessages())); } ``` ```cs C# // Get the first rate in the rates results. // Customize this based on your business logic. Rate rate = shipment.Rates[0]; Transaction transaction = await sdk.Transactions.CreateAsync( CreateTransactionRequestBody.CreateTransactionCreateRequest( new TransactionCreateRequest() { Rate = rate.ObjectId, LabelFileType = LabelFileTypeEnum.Pdf, } ) ); if (transaction.Status == TransactionStatusEnum.Success) { Console.WriteLine($"{transaction.LabelUrl}"); Console.WriteLine($"{transaction.TrackingNumber}"); } else { Console.WriteLine($"{transaction.Messages}"); } ``` You can also create multi-piece shipments in one API call. Check out our [tutorial for single label call creation](/docs/guides_general/single_call) for more details. The POST request returns the primary Transaction object in the response. To get labels for all the parcels in the Shipment you need to filter for each parcel transaction. 1. The Transaction response after you've purchased the rate provides you with the primary `tracking_number`of the entire Shipment and the `label_url` for the first parcel of the Shipment. As an example, [this label](https://shippo-static.s3.amazonaws.com/img/illustrations/mps1.png) has the primary tracking number on it incl. information about the status of the entire multi-piece shipment. 2. To retrieve labels for the rest of the parcels in the Shipment, you need to make another GET request to the Transaction endpoint with the Rate `object_id` as the query parameter. [These sample labels](https://shippo-static.s3.amazonaws.com/img/illustrations/mps2.png) have both the primary tracking number (`MSTR`) on it as well as their own parcel-specific tracking number. Here's an example request: **Request:** ```shell cURL curl https://api.goshippo.com/transactions/?rate=cf6fea899f1848b494d9568e8266e076\ -H "Authorization: ShippoToken " ``` ```Python Python import shippo from shippo.models import operations shippo_sdk = shippo.Shippo(api_key_header="") transactions = shippo_sdk.transactions.list( operations.ListTransactionsRequest(rate='cf6fea899f1848b494d9568e8266e076') ) ``` ```PHP PHP require_once('lib/Shippo.php'); Shippo::setApiKey(""); $transactions = Shippo_Transaction::all( array('rate' => 'cf6fea899f1848b494d9568e8266e076')); ``` ```typescript TypeScript const shippo = new Shippo({apiKeyHeader: ''}); const transactions = await shippo.transactions.list({ rate: "cf6fea899f1848b494d9568e8266e076" }); ``` The API will respond with a JSON serialized list of the transactions that belong to this Rate. Each of these transactions belongs to exactly one parcel of the multi-piece shipment. Each transaction has a unique `tracking_number` and `label_url` field for it's associated parcel. **Response:** ```json { "count":5, "next":null, "previous":null, "results":[ { "object_state":"VALID", "status":"SUCCESS", "object_created":"2014-07-17T00:43:40.842Z", "object_updated":"2014-07-17T00:43:50.531Z", "object_id":"70ae8117ee1749e393f249d5b77c45e0", "object_owner":"shippotle@shippo.com", "was_test":true, "rate":"ee81fab0372e419ab52245c8952ccaeb", "tracking_number":"9499907123456123456781", "tracking_status":{ "object_created":"2014-07-17T00:43:50.402Z", "object_id":"907d5e6120ed491ea27d4f681a7ccd4d", "status":"UNKNOWN", "status_details":"", "status_date":null }, "tracking_url_provider":"https://tools.usps.com/go/TrackConfirmAction_input?origTrackNum=9499907123456123456781", "eta":"2014-07-21T12:00:00.000Z", "label_url":"https://shippo-delivery.s3.amazonaws.com/70ae8117ee1749e393f249d5b77c45e0.pdf?Signature=vDw1ltcyGveVR1OQoUDdzC43BY8%3D&Expires=1437093830&AWSAccessKeyId=AKIAJTHP3LLFMYAWALIA", "commercial_invoice_url": "", "messages":[ ], "metadata":"" }, {...}, {...} ] } ``` If you have more than 5 transactions that belong to the Rate, the response will be paginated. You can modify your request to increase the number of transactions per page. Example: ```json https://api.goshippo.com/transactions/?results=10&rate=ee81fab0372e419ab52245c8952ccaeb ``` Or you can retrieve each page of the response listed in the 'next' parameter. Example: ```json "next": https://api.goshippo.com/transactions/?rate=ee81fab0372e419ab52245c8952ccaeb&page=2 ``` ## Multi-piece shipping label references Some carriers support adding your own reference to a shipping label. For more information about support for multi-piece label reference support, review our [Carrier reference fields](/docs/carriers/carrierreferencefields#add-reference-details-to-a-parcel) guide. ## Parcel-level insurance You can also purchase insurance for each parcel of the multi-piece shipment. This can be done through the [extras](/shippoapi/public-api/parcels/parcelextra) attribute when creating your Parcel object within the Shipment request. Here is a sample request for a Shipment with different insurance amounts for each Parcel. ```shell curl https://api.goshippo.com/shipment/\ -H "Authorization: ShippoToken "\ -H "Content-Type: application/json"\ -d '{ "address_from": "d799c2679e644279b59fe661ac8fa488", "address_to": "42236bcf36214f62bcc6d7f12f02a849", "parcels": [ { "length": "5", "width": "5", "height": "5", "distance_unit": "cm", "weight": "2", "mass_unit": "lb", "template": "", "metadata": "Box1", "extra": { "insurance": { "amount": 25.00, "currency": "USD", "provider": "FEDEX" } } }, { "length": "5", "width": "10", "height": "15", "distance_unit": "cm", "weight": "6", "mass_unit": "lb", "template": "", "metadata": "Box2", "extra": { "insurance": { "amount": 50.00, "currency": "USD", "provider": "FEDEX" } } }, { "length": "2", "width": "8", "height": "9", "distance_unit": "cm", "weight": "5", "mass_unit": "lb", "template": "", "metadata": "Box3", "extra": { "insurance": { "amount": 45.00, "currency": "USD", "provider": "FEDEX" } } } ], "async": false } ``` ### Handling shipment-level and parcel-level insurance - If both shipment-level and parcel-level insurance are specified, the parcel-level insurance will take precedence. Parcels without parcel-level insurance will have the shipment-level insurance amount applied to that parcel. - If only shipment-level insurance is specified, then the shipment insurance amount will be applied to *each parcel* -- not divide amongst parcels. ## Parcel-level Collect on Delivery UPS offer Collect on Delivery (COD) for individual parcels in a multi-piece shipment. You can specific your COD preference in the [extras](/shippoapi/public-api/parcels/parcelextra) attribute of the Parcel object when creating your Shipment.