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
- A valid API key (see Authentication)
- Items with known dimensions and weights
- At least one container definition
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:
- Item dimensions exceed all available container dimensions
- Item weight exceeds the
maxWeightof all containers allowMultipleBoxesisfalseand items do not all fit in one box
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
- Cost-Optimized Packing -- optimize for shipping cost instead of volume
- Batch Packing -- pack hundreds of orders asynchronously
- Order to Shipment -- full lifecycle from order creation through shipment