Skip to content
Need help with our api? Ask in Community
Import Packing Layout

Import Packing Layout

The wholesale_order_import_packing_layout mutation allows you to define the full packing structure of a wholesale order in a single API call, rather than building it container-by-container through the ShipHero UI.

Important

This mutation is currently intended for orders packed outside ShipHero. It creates the packing configuration directly from the provided layout without going through the standard warehouse picking and packing workflows. It does not validate against staged inventory, assign lots, or create LPNs. If your order is being packed through the ShipHero warehouse UI, use the standard packing flow instead.

Prerequisites

  • The wholesale order must be in packing status.
  • The order must not have an existing packing configuration. If one already exists (even partially), the import will be rejected. Reset the order’s packing state before re-importing.

Tip

Before assembling the packing_data payload, query the staged inventory manifest on the wholesale order. It returns the SKUs, quantities, and line_item_id values currently in staging — the same line_item_id plugs directly into order_line_item_id below — and helps keep the imported layout consistent with what’s actually been picked.

Mutation

mutation ImportPackingLayout($data: WholesaleOrderImportPackingLayoutInput!) {
  wholesale_order_import_packing_layout(data: $data) {
    request_id
    complexity
    wholesale_order {
      id
    }
  }
}

Variables:

{
  "data": {
    "order_id": "T3JkZXI6MTIzNDU2",
    "packing_data": {
      "containers": [
        {
          "type": "Package",
          "details": {
            "height": 12.0,
            "length": 10.0,
            "width": 8.0,
            "weight_in_oz": 32.0,
            "container_number": 1
          },
          "line_items": [
            {
              "order_line_item_id": "TGluZUl0ZW06MTIzNDU2",
              "quantity": 1
            }
          ]
        }
      ]
    }
  }
}

This request example assumes the wholesale order uses the COURIER shipping option.

Example response:

{
  "data": {
    "wholesale_order_import_packing_layout": {
      "request_id": "7f4fca5e8cf84cf5967ee27f",
      "complexity": 11,
      "wholesale_order": {
        "id": "V2hvbGVzYWxlT3JkZXI6MTIzNDU2"
      }
    }
  }
}

The packing_data field accepts a JSON object describing the entire container hierarchy.


JSON Structure

The top-level object must contain a containers array. Each entry in the array is a top-level container.

{
  "containers": [
    { "...container object..." },
    { "...container object..." }
  ]
}

Note

order_id accepts either a Public API GID or a legacy numeric ID provided as a string. Inside packing_data, order_line_item_id and custom_box_id accept a Public API GID or a legacy numeric ID provided as either a JSON number or numeric string. The examples on this page use GIDs, matching the values returned by Public API queries.


Container Types

Every container object must include a type field and a details field. The supported types are:

TypeDescriptionCan be top-level?Can be nested?
PalletA regular pallet. Contains packages, case packs, and/or loose line items.✅ Yes❌ No
UOM PalletA pallet that represents a single unit-of-measure product case (e.g., a full pallet of one SKU).✅ Yes❌ No
PackageA box or carton. Can contain case packs, line items, and/or nested inner packages.✅ Yes✅ Yes
CasePackA single sealed product case (e.g., one master carton of 12 units). Represents exactly one physical shippable unit. Leaf node — cannot contain children.✅ Yes✅ Yes

Shipping option constraints

  • Freight orders: Only Pallet and UOM Pallet are allowed at the top level. Packages and CasePacks must be nested inside a pallet.
  • Courier orders: Pallet and UOM Pallet are not allowed at any level. Use Package and CasePack as top-level containers.

Nesting rules

  • Pallets and UOM Pallets can only appear at the top level. They cannot be placed inside another container.
  • Packages can be nested inside other packages or inside pallets, up to a maximum depth:
    • Freight: 3 levels (e.g., Pallet → Package → Package)
    • Courier: 2 levels (e.g., Package → Package)
  • CasePacks can appear inside a pallet, inside a package, or at the top level (courier orders). They are always leaf nodes and do not count toward the nesting depth.

Container Fields

Note

Every container type accepts an optional details.sscc_barcode. If you provide one, ShipHero stores it as-is and the downstream wholesale_order_mark_as_packed step will not overwrite it. If you leave it empty, ShipHero generates an SSCC-18 for you at mark_as_packed time for trading partners that require GS1 labeling.

Shipping boxes and dimension precedence

Pallet and Package containers can reference either a custom box or a carrier box. The two fields are mutually exclusive.

Box inputDimension behavior
Neither box fieldheight, length, and width are all required and the submitted values are stored.
custom_box_idDimensions come from the referenced custom box. Any submitted dimensions are ignored.
carrier_box_codeDimensions come from the referenced carrier box. Any submitted dimensions are ignored.

weight_in_oz is always required for Pallet and Package; weight never comes from the referenced box.

When using a box reference, omit height, length, and width. If supplied, they do not override the box, although each supplied value must still be greater than 0.

Use the custom_boxes query to obtain a custom box id, or the carrier_boxes query to obtain a carrier box box_code. The selected box must be active, accessible to the authenticated user, and available at the order’s staging warehouse. A carrier box code must resolve to one connected carrier without ambiguity.

The referenced box must have all three dimensions configured. Each dimension must be greater than 0 and at most 99.9999, with up to 4 decimal places.

Important

Do not send shipping_box_id in an import payload. It remains an output field in the exported packing layout, but import requests must use custom_box_id or carrier_box_code.

Pallet

{
  "type": "Pallet",
  "details": {
    "weight_in_oz": 1600.0,
    "sscc_barcode": "PALLET001",
    "custom_box_id": "QXZhaWxhYmxlQm94OjEyMzQ1Ng==",
    "container_number": 1
  },
  "line_items": [ ],
  "containers": [ ]
}
FieldTypeRequiredDescription
details.heightfloatConditionalHeight in inches. Required without a box reference; ignored when a box reference is provided. When required, must be greater than 0 and at most 99.9999, with up to 4 decimal places.
details.lengthfloatConditionalLength in inches. Required without a box reference; ignored when a box reference is provided. When required, must be greater than 0 and at most 99.9999, with up to 4 decimal places.
details.widthfloatConditionalWidth in inches. Required without a box reference; ignored when a box reference is provided. When required, must be greater than 0 and at most 99.9999, with up to 4 decimal places.
details.weight_in_ozfloatYesTotal packed weight of the pallet, including its contents, in ounces. Must be greater than 0 and at most 9999999.99, with up to 2 decimal places.
details.sscc_barcodestringNoSSCC or other barcode identifier for the pallet. Max 30 characters.
details.custom_box_idIDNoIdentifier returned by custom_boxes. Accepts a Public API GID or a positive legacy numeric ID provided as either a JSON number or numeric string. Cannot be combined with carrier_box_code.
details.carrier_box_codestringNoNon-empty box_code returned by carrier_boxes. Cannot be combined with custom_box_id. Max 128 characters.
details.container_numberintYesSequential number for this pallet (see Container Numbering)
line_itemsarrayNoLoose items packed directly on the pallet (see Line Items)
containersarrayNoNested containers: Packages and/or CasePacks inside this pallet

Package

{
  "type": "Package",
  "details": {
    "weight_in_oz": 320.0,
    "sscc_barcode": "PKG001",
    "carrier_box_code": "86",
    "container_number": 1
  },
  "line_items": [ ],
  "containers": [ ]
}
FieldTypeRequiredDescription
details.heightfloatConditionalHeight in inches. Required without a box reference; ignored when a box reference is provided. When required, must be greater than 0 and at most 99.9999, with up to 4 decimal places.
details.lengthfloatConditionalLength in inches. Required without a box reference; ignored when a box reference is provided. When required, must be greater than 0 and at most 99.9999, with up to 4 decimal places.
details.widthfloatConditionalWidth in inches. Required without a box reference; ignored when a box reference is provided. When required, must be greater than 0 and at most 99.9999, with up to 4 decimal places.
details.weight_in_ozfloatYesTotal packed weight of the package, including its contents, in ounces. Must be greater than 0 and at most 9999999.99, with up to 2 decimal places.
details.sscc_barcodestringNoSSCC or other barcode identifier. Max 30 characters.
details.custom_box_idIDNoIdentifier returned by custom_boxes. Accepts a Public API GID or a positive legacy numeric ID provided as either a JSON number or numeric string. Cannot be combined with carrier_box_code.
details.carrier_box_codestringNoNon-empty box_code returned by carrier_boxes. Cannot be combined with custom_box_id. Max 128 characters.
details.container_numberintYesSequential number for this package (see Container Numbering)
line_itemsarrayNoItems packed inside this box (see Line Items)
containersarrayNoNested containers: inner Packages and/or CasePacks

CasePack

{
  "type": "CasePack",
  "details": {
    "sscc_barcode": "CASE001",
    "container_number": 1
  },
  "order_line_item_id": "TGluZUl0ZW06OTg3Ng==",
  "case_sku": "CASE-SKU-001"
}

Important

A CasePack entry represents exactly one physical shippable unit (one SSCC-18 label, one container). To pack N cases of the same product, send N separate CasePack entries.

FieldTypeRequiredDescription
order_line_item_idIDYesIdentifier of the order line item this case pack fulfills. Accepts a Public API GID or a legacy numeric ID provided as either a JSON number or numeric string.
case_skustringYesThe SKU of the product case definition. Must exist in your account’s product cases and must belong to the same product family as the order line item (same base product).
details.heightfloatNoOptional dimension override in inches. If any dimension is supplied, all three are required. Must be greater than 0 and at most 99.9999, with up to 4 decimal places.
details.lengthfloatNoOptional dimension override in inches. If any dimension is supplied, all three are required. Must be greater than 0 and at most 99.9999, with up to 4 decimal places.
details.widthfloatNoOptional dimension override in inches. If any dimension is supplied, all three are required. Must be greater than 0 and at most 99.9999, with up to 4 decimal places.
details.weight_in_ozfloatNoOptional weight override in ounces. Must be greater than 0 and at most 9999999.99, with up to 2 decimal places.
details.sscc_barcodestringNoSSCC or other barcode identifier. Max 30 characters.
details.container_numberintYesSequential number for this case pack (see Container Numbering)

Note

If height, length, and width are omitted, ShipHero uses all three dimensions from the product case linked to case_sku. Supplying all three overrides the configured dimensions; partial dimension overrides are rejected. weight_in_oz is independent: a submitted value overrides the configured weight, while an omitted value uses the configured weight. Submitted and configured fallback values must meet the limits listed above.

Important

CasePack does not accept custom_box_id, carrier_box_code, or shipping_box_id.

UOM Pallet

{
  "type": "UOM Pallet",
  "details": {
    "height": 60.0,
    "length": 48.0,
    "width": 40.0,
    "weight_in_oz": 2400.0,
    "sscc_barcode": "UOMPALLET001",
    "container_number": 2
  },
  "order_line_item_id": "TGluZUl0ZW06OTg3Nw==",
  "case_sku": "PALLET-SKU-001"
}
FieldTypeRequiredDescription
order_line_item_idIDYesIdentifier of the order line item this UOM pallet fulfills. Accepts a Public API GID or a legacy numeric ID provided as either a JSON number or numeric string.
case_skustringYesThe SKU of the pallet-level product case definition. Must exist in your account, must have container type PALLET, and must belong to the same product family as the order line item.
details.heightfloatNoOptional dimension override in inches. If any dimension is supplied, all three are required. Must be greater than 0 and at most 99.9999, with up to 4 decimal places.
details.lengthfloatNoOptional dimension override in inches. If any dimension is supplied, all three are required. Must be greater than 0 and at most 99.9999, with up to 4 decimal places.
details.widthfloatNoOptional dimension override in inches. If any dimension is supplied, all three are required. Must be greater than 0 and at most 99.9999, with up to 4 decimal places.
details.weight_in_ozfloatNoOptional weight override in ounces. Must be greater than 0 and at most 9999999.99, with up to 2 decimal places.
details.sscc_barcodestringNoSSCC or other barcode identifier. Max 30 characters.
details.container_numberintYesSequential number — shares the same sequence as regular Pallets (see Container Numbering)

Note

UOM Pallet uses the same precedence as CasePack: omit all dimensions to use the linked product case dimensions, or submit all three to override them. Submitted weight_in_oz overrides the configured weight; omitted weight uses the configured value.

Important

UOM Pallet does not accept custom_box_id, carrier_box_code, or shipping_box_id.


Line Items

Line items represent individual product units (eaches) packed directly inside a Package or on a Pallet.

{
  "order_line_item_id": "TGluZUl0ZW06MTIzNDU2",
  "quantity": 10
}
FieldTypeRequiredDescription
order_line_item_idIDYesIdentifier of the order line item being packed. Accepts a Public API GID or a legacy numeric ID provided as either a JSON number or numeric string.
quantityintYesNumber of units packed in this container (must be ≥ 1)

Line items can only appear inside a Package or directly on a Pallet. They cannot appear inside a CasePack or UOM Pallet.

Important

Line items represent loose eaches only. If the order line item is in cases (e.g., six-packs), use CasePack containers instead.


Container Numbering

Container numbers are sequential identifiers used for label generation, SSCC-18 codes, packing lists, and ASN transmissions. There are three independent sequences:

SequenceShared by
Pallet sequenceAll Pallet and UOM Pallet entries (they share one counter)
Package sequenceAll Package entries, regardless of nesting depth
CasePack sequenceAll CasePack entries, regardless of parent container

Rules:

  1. Each sequence must start at 1 and increment by 1 with no gaps or duplicates.
  2. Regular pallets and UOM pallets count together. If you have 2 pallets and 1 UOM pallet, their container numbers must be 1, 2, 3.
  3. All packages across the entire hierarchy share one sequence. A top-level package and a deeply nested inner box both draw from the same counter. If you have 3 packages total (at any depth), they must be numbered 1, 2, 3.
  4. All case packs share one sequence, regardless of which pallet or package they sit inside.

Example with correct numbering:

Pallet (container_number: 1)          ← pallet sequence
├── CasePack (container_number: 1)    ← case pack sequence
├── Package (container_number: 1)     ← package sequence
│   ├── LineItem
│   └── Package (container_number: 2) ← package sequence (continues)
│       └── LineItem
UOM Pallet (container_number: 2)      ← pallet sequence (continues)

One CasePack = One Physical Unit

Each CasePack entry always represents exactly one physical sealed case — one SSCC-18 barcode and one container in ShipHero. This holds regardless of whether the case pack is nested inside a parent container or sits at the top level.

To pack N cases of the same product, send N separate CasePack entries. For example, to pack 3 cases:

{
  "containers": [
    {
      "type": "CasePack",
      "details": { "container_number": 1 },
      "order_line_item_id": "TGluZUl0ZW06MTAwMQ==",
      "case_sku": "CASE-SKU-A"
    },
    {
      "type": "CasePack",
      "details": { "container_number": 2 },
      "order_line_item_id": "TGluZUl0ZW06MTAwMQ==",
      "case_sku": "CASE-SKU-A"
    },
    {
      "type": "CasePack",
      "details": { "container_number": 3 },
      "order_line_item_id": "TGluZUl0ZW06MTAwMQ==",
      "case_sku": "CASE-SKU-A"
    }
  ]
}

Quantity Validation

Every order line item must be accounted for in the packing layout, and the total quantity packed for each must exactly match the ordered quantity. If a line item is omitted entirely or its packed total does not match, the import will be rejected.

The system validates this by summing:

  • quantity from all line_items entries referencing that line item ID.
  • For CasePack entries: case_multiplier per entry, where the case multiplier is the number of eaches (ordered units) contained in one case, resolved from the product case hierarchy. Each CasePack is one case, so to account for more units add more CasePack entries.
  • For UOM Pallet entries: 1 × case_multiplier. UOM Pallets always represent exactly one physical pallet.

All integer quantity fields (quantity on line items, and container_number) must be ≥ 1. Zero, negative, or non-numeric values will be rejected.

Packing rules by order UOM

Order line item UOMAllowed packing methodsNotes
EachesLineItem (loose eaches) and/or CasePackCan mix eaches and cases in the same layout.
Cases (e.g., six-packs)CasePack with the exact same case SKU as the order line itemMust use the same case definition. Different case sizes within the same product family are not supported.

Warning

These packing rules are not fully enforced by the API. Following them is the caller’s responsibility — submitting a layout that violates these rules may result in incorrect packing data.


Current Limitations

The following features are not currently supported by the import:

Packed Outside ShipHero Only

This import is designed for orders packed outside ShipHero’s warehouse workflows. It does not validate against staged inventory (order bin allocations) and bypasses the standard picking flow. Do not use it for orders being packed through the ShipHero warehouse UI.

Lot Tracking

The import does not currently accept or assign lot information. If your account uses lot tracking, the imported packing layout will not have lots associated with line items or case packs. This means:

  • Lot-tracked products will not show lot assignments on packed items.
  • If lot tracking enforcement is required for your workflow, coordinate with ShipHero support before using this endpoint.

LPN (License Plate Number) Assignment

The import itself does not create or assign LPN identifiers to containers — the imported layout starts without LPNs. They are created later, when you call wholesale_order_mark_as_packed, which also moves inventory out of the staging bin into the containers. LPNs are required for:

  • Scanning containers in the warehouse.
  • Unpacking and repacking operations.
  • Label generation and fulfillment workflows.

Weight Recalculation

Pallet and Package weights are taken as-is from the payload. CasePack and UOM Pallet weights use the submitted override or the linked product case’s configured weight. The system does not recalculate container weights from their contents, so ensure submitted and configured weights are accurate.

Partial Imports and Incremental Updates

The import creates the full packing configuration in a single call. You cannot add containers to an existing configuration or import a partial layout. To modify a previously imported layout, reset the order’s packing configuration and re-import the full layout.


Full Examples

The examples below intentionally mix Public API GIDs, JSON numbers, and numeric strings for order_line_item_id to demonstrate all accepted formats.

Freight Order

A freight order with 4 line items packed across a regular pallet and a UOM pallet:

{
  "containers": [
    {
      "type": "Pallet",
      "details": {
        "weight_in_oz": 1600.0,
        "custom_box_id": "QXZhaWxhYmxlQm94OjEyMzQ1Ng==",
        "sscc_barcode": "PALLET001",
        "container_number": 1
      },
      "line_items": [
        { "order_line_item_id": 1001, "quantity": 10 }
      ],
      "containers": [
        {
          "type": "CasePack",
          "details": {
            "sscc_barcode": "CASE001",
            "container_number": 1
          },
          "order_line_item_id": "1002",
          "case_sku": "CASE-SKU-A"
        },
        {
          "type": "Package",
          "details": {
            "weight_in_oz": 320.0,
            "custom_box_id": "QXZhaWxhYmxlQm94OjY1NDMyMQ==",
            "sscc_barcode": "PKG001",
            "container_number": 1
          },
          "line_items": [
            { "order_line_item_id": "1002", "quantity": 2 }
          ],
          "containers": [
            {
              "type": "Package",
              "details": {
                "height": 8.0,
                "length": 6.0,
                "width": 4.0,
                "weight_in_oz": 80.0,
                "sscc_barcode": "PKG002",
                "container_number": 2
              },
              "line_items": [
                { "order_line_item_id": "TGluZUl0ZW06MTAwMw==", "quantity": 15 }
              ]
            }
          ]
        }
      ]
    },
    {
      "type": "UOM Pallet",
      "details": {
        "sscc_barcode": "UOMPALLET001",
        "container_number": 2
      },
      "order_line_item_id": "1004",
      "case_sku": "PALLET-SKU-B"
    }
  ]
}

Numbering breakdown

  • Pallet sequence: Pallet → 1, UOM Pallet → 2
  • Package sequence: PKG001 → 1, PKG002 → 2
  • CasePack sequence: CASE001 → 1

In this example, the regular pallet and PKG001 use dimensions from distinct custom_box_id values, while PKG002 uses its submitted dimensions. The CasePack and UOM Pallet omit dimensions and weight, so those values come from their linked product case configurations.

Courier Order

A courier order with 2 line items — one packed as loose eaches in a box, and one as a standalone case pack. Both Package and CasePack are valid top-level containers for courier orders.

{
  "containers": [
    {
      "type": "Package",
      "details": {
        "weight_in_oz": 320.0,
        "carrier_box_code": "86",
        "sscc_barcode": "PKG001",
        "container_number": 1
      },
      "line_items": [
        { "order_line_item_id": 2001, "quantity": 5 }
      ]
    },
    {
      "type": "CasePack",
      "details": {
        "height": 12.0,
        "length": 10.0,
        "width": 8.0,
        "weight_in_oz": 100.0,
        "sscc_barcode": "CASE001",
        "container_number": 1
      },
      "order_line_item_id": "TGluZUl0ZW06MjAwMg==",
      "case_sku": "CASE-SKU-X"
    }
  ]
}

Numbering breakdown

  • Package sequence: PKG001 → 1
  • CasePack sequence: CASE001 → 1

The package uses dimensions from carrier_box_code. The CasePack submits all three dimensions and weight_in_oz, so those values override its linked product case configuration. The package and case pack sequences are independent — both start at 1.


Error Responses

The mutation will raise an error with a descriptive message in the following cases:

ScenarioError message
Order not in packing statusWholesale order is not in packing status
Packing config already existsPacking configuration already exists for this order...
Invalid packing object or structure (missing fields, wrong types, extra fields, unknown container type, nested pallets, zero/negative quantities, zero/negative dimensions, oversized strings)Invalid packing data: ... (includes specific validation details)
shipping_box_id sent in any container, or a box field sent in CasePack/UOM PalletInvalid packing data: ... (rejected as an unexpected extra field)
Both custom_box_id and carrier_box_code sent on one Pallet/PackageOnly one of custom_box_id or carrier_box_code can be provided...
Missing height, length, or width on a Pallet/Package without a box referenceContainer dimensions are required when no custom_box_id or carrier_box_code is provided. Missing: ...
Custom box is invalid, inactive, inaccessible, or assigned to another warehouseInvalid custom_box_id: {id}
Carrier box is invalid, inactive, unavailable at the staging warehouse, or its carrier is not connectedInvalid carrier_box_code: {code}
Carrier box code resolves to multiple connected carriersAmbiguous carrier_box_code {code}
Referenced box has missing or unsupported dimensionsBox {reference} has invalid dimensions...
Only some product-case dimensions are suppliedProduct case dimensions for case_sku={sku} must include height, length, and width when any dimension is provided. Missing: ...
Product-case fallback is needed but its configured container is missingProduct case container for case_sku={sku} was not found
Submitted or configured dimensions/weight exceed the supported value or decimal placesError identifies the invalid field or value; see the limits above.
Freight order with non-pallet at top levelFreight orders must have only Pallets or UOM Pallets at the top level. Found invalid types: ...
Courier order with palletsCourier orders cannot contain Pallets or UOM Pallets. Found at top level: ...
CasePack entry with a quantity field (the field is no longer accepted)Invalid packing data: ... (rejected as an unexpected extra field)
Nesting too deep (freight)Maximum nesting depth of 3 exceeded at ...
Nesting too deep (courier)Maximum nesting depth of 2 exceeded at ...
Line item not in orderLine item {id} does not belong to order {order_id}
Quantity mismatch or missing line itemLine item {sku} quantity mismatch. Expected: {n}, Got: {m}
Unknown case SKUCase SKU {sku} not found
Case SKU belongs to different product familyCase SKU {sku} is not compatible with line item SKU {sku}
Quantity does not convert evenly between UOMsQuantity {n} of {case_sku} does not convert evenly to {line_item_sku}
UOM Pallet with non-PALLET product caseUOM Pallet requires a PALLET product case, but {sku} has container type {type}