Skip to main content

Packing Optimization API

The Packing Optimization API calculates optimal 3D packing solutions for SKUs into pallets and containers using a hybrid 3-layer architecture combining rule-based systems, AI prediction, and mathematical optimization.

Overview​

The Packing API solves the 3D bin packing problem with support for:

  • Multiple pallet types: Mixed pallet sizes and specifications
  • Weight constraints: Per-pallet and per-SKU weight limits
  • Dangerous goods: Isolation and special handling
  • Stacking constraints: Non-stackable item support
  • Pre-assigned pallets: Items already packed in specific pallets
  • Unavailable pallet filtering: Exclude specific pallet types
  • Vehicle loading: Container/truck loading optimization

Architecture​

The packing service uses a unique three-layer hybrid architecture:

┌─────────────────────────────────────────────────────────┐
│ Layer 3: OR-Tools Mathematical Solver │
│ - 100% correctness guarantee │
│ - Constraint Programming (CP-SAT │
│ - Optimal or near-optimal solutions │
└─────────────────────────────────────────────────────────┘
↑
┌─────────────────────────────────────────────────────────┐
│ Layer 2: AI Prediction Model │
│ - SKU-pallet compatibility scoring │
│ - Placement sequence optimization │
│ - Pattern recognition from historical data │
└─────────────────────────────────────────────────────────┘
↑
┌─────────────────────────────────────────────────────────┐
│ Layer 1: Rule Engine │
│ - Pre-assigned pallet handling │
│ - Unavailable pallet filtering │
│ - Dangerous goods isolation │
│ - Stacking constraints │
└─────────────────────────────────────────────────────────┘

Performance Characteristics:

LayerSpeedOptimalityUse Case
Rule Engine< 50msBasicFast validation
AI Model100-500msGoodQuick solutions
OR-Tools1-30sOptimalHigh-quality results

Endpoints​

Calculate Packing​

POST /api/packing/calculate​

Calculate the optimal packing plan for a set of SKUs.

Request Body:

{
"skus": [
{
"id": "SKU-001",
"weight": 2.5,
"weight_unit": "kg",
"length": 20.0,
"width": 15.0,
"height": 10.0,
"quantity": 50,
"is_dangerous": false,
"is_stackable": true
}
],
"pallets": [
{
"id": "EUR-PALLET",
"length": 120.0,
"width": 80.0,
"height": 150.0,
"weight": 25.0,
"max_weight": 1500.0,
"cost": 8.50,
"flexible_height_ratio": 0.05
}
],
"vehicle": {
"length": 1200.0,
"width": 240.0,
"height": 260.0,
"max_weight": 24000.0,
"unit": "cm"
},
"entropy_factor": 1.0,
"pre_assigned_pallets": null,
"unavailable_pallet_types": null,
"use_ai": true,
"time_limit_ms": 30000
}

SKU Fields:

FieldTypeDefaultDescription
idstring✓Unique SKU identifier
weightfloat✓Weight of one unit
weight_unitstring"kg"Weight unit (kg, g, lb, oz)
lengthfloat✓Length dimension
widthfloat✓Width dimension
heightfloat✓Height dimension
quantityinteger1Number of units
is_dangerousbooleanfalseDangerous goods flag
is_stackablebooleantrueCan be stacked
Dimension Units

All SKU dimensions default to cm unless specified otherwise. The API automatically converts units based on unit specifications.

Pallet Fields:

FieldTypeDefaultDescription
idstring✓Pallet type identifier
lengthfloat✓Pallet length
widthfloat✓Pallet width
heightfloat✓Pallet height
weightfloat0.0Pallet tare weight
max_weightfloat✓Maximum loaded weight
length_unitstring"cm"Dimension unit
weight_unitstring"kg"Weight unit
costfloat0.0Cost per pallet use
max_heightfloatnullOptional max stack height
flexible_height_ratiofloat0.05Height tolerance ratio
Flexible Height

The flexible_height_ratio allows small height overruns. Default 5% means a ratio means items can exceed pallet height by 5% if otherwise impossible to pack.

Vehicle Fields (Optional):

FieldTypeDescription
lengthfloatVehicle interior length
widthfloatVehicle interior width
heightfloatVehicle interior height
max_weightfloatMaximum vehicle payload
unitstringDimension unit

Optimization Parameters:

ParameterTypeDefaultDescription
entropy_factorfloat1.0Solution diversity (0.8-2.0)
pre_assigned_palletsarraynullAlready packed pallets
unavailable_pallet_typesarraynullPallet types to exclude
use_aibooleantrueEnable AI enhancement
time_limit_msinteger30000Max solve time in ms

Response:

{
"pallets": [
{
"id": "pallet_1",
"pallet_type": "EUR-PALLET",
"items": [
{
"sku_id": "SKU-001",
"quantity": 45
}
],
"length": 120.0,
"width": 80.0,
"height": 140.0,
"total_weight": 112.5,
"total_volume": 135000.0,
"pallet_volume": 1440000.0,
"sku_volume": 135000.0,
"pallet_cost": 8.50,
"utilization": 0.78
}
],
"total_pallets": 2,
"total_weight": 225.0,
"total_volume": 270000.0,
"gross_weight": 275.0,
"net_weight": 225.0,
"total_items": 100,
"loaded_items": 90,
"unloaded_items": 10,
"total_sku_base_volume": 300000.0,
"volume_reduction": 0.1,
"pallet_volume": 2880000.0,
"total_cost": 17.0,
"vehicle_utilization": 0.15,
"algorithm_used": "IntelligentPacking 3-Layer Architecture",
"pallet_type_usage": {
"EUR-PALLET": 2
},
"solve_time_ms": 1523.45,
"errors": [],
"unloaded_items_detail": [
{
"sku_id": "SKU-001",
"quantity": 10,
"reason": "weight_limit_exceeded"
}
],
"success": false,
"message": "Packing complete with 10 items unloaded due to weight constraints",
"statistics": {
"weight_utilization": 0.75,
"volume_utilization": 0.78,
"pallet_efficiency": 0.92
},
"layers_used": ["rule_engine", "ai_model", "or_tools"],
"processing_time_ms": 1650.23
}

LDM (Loading Meter)​

The response now includes LDM metrics for logistics billing and vehicle floor planning.

Request Parameters

ParameterTypeDefaultDescription
ldm_widthfloatnullVehicle width in meters. Priority: explicit ldm_width > vehicle.width > 2.4
ldm_modestring"projection"Calculation mode: "projection" or "arrangement"

Response Fields

FieldTypeDescription
total_ldmfloatTotal loading meters for the solution
ldm_modestringMode used for calculation
ldm_width_usedfloatActual vehicle width used (meters)
ldmfloatPer-pallet loading meter

projection Mode

{
"total_ldm": 1.5,
"ldm_mode": "projection",
"ldm_width_used": 2.4,
"pallets": [
{
"id": "pallet_1",
"length": 120.0,
"width": 80.0,
"ldm": 0.4
}
]
}

Formula: ldm = (pallet_length_m * pallet_width_m) / ldm_width_m

arrangement Mode

{
"total_ldm": 1.2,
"ldm_mode": "arrangement",
"ldm_width_used": 2.4
}

arrangement assumes pallets are placed side-by-side along the vehicle width.

Example Request with LDM

payload = {
"skus": [...],
"pallets": [...],
"vehicle": {
"length": 1360,
"width": 244,
"height": 260,
"max_weight": 20000,
"unit": "cm"
},
"ldm_width": 2.44,
"ldm_mode": "projection"
}

Pre-Assigned Pallets​

Specify items already packed in specific pallets:

```json
\{
"skus": [...],
"pallets": [...],
"pre_assigned_pallets": [
\{
"pallet_type_id": "EUR-PALLET",
"pallet_id": "PRE-PAL-001",
"items": [
\{
"sku_id": "SKU-001",
"quantity": 10
}
],
"used_volume": 30000.0,
"used_weight": 25.0
}
]
}

The optimizer will respect these assignments and optimize around them.

Unavailable Pallet Types​

Exclude specific pallet types from consideration:

\{
"skus": [...],
"pallets": [...],
"unavailable_pallet_types": ["CHEP-PALLET", "ONE-WAY"]
}

Legacy Endpoint​

POST /api/packing/calculate/legacy​

Legacy endpoint with same interface as /calculate for backward compatibility with older clients.

Health Check​

GET /api/packing/health​

Check packing service health status.

Response:

\{
"status": "healthy",
"service": "packing",
"version": "7.0.0",
"architecture": "3-Layer Hybrid (Rule Engine + AI + OR-Tools)"
}

Error Handling​

The API returns structured errors in the errors array:

"errors": [
\{
"sku_id": "SKU-001",
"error_type": "dimension_too_large",
"message": "SKU dimensions exceed all available pallets",
"details": \{
"sku_dimensions": [200, 150, 100],
"largest_pallet": [120, 80, 150]
},
"severity": "error"
}
]

Error Types:

TypeSeverityDescription
dimension_too_largeerrorSKU larger than any pallet
weight_limit_exceededwarningCannot fit due to weight
dangerous_isolationwarningDangerous goods isolation constraint
stacking_violationwarningNon-stackable stacking violation
unloading_unsolvableerrorPacking problem infeasible

Performance Tips​

1. Start Simple​

  • Order SKUs by volume descending:
# Best packing efficiency
skus.sort(key=lambda x: x.length * x.width * x.height, reverse=True)

2. Weight Distribution​

Distribute weight evenly across pallets:

\{
"pallets": [
\{"id": "heavy", "max_weight": 2000 /* heavy items */ },
\{"id": "light", "max_weight": 500 /* light items */ }
]
}

3. Dangerous Goods Isolation​

Separate dangerous goods from regular items:

for sku in skus:
if sku.is_dangerous:
# These items get their own pallets
pass

4. Time Limit Tuning​

Adjust based on problem size:

SKU CountRecommended Time Limit
< 105000ms
10-5015000ms
50-20030000ms
> 20060000ms

Examples​

Example 1: Simple E-Commerce Order​

payload = \{
"skus": [
\{"id": "BOX-SMALL", "weight": 0.5, "length": 15, "width": 10, "height": 8, "quantity": 200},
\{"id": "BOX-MEDIUM", "weight": 2.0, "length": 30, "width": 20, "height": 15, "quantity": 50},
\{"id": "BOX-LARGE", "weight": 5.0, "length": 50, "width": 40, "height": 30, "quantity": 10}
],
"pallets": [
\{
"id": "STD", "length": 120, "width": 100, "height": 150, "max_weight": 1000, "cost": 5.0
}
],
"use_ai": True,
"time_limit_ms": 15000
}

response = requests.post("/api/packing/calculate", json=payload)

Example 2: Mixed Pallet Types​

payload = \{
"skus": [...],
"pallets": [
\{"id": "EUR", "length": 120, "width": 80, "height": 200, "max_weight": 1500, "cost": 8.0},
\{"id": "HALF", "length": 80, "width": 60, "height": 150, "max_weight": 500, "cost": 4.0},
\{"id": "INDUSTRIAL", "length": 120, "width": 100, "height": 180, "max_weight": 2000, "cost": 12.0}
]
}

Example 3: With Vehicle Loading​

payload = \{
"skus": [...],
"pallets": [...],
"vehicle": \{
"length": 1360, "width": 244, "height": 260, "max_weight": 20000, "unit": "cm"
}
}

Cost Optimization​

Minimize total cost when multiple pallet types:

# API automatically selects optimal pallet mix to minimize:
# total_cost = sum(pallet_type.cost * count)

Set appropriate costs on pallets to get cost-optimized solutions.