What the fields are for, in a request that solves something.
Each scenario below is real, runnable code against the published package API — not a mock-up. The fields are the same request contract documented on every constraint page; this is what they look like put together.
Pick the cheapest box for a mixed order
An order has several item types. You have more than one box size available and want the packer to tell you what fits, and to see exactly why anything didn't.
Every container carries its own cost_minor, so a lowest_cost objective (or, here, a single candidate box) picks between them on price rather than a heuristic guess. Each unpacked item comes back with a reason instead of a silent drop.
import { pack } from '@packvium/engine';
const request = {
items: [
{ id: 'mug', quantity: 6, dimensions: { length: '120', width: '120', height: '100' }, weight: '400 g' },
{ id: 'plate', quantity: 8, dimensions: { length: '260', width: '260', height: '20' }, weight: '600 g' },
// Too long for the box in every orientation.
{ id: 'ladder', quantity: 1, dimensions: { length: '1800', width: '300', height: '100' }, weight: '6 kg' },
],
containers: [
{ id: 'box', inner_dimensions: { length: '400', width: '400', height: '400' }, max_payload: '15 kg', cost_minor: 180 },
],
};
const result = pack(request);
console.log(result.status, result.containers.length, 'container(s) opened');
for (const unpacked of result.unpacked_items) {
console.log(unpacked.item_id, unpacked.reason); // e.g. "ladder no_feasible_placement"
}status is partial: the mugs and plates place, the ladder comes back in unpacked_items with reason no_feasible_placement — an answer, not an exception to catch.
Keep a hazardous item upright, floor-only, and away from food
A shipment mixes an open container that must stay upright, a fragile item that can't be crushed by anything stacked on it, and a chemical that legally cannot travel with food.
keep_upright and must_be_on_floor restrict orientation and position per item; stackable=False and max_top_load bound what can rest above it; tags and incompatible_tags force a chemical and a food item into different containers even when there's volume to spare.
from packvium import Container, Dimensions, Item, Packer, PackingConfig
items = [
Item.create("bleach", Dimensions.mm("150", "150", "300"), weight="3 kg",
keep_upright=True, must_be_on_floor=True, tags=("hazmat",), incompatible_tags=("food",)),
Item.create("glassware", Dimensions.mm("200", "200", "250"), weight="5 kg",
stackable=False, max_top_load="0 kg"),
Item.create("flour", Dimensions.mm("300", "200", "150"), weight="2 kg", quantity=4,
tags=("food",)),
]
containers = [
Container.create("crate", Dimensions.mm("600", "500", "500"), tare_weight="3 kg", max_payload="25 kg"),
]
result = Packer(PackingConfig.balanced()).pack(items=items, containers=containers)
print(result.status, len(result.containers), "container(s) opened")The engine opens a second crate on its own: bleach and flour carry incompatible tags, so packing them together is never a candidate the search considers, regardless of how much room is left.
Fill identical crates for warehouse storage, priced per crate
One SKU, a known quantity, and more than one crate size in the catalogue. You want to know how many crates it actually takes and what that costs, not just whether the volume adds up on a spreadsheet.
quantity expands one item declaration into that many physical units for the search; tare_weight and max_payload on the container are the same two fields the request contract uses everywhere else, so switching crate sizes is a data change, not a code change.
use Packvium\Config\PackingConfig;
use Packvium\Domain\{Container, Dimensions, Item};
use Packvium\Packer;
$items = [
Item::create('bin', Dimensions::mm('300', '200', '200'), weight: '4 kg', quantity: 40),
];
$containers = [
Container::create('crate', Dimensions::mm('600', '400', '400'), tareWeight: '3 kg', maxPayload: '80 kg', costMinor: 250),
];
$result = (new Packer(PackingConfig::balanced()))->pack($items, $containers);
echo $result->status->value, ' ', count($result->containers), " crate(s)\n";The result names exactly how many crates the 40 bins need and the placements inside each one — the number to put in a quote, not an estimate to double-check by hand.
Run your own request, or read the full field list.
The playground runs a real request without installing anything. The request contract page lists every field these examples use, and the ones they don't.
Run a request ↗Read the full contract ↗