Skip to content
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.

Mutation

mutation {
  wholesale_order_import_packing_layout(data: {
    order_id: "12345"
    packing_data: "{ ... JSON string ... }"
  }) {
    request_id
    complexity
    wholesale_order {
      id
    }
  }
}

The packing_data field accepts a JSON string 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..." }
  ]
}

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 sealed product case (e.g., a master carton of 12 units). 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

Pallet

{
  "type": "Pallet",
  "details": {
    "height": 48.0,
    "length": 40.0,
    "width": 48.0,
    "weight_in_oz": 1600.0,
    "sscc_barcode": "PALLET001",
    "shipping_box_id": "optional-box-id",
    "container_number": 1
  },
  "line_items": [ ],
  "containers": [ ]
}
FieldTypeRequiredDescription
details.heightfloatYesHeight in inches. Must be greater than 0.
details.lengthfloatYesLength in inches. Must be greater than 0.
details.widthfloatYesWidth in inches. Must be greater than 0.
details.weight_in_ozfloatYesTare weight in ounces (weight of the pallet itself, excluding contents). Must be greater than 0.
details.sscc_barcodestringNoSSCC or other barcode identifier for the pallet. Max 30 characters.
details.shipping_box_idstringNoReference to a predefined pallet/shipping box type. 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": {
    "height": 16.0,
    "length": 12.0,
    "width": 10.0,
    "weight_in_oz": 320.0,
    "sscc_barcode": "PKG001",
    "shipping_box_id": "optional-box-id",
    "container_number": 1
  },
  "line_items": [ ],
  "containers": [ ]
}
FieldTypeRequiredDescription
details.heightfloatYesHeight in inches. Must be greater than 0.
details.lengthfloatYesLength in inches. Must be greater than 0.
details.widthfloatYesWidth in inches. Must be greater than 0.
details.weight_in_ozfloatYesTare weight in ounces. Must be greater than 0.
details.sscc_barcodestringNoSSCC or other barcode identifier. Max 30 characters.
details.shipping_box_idstringNoReference to a predefined shipping box type. 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": {
    "height": 12.0,
    "length": 10.0,
    "width": 8.0,
    "weight_in_oz": 160.0,
    "sscc_barcode": "CASE001",
    "container_number": 1
  },
  "order_line_item_id": 98765,
  "case_sku": "CASE-SKU-001",
  "quantity": 1
}
FieldTypeRequiredDescription
order_line_item_idintYesThe order line item ID this case pack fulfills
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).
quantityintYesNumber of cases (must be ≥ 1). The total quantity must convert evenly to the order line item’s unit of measure. See CasePack Quantity Rules for when this can be greater than 1.
details.heightfloatYesHeight in inches. Must be greater than 0.
details.lengthfloatYesLength in inches. Must be greater than 0.
details.widthfloatYesWidth in inches. Must be greater than 0.
details.weight_in_ozfloatYesWeight in ounces. Must be greater than 0.
details.sscc_barcodestringNoSSCC or other barcode identifier. Max 30 characters.
details.container_numberintYesSequential number for this case pack (see Container Numbering)

Note

The product case definition linked to case_sku already stores canonical dimensions in ShipHero. The import requires dimensions in the payload and stores them as provided. For consistency with the UI packing flow (which always uses product case master data), we recommend passing values that match your product case definition.

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": 98766,
  "case_sku": "PALLET-SKU-001"
}
FieldTypeRequiredDescription
order_line_item_idintYesThe order line item ID this UOM pallet fulfills
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.heightfloatYesHeight in inches. Must be greater than 0.
details.lengthfloatYesLength in inches. Must be greater than 0.
details.widthfloatYesWidth in inches. Must be greater than 0.
details.weight_in_ozfloatYesWeight in ounces. Must be greater than 0.
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 Pallets have a linked product case definition that stores canonical dimensions. In the current version the import uses the dimensions you provide in the payload. For consistency with the UI packing flow, we recommend passing values that match your product case definition. In a future iteration, the system may enforce or default to the product case master data dimensions.


Line Items

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

{
  "order_line_item_id": 12345,
  "quantity": 10
}
FieldTypeRequiredDescription
order_line_item_idintYesThe order line item ID being packed
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)

CasePack Quantity Rules

The quantity field on a CasePack entry behaves differently depending on whether the CasePack is nested inside a parent container or top-level (i.e., a standalone shippable carton).

Nested CasePacks (inside a Package or Pallet)

When a CasePack is inside a Package or Pallet, the parent container is the shippable unit that receives a shipping label. In this case, quantity can be greater than 1 — a single entry with quantity: 3 means 3 cases of the same product packed inside that parent container, all sharing the same container_number.

{
  "type": "Package",
  "details": { "..." },
  "containers": [
    {
      "type": "CasePack",
      "details": { "container_number": 1 },
      "order_line_item_id": 1001,
      "case_sku": "CASE-SKU-A",
      "quantity": 3
    }
  ]
}

Top-level CasePacks (courier orders)

When a CasePack is at the top level of a courier order, it represents a standalone physical carton that will receive its own shipping label. In this case, quantity must be 1. Each physical carton needs its own entry with its own container_number.

To pack 3 top-level cases of the same product, create 3 separate entries:

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

Note

Top-level CasePacks with quantity > 1 are rejected. Each physical carton shipped separately needs its own entry and shipping label.


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: quantity × case_multiplier, where the case multiplier is the number of eaches (ordered units) contained in one case, resolved from the product case hierarchy.
  • For UOM Pallet entries: 1 × case_multiplier. UOM Pallets always represent exactly one physical pallet.

All integer quantity fields (quantity on line items, CasePacks, 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 in the current version. Following them is the caller’s responsibility — submitting a layout that violates these rules may result in incorrect packing data. A future update will add server-side enforcement with clear error messages.


Current Limitations

The following features are not yet supported in this first version of the import and will be added in future iterations:

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 does not currently create or assign LPN identifiers to containers. LPNs are normally auto-generated during the UI packing flow and are required for:

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

If your workflow requires LPN-based scanning after import, this limitation should be considered.

Weight Recalculation

Container weights are taken as-is from the payload. The system does not automatically recalculate container weights based on their contents (as the UI packing flow does). Ensure the weights you provide 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

Freight Order

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

{
  "containers": [
    {
      "type": "Pallet",
      "details": {
        "height": 48.0,
        "length": 40.0,
        "width": 48.0,
        "weight_in_oz": 1600.0,
        "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",
          "quantity": 1
        },
        {
          "type": "Package",
          "details": {
            "height": 16.0,
            "length": 12.0,
            "width": 10.0,
            "weight_in_oz": 320.0,
            "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": 1003, "quantity": 15 }
              ]
            }
          ]
        }
      ]
    },
    {
      "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": 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

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": {
        "height": 16.0,
        "length": 12.0,
        "width": 10.0,
        "weight_in_oz": 320.0,
        "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": 2002,
      "case_sku": "CASE-SKU-X",
      "quantity": 1
    }
  ]
}

Numbering breakdown

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

Note that 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...
Malformed JSON 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)
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: ...
Top-level CasePack with quantity > 1 (courier)Top-level CasePacks must have quantity 1. To pack multiple cases, create separate entries.
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}
Product case not found during creationProduct case not found for SKU: {sku}
UOM Pallet with non-PALLET product caseUOM Pallet requires a PALLET product case, but {sku} has container type {type}
Line item not foundLine item not found: {id}