Basic Packing

Pack items into containers using the FractalPack packing engine. This recipe covers single-box packing, multi-box scenarios, separation groups, and affinity groups.

Prerequisites

Step 1: Define items and containers

Items require id, length, width, height (inches), weight (lbs), and quantity. Containers require id, length, width, height (inner dimensions in inches), and maxWeight (lbs).

Step 2: Pack items into a single box

curl -X POST https://api.fractalpack.com/api/v1/pack \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: fpk_test_your_api_key" \
  -d '{
    "items": [
      {
        "id": "WIDGET-LG-001",
        "length": 12,
        "width": 8,
        "height": 6,
        "weight": 2.5,
        "quantity": 3
      },
      {
        "id": "GADGET-SM-042",
        "length": 4,
        "width": 4,
        "height": 3,
        "weight": 0.8,
        "quantity": 5
      }
    ],
    "containers": [
      {
        "id": "BOX-MEDIUM",
        "length": 18,
        "width": 14,
        "height": 12,
        "maxWeight": 40
      }
    ]
  }'

Response

{
  "algorithm": "ebAfit",
  "results": [
    {
      "containerId": "BOX-MEDIUM",
      "boxIndex": 0,
      "containerDimensions": {
        "length": 18,
        "width": 14,
        "height": 12
      },
      "packedItems": [
        {
          "id": "WIDGET-LG-001",
          "coordinate": { "x": 0, "y": 0, "z": 0 },
          "packedDimensions": { "length": 12, "width": 8, "height": 6 },
          "weight": 2.5,
          "tags": []
        },
        {
          "id": "WIDGET-LG-001",
          "coordinate": { "x": 12, "y": 0, "z": 0 },
          "packedDimensions": { "length": 12, "width": 8, "height": 6 },
          "weight": 2.5,
          "tags": []
        },
        {
          "id": "WIDGET-LG-001",
          "coordinate": { "x": 0, "y": 8, "z": 0 },
          "packedDimensions": { "length": 12, "width": 8, "height": 6 },
          "weight": 2.5,
          "tags": []
        },
        {
          "id": "GADGET-SM-042",
          "coordinate": { "x": 0, "y": 0, "z": 6 },
          "packedDimensions": { "length": 4, "width": 4, "height": 3 },
          "weight": 0.8,
          "tags": []
        }
      ],
      "unpackedItems": [],
      "volumeUtilizationPercent": 68.2,
      "totalWeight": 11.5
    }
  ]
}

Key fields in the response:

Field Description
algorithm The packing algorithm used (default: ebAfit)
results Array of packed containers. Each entry is one physical box.
results[].containerId Which container type was used
results[].boxIndex Index when multiple boxes of the same type are used
results[].packedItems Items placed in this box, with 3D coordinates and orientation
results[].unpackedItems Items that did not fit (empty if all items were packed)
results[].volumeUtilizationPercent How efficiently the box volume is used
results[].totalWeight Total weight of items in this box

Each packed item includes coordinate (placement origin in inches from the box corner) and packedDimensions (the item's oriented dimensions as placed).

Step 3: Multi-box packing

Set allowMultipleBoxes: true to let the engine use more than one box. Provide multiple container types and the engine selects the best combination.

curl -X POST https://api.fractalpack.com/api/v1/pack \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: fpk_test_your_api_key" \
  -d '{
    "items": [
      {
        "id": "MONITOR-27IN",
        "length": 28,
        "width": 18,
        "height": 8,
        "weight": 12.0,
        "quantity": 1
      },
      {
        "id": "KEYBOARD-MECH",
        "length": 17,
        "width": 6,
        "height": 2,
        "weight": 2.1,
        "quantity": 2
      },
      {
        "id": "MOUSE-ERGO",
        "length": 5,
        "width": 3,
        "height": 2,
        "weight": 0.3,
        "quantity": 4
      },
      {
        "id": "DESKPAD-XL",
        "length": 35,
        "width": 17,
        "height": 0.2,
        "weight": 1.8,
        "quantity": 1
      }
    ],
    "containers": [
      {
        "id": "BOX-SMALL",
        "length": 12,
        "width": 10,
        "height": 6,
        "maxWeight": 15
      },
      {
        "id": "BOX-LARGE",
        "length": 36,
        "width": 20,
        "height": 12,
        "maxWeight": 50
      }
    ],
    "allowMultipleBoxes": true
  }'

Response

The engine may split across multiple boxes:

{
  "algorithm": "ebAfit",
  "results": [
    {
      "containerId": "BOX-LARGE",
      "boxIndex": 0,
      "packedItems": [
        { "id": "MONITOR-27IN", "weight": 12.0 },
        { "id": "DESKPAD-XL", "weight": 1.8 },
        { "id": "KEYBOARD-MECH", "weight": 2.1 },
        { "id": "KEYBOARD-MECH", "weight": 2.1 }
      ],
      "unpackedItems": [],
      "volumeUtilizationPercent": 52.1,
      "totalWeight": 18.0
    },
    {
      "containerId": "BOX-SMALL",
      "boxIndex": 0,
      "packedItems": [
        { "id": "MOUSE-ERGO", "weight": 0.3 },
        { "id": "MOUSE-ERGO", "weight": 0.3 },
        { "id": "MOUSE-ERGO", "weight": 0.3 },
        { "id": "MOUSE-ERGO", "weight": 0.3 }
      ],
      "unpackedItems": [],
      "volumeUtilizationPercent": 16.7,
      "totalWeight": 1.2
    }
  ]
}

Each boxIndex starts at 0 per container type. If two BOX-LARGE boxes are needed, they appear as boxIndex: 0 and boxIndex: 1.

Step 4: Separation groups

Separation groups prevent items with certain tags from sharing a box. Each inner list defines a compatibility group. Items from different groups are packed into separate containers.

Use case: hazardous materials that cannot be combined in the same package.

curl -X POST https://api.fractalpack.com/api/v1/pack \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: fpk_test_your_api_key" \
  -d '{
    "items": [
      {
        "id": "BLEACH-1GAL",
        "length": 6,
        "width": 4,
        "height": 12,
        "weight": 9.0,
        "quantity": 2,
        "tags": ["oxidizer", "cleaning"]
      },
      {
        "id": "AMMONIA-1GAL",
        "length": 6,
        "width": 4,
        "height": 12,
        "weight": 8.5,
        "quantity": 2,
        "tags": ["reducer", "cleaning"]
      },
      {
        "id": "SPONGE-PACK",
        "length": 5,
        "width": 3,
        "height": 2,
        "weight": 0.2,
        "quantity": 4,
        "tags": ["cleaning"]
      }
    ],
    "containers": [
      {
        "id": "BOX-CHEM",
        "length": 14,
        "width": 10,
        "height": 14,
        "maxWeight": 50
      }
    ],
    "allowMultipleBoxes": true,
    "separationGroups": [
      ["oxidizer", "bleach"],
      ["reducer", "ammonia"]
    ]
  }'

Items tagged oxidizer or bleach form one group. Items tagged reducer or ammonia form another. The engine guarantees these groups never share a container. Items without tags matching any group (like SPONGE-PACK with only the cleaning tag) can go in either box.

Response

{
  "algorithm": "ebAfit",
  "results": [
    {
      "containerId": "BOX-CHEM",
      "boxIndex": 0,
      "packedItems": [
        { "id": "BLEACH-1GAL", "tags": ["oxidizer", "cleaning"] },
        { "id": "BLEACH-1GAL", "tags": ["oxidizer", "cleaning"] },
        { "id": "SPONGE-PACK", "tags": ["cleaning"] },
        { "id": "SPONGE-PACK", "tags": ["cleaning"] }
      ],
      "unpackedItems": [],
      "totalWeight": 18.4
    },
    {
      "containerId": "BOX-CHEM",
      "boxIndex": 1,
      "packedItems": [
        { "id": "AMMONIA-1GAL", "tags": ["reducer", "cleaning"] },
        { "id": "AMMONIA-1GAL", "tags": ["reducer", "cleaning"] },
        { "id": "SPONGE-PACK", "tags": ["cleaning"] },
        { "id": "SPONGE-PACK", "tags": ["cleaning"] }
      ],
      "unpackedItems": [],
      "totalWeight": 17.4
    }
  ]
}

Step 5: Affinity groups

Affinity groups pin items matching certain patterns to specific containers. Use this when certain products must always go in a particular box type.

curl -X POST https://api.fractalpack.com/api/v1/pack \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: fpk_test_your_api_key" \
  -d '{
    "items": [
      {
        "id": "WINE-RED-750ML",
        "length": 3.5,
        "width": 3.5,
        "height": 12,
        "weight": 3.0,
        "quantity": 6,
        "tags": ["wine", "fragile"]
      },
      {
        "id": "CHEESE-WHEEL",
        "length": 8,
        "width": 8,
        "height": 4,
        "weight": 2.0,
        "quantity": 2,
        "tags": ["food"]
      }
    ],
    "containers": [
      {
        "id": "WINE-SHIPPER-6PK",
        "length": 12,
        "width": 8,
        "height": 14,
        "maxWeight": 25
      },
      {
        "id": "BOX-INSULATED",
        "length": 18,
        "width": 12,
        "height": 10,
        "maxWeight": 30
      }
    ],
    "allowMultipleBoxes": true,
    "affinityGroups": [
      {
        "itemPatterns": ["wine"],
        "containerIds": ["WINE-SHIPPER-6PK"],
        "exclusive": true
      }
    ]
  }'
Field Description
itemPatterns Tag patterns to match against item tags
containerIds Container IDs these items must be packed into
exclusive When true, only matching items can go in these containers

With exclusive: true, the wine shipper box is reserved exclusively for wine items. The cheese goes into the insulated box.

Handling unpacked items

If an item cannot fit in any available container, it appears in the unpackedItems array:

{
  "results": [
    {
      "containerId": "BOX-SMALL",
      "boxIndex": 0,
      "packedItems": [ ... ],
      "unpackedItems": [
        {
          "id": "OVERSIZED-PANEL",
          "dimensions": { "length": 48, "width": 36, "height": 2 },
          "weight": 15.0
        }
      ]
    }
  ]
}

Common causes:

Container Master fallback

If you omit containers from the request (do not send the field at all), the engine loads your Container Master -- the box, pallet, and equipment definitions saved in your account. This is the recommended approach for production use.

Sending an explicit empty array "containers": [] means "no containers" and will result in a validation error. Omit the field entirely to use Container Master defaults.

Error handling

Status Cause Fix
400 No containers provided and no Container Master configured Add containers to the request or set up Container Master
400 No items in request Provide at least one item
400 Item dimensions invalid (zero or negative) Check length/width/height are positive numbers
400 Total quantity exceeds 500,000 Reduce item quantities or use batch packing

Next steps