Quick start
From API key to a packed container in three steps.
Get an API key
Create a key in your Cargo Load Planner account and keep it on your server. Every call except
get_calculation_resultsends it in theclp-api-keyheader. The Integration guide covers setup.Send a calculation
Save this as
request.json: two cartons and a 20 ft container.apply_cog: 1turns on balance-aware packing.request.json{ "multi": 0, "cal_type": "c", "apply_cog": 1, "boxes": [ { "id": 1, "name": "box-1", "dim1": 45, "dim2": 55, "dim3": 65, "dim_uom": "cm", "weight": 10, "weight_uom": "kg", "count": 1, "tilt_length": 1, "tilt_width": 1, "stacked": 1, "heavy": 0, "color": "#ff0000", "group_id": 0 }, { "id": 2, "name": "box-2", "dim1": 75, "dim2": 40, "dim3": 35, "dim_uom": "cm", "weight": 10, "weight_uom": "kg", "count": 1, "tilt_length": 1, "tilt_width": 1, "stacked": 1, "heavy": 0, "color": "#ffff00", "group_id": 0 } ], "container": { "id": 1, "name": "Standard 20 feet", "dim_uom": "cm", "x": 235, "y": 239, "z": 590, "volume": 33.2, "weight": 21770, "fs": 0, "bs": 0, "ls": 0, "rs": 0, "ts": 0 } }Then post it. Set a generous client timeout: large multi-container loads can take several seconds.
curl -X POST "https://www.cargo-load-planner.com/api/v2/calculator/calculate" \ -H "Content-Type: application/json" \ -H "clp-api-key: $CLP_API_KEY" \ -d @request.jsonimport { readFile } from "node:fs/promises"; const body = await readFile("request.json", "utf8"); const res = await fetch("https://www.cargo-load-planner.com/api/v2/calculator/calculate", { method: "POST", headers: { "Content-Type": "application/json", "clp-api-key": process.env.CLP_API_KEY, }, body, }); if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`); const plan = await res.json(); const best = plan.options.find((o) => o.id === plan.best_option_id); console.log(`${best.summary.volume_percent}% of the volume used`); console.log("balanced:", best.containers[0].cog.safe);import json, os import requests with open("request.json") as f: payload = json.load(f) res = requests.post( "https://www.cargo-load-planner.com/api/v2/calculator/calculate", headers={"clp-api-key": os.environ["CLP_API_KEY"]}, json=payload, timeout=60, ) res.raise_for_status() plan = res.json() best = next(o for o in plan["options"] if o["id"] == plan["best_option_id"]) print(f"{best['summary']['volume_percent']}% of the volume used") print("balanced:", best["containers"][0]["cog"]["safe"])using System.Text; using System.Text.Json; var http = new HttpClient { Timeout = TimeSpan.FromSeconds(60) }; http.DefaultRequestHeaders.Add("clp-api-key", Environment.GetEnvironmentVariable("CLP_API_KEY")); var body = new StringContent(await File.ReadAllTextAsync("request.json"), Encoding.UTF8, "application/json"); var res = await http.PostAsync("https://www.cargo-load-planner.com/api/v2/calculator/calculate", body); res.EnsureSuccessStatusCode(); using var plan = JsonDocument.Parse(await res.Content.ReadAsStringAsync()); var bestId = plan.RootElement.GetProperty("best_option_id").GetInt64(); foreach (var option in plan.RootElement.GetProperty("options").EnumerateArray()) { if (option.GetProperty("id").GetInt64() != bestId) continue; Console.WriteLine($"{option.GetProperty("summary").GetProperty("volume_percent")}% of the volume used"); Console.WriteLine($"balanced: {option.GetProperty("containers")[0].GetProperty("cog").GetProperty("safe")}"); }Read the result
You get one option back, with a container for each one used.
- best_option_idWhich entry of
optionswon. Look it up byid; it is not always 0. - containers[].itemsWhere every piece sits:
locx,locy,loczanddimx,dimy,dimz, in millimetres. - unallocatedProducts that did not fit, as
idandqty. - summaryHow full the container is:
volume_percentandweight_percent. - cog.safeWhether the centre of gravity is inside its limits.
warningssays why not. - suggestions[].applyA patch to merge into your request for a better result.
Response (abridged){ "version": "2.0", "status": "success", "description": "", "unique_id": "5b1f0d7e-2c3a-4e7b-9a61-8f4d2c6e1b90", "multi": 0, "cal_type": "c", "best_option_id": 2, "container": { "id": 1, "name": "Standard 20 feet", "dim_uom": "cm", "x": 235, "y": 239, "z": 590, "volume": 33.2, "weight": 21770, "fs": 0, "bs": 0, "ls": 0, "rs": 0, "ts": 0 }, "options": [ { "id": 2, "containers": [ { "id": 1, "items": [ { "sno": 1, "id": 1, "name": "box-1", "dim1": 450, "dim2": 550, "dim3": 650, "weight": 10000, "volume": 160875000, "count": 1, "tilt_length": 1, "tilt_width": 1, "stacked": 1, "locx": 0, "locy": 0, "locz": 0, "dimx": 650, "dimy": 550, "dimz": 450, "packsno": 1, "option_id": 2, "pallet_id": 1, "color": "#ff0000", "heavy": 0, "group_id": 0, "bearing_kg": 0, "stack_level": 1 }, { "sno": 2, "id": 2, "name": "box-2", "dim1": 750, "dim2": 400, "dim3": 350, "weight": 10000, "volume": 105000000, "count": 1, "tilt_length": 1, "tilt_width": 1, "stacked": 1, "locx": 650, "locy": 0, "locz": 0, "dimx": 750, "dimy": 350, "dimz": 400, "packsno": 2, "option_id": 2, "pallet_id": 1, "color": "#ffff00", "heavy": 0, "group_id": 0, "bearing_kg": 0, "stack_level": 1 } ], "summary": { "max_weight": 21770000, "max_volume": 33200000000, "packed_weight": 20000, "weight_percent": 0.09, "packed_volume": 265875000, "volume_percent": 0.80 }, "cog": { "x": 67.5, "y": 22.5, "z": 21.25, "totalWeight": 20.0, "xPercent": 28.723404255319153, "yPercent": 9.414225941422593, "zPercent": 3.6016949152542375, "xSafe": false, "ySafe": true, "zSafe": false, "safe": false, "warnings": [ { "severity": "WARNING", "message": "The load is heavier on the left (28.7% across the width)." }, { "severity": "WARNING", "message": "The load sits too far toward the closed end (3.6% along the length)." } ] }, "axle_loads": null, "loading": { "requested": 0, "floor_first": true, "volume_at_weight_limit_percent": 0.8, "reason": "auto: weight limit reached at 1% of volume (below 50%), floor first", "mode_used": "floor_first" }, "delivery_groups": null } ], "summary": { "max_weight": 21770000, "max_volume": 33200000000, "packed_weight": 20000, "weight_percent": 0.09, "packed_volume": 265875000, "volume_percent": 0.80 }, "unallocated": [] } ], "suggestions": [ { "code": "PLACEMENT_POLICY", "severity": "recommend", "scope": "calculation", "container_id": null, "message": "In 1 container(s) the load sits against the closed end with its centre of gravity outside the band along the length; 'centred' placement brings 1 of them into the band.", "apply": { "placement_policy": "centred" }, "requires": null, "expected": { "c1_cog_z_percent": 50.0, "c1_z_safe": true }, "expected_summary": "The load lands at 50.0% along the length, inside the band." }, { "code": "ADD_VEHICLE", "severity": "info", "scope": "calculation", "container_id": null, "message": "CoG along the length is judged by a fixed band. With a vehicle profile the engine computes axle loads and the exact window the load must sit in.", "apply": null, "requires": "vehicle", "expected": null, "expected_summary": null } ] }voids,axleandplacementare left out.axle_loadsanddelivery_groupsarenullbecause the request had no vehicle and nogroup_idvalues. Here the load sits against the back wall, so the response flags the centre of gravity and suggestsplacement_policy: "centred". Merge thatapplypatch into your request and call again.- best_option_idWhich entry of
Authentication
Send your key in the clp-api-key header, and Content-Type: application/json on POST requests. get_calculation_result is the one call that takes no key: the calculation id is the access token, so share it only where you would share the result.
clp-api-key: YOUR_API_KEY- A missing, invalid or expired key, an inactive subscription, or a used-up API allowance all return
401with the bodyUnauthorized. - Every calculation is saved and counts toward your plan's API allowance.
Units and coordinates
Requests use the units you declare. Responses always use millimetres and grams.
dim_uom is read as millimetres and an unknown weight_uom as grams, so m, ft or CM quietly gives you sizes or weights that are 10 to 1000 times too small. Use exactly: mm, cm, meter, inch, feet, yard and kg, gm, lb, all lowercase.| Where | Unit | Notes |
|---|---|---|
| boxes[].dim1, dim2, dim3 | mm, cm, meter, inch, feet, yard | Set by dim_uom. Whole numbers only: for 45.5 cm send 455 with mm. |
| boxes[].weight | kg, gm, lb | Set by weight_uom. Weight of one unit. |
| container.x, y, z | same as container.dim_uom | x is the width, y the height and z the length. |
| container.volume | m³ | Usable volume. |
| container.weight | kg | Maximum payload. |
| container.fs, bs, ls, rs, ts | mm | Clearance kept at the front, back, left, right and top. Always millimetres. |
| items[]: loc*, dim* | mm | locx, locy, locz, dimx, dimy, dimz, and the echoed dim1–dim3. |
| weights in the response | grams | items[].weight, summary.packed_weight, summary.max_weight. |
| volumes in the response | mm³ | items[].volume, summary.packed_volume, summary.max_volume. |
| *_percent | percent, 0–100 | 0.09 means 0.09 %, not 9 %. |
| cog.x, y, z | cm | cog.totalWeight is in kg. |
| bearing_kg, weight_kg, axle_loads | kg | Reports that already use kilograms. |
Coordinates
The origin is the back-left-floor corner of the container. X runs left to right across the width, Y runs up, and Z runs from the closed back wall to the doors. The diagram at the top of this page uses the same axes. Each item's locx, locy, locz is its corner nearest the origin, and dimx, dimy, dimz is its size after rotation.
In the request, a package's dim1, dim2, dim3 are its length, width and height, while a container's x, y, z are its width, height and length. Note that z is the long side.
Endpoints
Every path below is relative to the base URL.
https://www.cargo-load-planner.com/api/v2/calculator| Endpoint | What it does | Key |
|---|---|---|
| POST /calculate | Packs your cargo and reports balance, fill and suggestions. | Required |
| GET /get_calculation_result/{id} | Fetches a saved calculation: request and result. | Not needed |
| GET /placement_info/{id} | Fetches the placement report as Base64. | Required |
POST /calculate
Packs the products in boxes into the container and returns every placement, the fill figures, the centre of gravity and suggestions.
- Every call is saved. The
unique_idin the response identifies it for the two GET endpoints. - With
multi: 0everything goes into one container and what does not fit is listed inunallocated. Withmulti: 1more containers of the same type are added until all cargo is loaded.
GET /get_calculation_result/{calculation_id}
Returns a saved calculation as { "output", "input" }: the v2 result and the request exactly as saved.
- When the calculation was submitted in
cm,output.containeris returned inmm(dim_uom: "mm"). - An unknown id returns
400with the textNo such calculation exist.If the account behind the calculation has no valid subscription, it returns401.
GET /placement_info/{calculation_id}
Returns the placement report for a saved calculation as a Base64 string. Decode it to get the report file.
- Failures do not use an error status. A bad key, an unknown id or a report that cannot be built all return
200with an empty body, so check for an empty string.
Request body
One JSON object. Everything except the fields marked required is optional.
Top-level fields
| Field | Type | Description |
|---|---|---|
| cal_type required | string | c packs into a container, p onto a pallet. Anything other than c is treated as p. |
| boxes required | array | The products to load. See boxes. |
| container required | object | The container or pallet. See container. |
| multi | 0 | 1 | 0 uses one container and lists what does not fit. 1 adds containers until everything is loaded. Default 0. |
| apply_cog | 0 | 1 | 1 packs for balance. See Balance options. Default 0. |
| placement_policy | string | compact (default), centred or spread. Needs apply_cog: 1. |
| spread_allow_end_gaps | boolean | With spread, allow gaps at the back wall and the doors. Default false. |
| cog_limits | object | Safe range for the centre of gravity. See Balance options. |
| vehicle | object | Adds axle loads and a vehicle-derived length limit. |
| loading_mode | string | auto (default), floor_first or stack. See Loading and stacking. |
| stack_same_footprint_only | boolean | A box may only rest inside the footprint of what carries it. |
| max_floor_load_kg_per_m2 | number | Floor load limit, checked under every stack. 0 means no limit. |
| constraints_override | object | Fine-tuning of engine settings. All fields optional. |
boxes
One object per product.
Product and size
| Field | Type | Description |
|---|---|---|
| id required | integer | Unique id of the product. Responses refer to it in unallocated. |
| name | string | Label for the product. |
| dim1 required | integer | Length. |
| dim2 required | integer | Width. |
| dim3 required | integer | Height. |
| dim_uom required | string | mm, cm, meter, inch, feet or yard. |
| weight required | number | Weight of one unit. |
| weight_uom required | string | kg, gm or lb. |
| count required | integer | Quantity. |
| color | string | Colour such as #ff0000. Returned unchanged. |
| group_id | integer | Delivery stop. The lowest stop is loaded nearest the doors; 0 means no stop and sits at the back. Default 0. |
Orientation and stacking
| Field | Type | Description |
|---|---|---|
| tilt_length | 0 | 1 | 1 lets the packer tip the package around its length, 0 does not. Default 1. |
| tilt_width | 0 | 1 | 1 lets the packer tip the package around its width, 0 does not. Default 1. |
| stacked | 0 | 1 | 1 allows other packages on top, 0 means nothing on top. Default 1. |
| heavy | 0 | 1 | 1 keeps the package on the floor. Default 0. |
Stacking rules
Optional. Left out, a product behaves as before.
| Field | Type | Description |
|---|---|---|
| max_load_on_top_kg | number | Load the package can carry. 0 means nothing on top. Omit for no limit. |
| self_stack_only | boolean | Only the same product may rest on it. |
| max_self_stack | integer | Most units of this product stacked, counting itself. 0 means unlimited. |
| max_self_stack_height_mm | integer | The same limit as a height in mm. 0 means unlimited. |
| bottom_only | boolean | Floor only. Same as heavy: 1. |
| top_only | boolean | Carries nothing and is packed after everything else. |
| keep_upright | boolean | No tipping. Same as tilt_length: 0 and tilt_width: 0. |
| min_support_percent | number | Share of its footprint that must rest on what is below. Default from constraints_override, else 50. |
container
| Field | Type | Description |
|---|---|---|
| id required | integer | Id of the container. |
| name required | string | Label for the container. |
| dim_uom required | string | mm, cm, meter, inch, feet or yard. |
| x required | integer | Width. |
| y required | integer | Height. |
| z required | integer | Length. |
| volume required | number | Usable volume in m³. |
| weight required | number | Maximum payload in kg. |
| fs | integer | Clear space kept at the front, in mm. Default 0. |
| bs | integer | Clear space kept at the back, in mm. |
| ls | integer | Clear space kept on the left, in mm. |
| rs | integer | Clear space kept on the right, in mm. |
| ts | integer | Headroom kept above the load, in mm. |
For a pallet (cal_type: "p") describe the pallet in the same object.
Balance options
With apply_cog: 1 the packer prefers a low centre of gravity, applies placement_policy, mirrors groups of boxes sideways to level the width, and among equally good packings picks one that is safe. The cog report is in every response either way.
cog_limits
| Field | Type | Description |
|---|---|---|
| xMin, xMax | number | Safe range for the centre of gravity across the width, as a percent of the width (0 is the left wall). Defaults 40 and 60. |
| yBest | number | Height percent at or below which the load is ideal. Default 40. |
| yAcceptable | number | Above yBest and up to this value the load is safe but raises a CAUTION. Above it is CRITICAL. Default 60. |
| zMin, zMax | number | Safe range along the length, as a percent of the length (0 is the back wall, 100 the doors). Defaults 40 and 60. |
Every field is optional and keeps its default when left out.
placement_policy
Where the finished load sits along the length. It only moves whole groups of boxes, so nothing inside a group changes.
spread_allow_end_gaps is true.vehicle: axle loads
Send a vehicle and each container comes back with per-axle loads in axle_loads, and the length limit is derived from the axle limits instead of cog_limits.zMin and zMax. Positions are millimetres along the vehicle from the back wall of the cargo space, positive toward the doors. Anything ahead of the cargo, such as a steering axle or kingpin, is negative.
| Field | Type | Description |
|---|---|---|
| id, name | integer, string | Identify the vehicle. |
| type | string | rigid or tractor_semi. |
| axles | array | Axle groups: name, role (steering, drive or trailer), position_mm, tare_kg and max_kg. |
| kingpin_position_mm | integer | tractor_semi only. Usually negative. |
| tractor_front_share | number | tractor_semi only. Share of the kingpin load that reaches the steering axle, typically 0.10–0.25. Default 0.15. |
| body_tare_kg, body_cog_position_mm | number, integer | Weight of a body or chassis that is not already in the axle tares, and where it acts. |
| gross_max_kg | number | Legal gross vehicle weight. |
| min_steering_share_percent | number | Least share of the load on the steering axle. Default 20. |
{
"vehicle": {
"id": 1,
"name": "18 t rigid",
"type": "rigid",
"axles": [
{
"name": "Front",
"role": "steering",
"position_mm": -800,
"tare_kg": 3300,
"max_kg": 7500
},
{
"name": "Rear",
"role": "drive",
"position_mm": 5000,
"tare_kg": 2500,
"max_kg": 11500
}
],
"gross_max_kg": 18000
}
}Loading and stacking options
| loading_mode | Behaviour |
|---|---|
| auto | Floor-first when the payload limit would be reached below floor_first_threshold_percent of the volume, so heavy cargo. Otherwise stack. Decided per container. |
| floor_first | One layer across the whole floor first. Boxes are stacked only when the floor is full. |
| stack | Walls are packed to full height. |
constraints_override: engine settings
Every field is optional.
| Field | Type | Description |
|---|---|---|
| x_balance_enabled | boolean | Mirror groups of boxes sideways to move the centre of gravity toward the middle. Default true. |
| x_balance_only_outside_band | boolean | Only mirror when the width balance is outside its band. Default false. |
| x_balance_min_gain_percent | number | Skip a mirror that would improve balance by less than this. Default 1. |
| min_reported_gap_mm | integer | Gaps shorter than this are not reported as filler positions. Default 50. |
| min_reported_side_gap_mm | integer | Side gaps narrower than this are not reported as filler positions. Default 150. |
| min_spread_free_length_mm | integer | spread is skipped when the free length is below this. Default 500. |
| min_support_percent | number | Default footprint support for stacked boxes, 0–100. Default 50. |
| floor_first_threshold_percent | number | auto loading switches to floor-first below this volume percent, 0–100. Default 50. |
Response body
The result of /calculate, and output in /get_calculation_result.
response ├─ status, description, unique_id, best_option_id top level ├─ container the container you sent ├─ options[] one entry: the winner │ ├─ summary, unallocated[] │ └─ containers[] │ ├─ items[] where each piece sits │ ├─ summary fill for this container │ ├─ cog balance report │ └─ loading, axle_loads, voids, delivery_groups, placement, axle ├─ selection how the option was chosen └─ suggestions[] what to change, with a patch
Top level
| Field | Type | Description |
|---|---|---|
| version | string | "2.0". |
| status | string | success or failed. A failed status still comes with HTTP 200. See Errors. |
| description | string | Empty on success. On failure, what was wrong. |
| unique_id | string | Id of the saved calculation. Use it with the GET endpoints. |
| multi, cal_type | number, string | Echo of your request. |
| best_option_id | integer | Id of the winning option. |
| container | object | The container you sent. |
| options | array | See options and containers. |
| selection | object | null | How the option was chosen. See Other reports. |
| suggestions | array | See Suggestions. |
Options and containers
In practice options has one entry: the winning packing. It holds a container for each one used.
| Field | Type | Description |
|---|---|---|
| id | integer | Equals best_option_id. |
| containers | array | One entry per container used. id starts at 1. |
| summary | object | Totals across all containers. |
| unallocated | array | Products that did not fit: id and qty. |
summary
| Field | Type | Description |
|---|---|---|
| max_weight, max_volume | number | Capacity in grams and mm³. |
| packed_weight, packed_volume | number | Loaded amount in grams and mm³. |
| weight_percent, volume_percent | number | Fill as a percent, 0–100. |
items
Every placed piece. The positions are final: when a placement policy moved the load, the coordinates already include it.
| Field | Type | Description |
|---|---|---|
| sno | integer | Serial number of the placed piece. |
| id, name | integer, string | The product this piece belongs to. |
| dim1, dim2, dim3 | integer | Length, width and height in mm as you sent them. |
| weight | number | Weight in grams. |
| volume | number | Volume in mm³. |
| count | integer | Quantity this row stands for. Each row is one placed piece. |
| tilt_length, tilt_width, stacked, heavy, group_id, color | Echo of the product settings. | |
| locx, locy, locz | integer | Position of the corner nearest the origin, in mm. |
| dimx, dimy, dimz | integer | Size along X, Y and Z after rotation, in mm. |
| packsno | integer | Loading order. |
| option_id, pallet_id | integer | The option and container this piece is in. pallet_id is the container id. |
| bearing_kg | number | Weight the piece carries, in kg. |
| stack_level | integer | 1 is the floor. |
cog
Present on every container, whether or not apply_cog is on. Limits come from cog_limits, or the defaults.
| Field | Type | Description |
|---|---|---|
| x, y, z | number | Centre of gravity in cm from the origin. |
| totalWeight | number | Total cargo weight in kg. |
| xPercent, yPercent, zPercent | number | Position as a percent of the container width, height and length. |
| xSafe, ySafe, zSafe | boolean | Each axis against its limits. |
| safe | boolean | true when all three are safe. |
| warnings | array | severity (WARNING, CAUTION or CRITICAL) and message. |
Other container reports
Each container also carries these. Reports that do not apply are null.
loading
| Field | Type | Description |
|---|---|---|
| requested | number | 0 auto, 1 floor_first, 2 stack. |
| mode_used | string | floor_first or stack, the mode actually used for this container. |
| floor_first | boolean | Whether the container was floor-first. |
| volume_at_weight_limit_percent | number | Share of the volume the cargo would fill when the payload limit is reached. |
| reason | string | Why the mode was chosen. |
axle_loads: per-axle loads (null without a vehicle)
| Field | Type | Description |
|---|---|---|
| vehicle_name, vehicle_type | string | From your vehicle. |
| cargo_kg, cog_z_mm, cog_z_percent | number | Cargo weight and where its centre sits along the length. |
| groups[] | array | Per axle group: name, role, position_mm, tare_kg, body_kg, cargo_kg, load_kg, max_kg, percent_of_max, ok. |
| gross_kg, gross_max_kg | number | Total weight and its limit. |
| steering_share_percent, min_steering_share_percent | number | Load on the steering axle and its minimum. |
| ok, warnings | boolean, array | Overall result and the reasons for any failure. |
| window | object | The centre-of-gravity range that keeps every axle legal: feasible, z_min_mm, z_max_mm, z_min_percent, z_max_percent, limiting_low, limiting_high, note. |
voids: empty space and filler positions
| Field | Type | Description |
|---|---|---|
| container_volume, packed_volume, total_void_volume, reported_void_volume | number | In mm³. |
| free_length_mm | integer | Length not taken up by loaded groups. |
| components[] | array | Groups of boxes that can move as a unit: index, z_min, z_max, x_min, x_max, y_max, width, length, weight, packed_volume, packsnos, cog_x, cog_z, mirrored. |
| voids[] | array | Empty space: type_name (BACK_GAP, BETWEEN_GAP, FRONT_GAP, SIDE, TOP, INTERNAL), position and size in mm, volume, needs_filler and recommendation. |
| fillers[] | array | The voids that need filler, in order along the length. |
Sizes are in mm. axle is a legacy quarter-length summary kept for existing clients.
delivery_groups: unloading order (null without group_id values)
| Field | Type | Description |
|---|---|---|
| groups[] | array | Per stop: group_id, sequence (1 is unloaded first), boxes, weight_kg, z_min, z_max, intruders. |
| in_delivery_order | boolean | The lowest stop is nearest the doors. |
| contiguous | boolean | No stop's boxes sit inside another stop's length. |
| note | string | A one-line summary. |
placement: what the placement policy did
| Field | Type | Description |
|---|---|---|
| policy, applied, note | string, boolean | The policy used and whether it moved anything. |
| shift_mm, gaps_mm, free_length_mm | number, array | What centred or spread did. |
| cog_z_before_percent, cog_z_after_percent, target_z_percent, z_in_band_after | number, boolean | Length balance before and after. |
| z_band_source, z_band_min_percent, z_band_max_percent, z_band_note | string, number | The band used. vehicle when derived from axle limits. |
| x_applied, x_note, mirrored_components | boolean, string, array | Sideways mirroring. |
| cog_x_before_percent, cog_x_after_percent, target_x_percent, x_in_band_after | number, boolean | Width balance before and after. |
Present when apply_cog is 1 and either placement_policy is not compact or sideways balancing is on.
selection: how the option was chosen
| Field | Type | Description |
|---|---|---|
| applied | boolean | true when the balance check changed the choice. |
| evaluated | boolean | false when apply_cog was off or there was a single option. |
| ranked_option_id, chosen_option_id | integer | The winner before and after the balance check. |
| reason | string | Why. |
| candidates[] | array | option_id, rank, safe, violation and warnings for each equivalent option. |
suggestions
Each suggestion carries an apply patch. Merge it into the request you sent and call again. Merge constraints_override field by field.
| Field | Type | Description |
|---|---|---|
| code | string | One of the codes below. |
| severity | string | recommend or info. |
| scope, container_id | string, integer | calculation or container, and which container. |
| message | string | What is wrong, in one sentence. |
| apply | object | null | Fields to merge into your request. null when you must supply data. |
| requires | string | null | What to add when apply is null. |
| expected, expected_summary | object, string | Outcome of a trial run, when one was made. Only for PLACEMENT_POLICY. |
Codes
| code | Meaning |
|---|---|
| ENABLE_COG | apply_cog is off. Patch: { "apply_cog": 1 }. |
| LOADING_MODE_FLOOR_FIRST | Weight-bound containers were packed in stacks. Patch: { "loading_mode": "floor_first" }. |
| PLACEMENT_POLICY | The load sits at the closed end and centred or spread would bring it into the band. Trial-run, so expected holds real numbers. |
| ADD_VEHICLE | Length balance is judged by a fixed band. Send a vehicle for axle loads. apply is null, requires is vehicle. |
| RELAX_SUPPORT_PERCENT | Products are unallocated under a support requirement above 50 %. Patch: { "constraints_override": { "min_support_percent": 50 } }. |
Errors
| Status | Meaning |
|---|---|
| 200 | The call ran. Check status: failed means the input was rejected, and description says why. |
| 400 | A field has the wrong type, the calculation threw, or the calculation id does not exist. The body is JSON for a wrong type and plain text otherwise. |
| 401 | The key is missing, invalid or expired, the subscription is inactive, or the API allowance is used up. The body is Unauthorized. |
| 415 | A POST without Content-Type: application/json. |
Rejected input
Invalid dimensions : Item ids (3). means a product cannot fit the container in any allowed rotation, after the clearances fs, bs, ls, rs and ts are taken off. Check the units first, then whether tilt_length and tilt_width forbid the rotation it needs.
{
"version": "2.0",
"status": "failed",
"description": "Invalid dimensions : Item ids (3).",
"unique_id": "5b1f0d7e-2c3a-4e7b-9a61-8f4d2c6e1b90",
"multi": 0,
"cal_type": "c",
"best_option_id": 0,
"container": {
"id": 1,
"name": "Standard 20 feet",
"dim_uom": "cm",
"x": 235,
"y": 239,
"z": 590,
"volume": 33.2,
"weight": 21770,
"fs": 0,
"bs": 0,
"ls": 0,
"rs": 0,
"ts": 0
},
"options": [],
"selection": null,
"suggestions": []
}Wrong field types
Sizes and counts are whole numbers, so "dim1": 45.5 is rejected. The response lists the field path. Text abridged.
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"$.boxes[0].dim1": [
"The JSON value could not be converted to System.Int64. Path: $.boxes[0].dim1 | LineNumber: 6 | BytePositionInLine: 20."
]
}
}