Using Microsoft Dynamics 365 Finance & Operations (OData & X++)
Building the CubeMaster payload requires joining Master Data (for dimensions and weights) with Transactional Data (for order quantities). The transactional entity you choose depends on your D365 warehouse setup.
| D365 Entity: ReleasedProductsV2 | CubeMaster Key | Notes |
|---|---|---|
ItemNumber |
name |
The unique SKU identifier for the cargo. |
PhysicalLength, PhysicalWidth, PhysicalHeight |
length, width, height |
Ensure the D365 Unit of Measure matches the API request (e.g., ?UOM=UnitMetric or ?UOM=UnitEnglish). |
GrossWeight |
weight |
Used to calculate max capacity limits. |
PackingGroupId (Custom Extension) |
style |
Maps to CubeMaster styles like Shipcase, Pallet, or Cylinder. |
| Scenario | D365 Entity | CubeMaster Mapping | Use Case |
|---|---|---|---|
| Standard Operations | SalesOrderLinesV2 |
Map SalesQty to qty. |
Used for simple pack-station cartonization before shipping. Predicts how many standard UPS/FedEx boxes to pull. |
| Advanced Warehouse (WMS) | WarehousingLoadLines |
Map Quantity to qty. |
Used for truckload or ocean container planning. The "Load" is generated first, and you calculate trailer utilization. |
For accurate 3D load planning, physical dimensions aren't always enough. You must pass constraints to tell CubeMaster how items can be stacked. While F&O has some native warehouse fields, you may need to map these to Item Groups or Custom Fields.
| D365 F&O Suggested Mapping | CubeMaster Field | Purpose & Behavior |
|---|---|---|
WHSInventTable.FilterCode |
cargoes[].stackingGroup |
Groups similar items. Items with different stacking group IDs will not be stacked on top of each other. |
InventTable.ItemType (or Custom Field) |
rules.isSafeStackingUsed |
Boolean (True/False). Prevents heavier items from being placed on top of lighter/fragile items. |
WHSLoadMixGroup |
rules.fillDirection |
Dictates how the container is filled (e.g., "FrontToRear", "BottomToTop"). |
WHSLoadTable.WeightLimit |
rules.isWeightLimited |
Boolean. Forces the API to respect the maxWeight defined on the container object. |
Released products table to capture XYZ rotational rules for CubeMaster.
Different shipping requirements dictate how you format the JSON payload.
Goal: Find the smallest possible standard shipping boxes for a multi-item sales order.
{
"title": "Sales Order SO-10023",
"cargoes": [
{ "name": "SKU-A", "length": 5.0, "width": 5.0, "height": 5.0, "weight": 1.0, "qty": 3 },
{ "name": "SKU-B", "length": 10.0, "width": 2.0, "height": 2.0, "weight": 0.5, "qty": 1 }
],
"containers": [
{ "name": "FedEx Small", "length": 12.0, "width": 10.0, "height": 8.0, "containerType": "Carton" },
{ "name": "FedEx Medium", "length": 15.0, "width": 11.0, "height": 11.0, "containerType": "Carton" }
],
"rules": {
"algorithmType": "Optimization",
"isWeightLimited": false
}
}
Goal: Load heavy items onto a flatbed where weight limits and axle distribution are more critical than volume.
{
"title": "Load LD-99482 (WMS)",
"cargoes": [
{ "name": "Engine-Block", "length": 48.0, "width": 40.0, "height": 36.0, "weight": 1200.0, "qty": 15, "style": "Pallet" }
],
"containers": [
{
"name": "53ft Standard Trailer",
"length": 636.0,
"width": 102.0,
"height": 110.0,
"maxWeight": 45000.0,
"containerType": "Truck"
}
],
"rules": {
"algorithmType": "Optimization",
"isWeightLimited": true,
"fillDirection": "BottomToTop"
}
}
Goal: First pack items onto wooden pallets, then pack those pallets into a Sea Container.
{
"title": "Export Order EX-001",
"cargoes": [
{ "name": "RetailBox", "length": 12.0, "width": 12.0, "height": 12.0, "weight": 10.0, "qty": 200, "style": "Shipcase" }
],
"containers": [
{
"name": "Standard Wood Pallet",
"length": 48.0,
"width": 40.0,
"height": 60.0,
"emptyWeight": 40.0,
"maxWeight": 2000.0,
"containerType": "Pallet"
}
],
"rules": {
"algorithmType": "Palletization",
"isSafeStackingUsed": true
}
}
Use a C# integration layer (such as an Azure Function or D365 Custom Service) to execute the API. Ensure you include graphicsCreated=true in your endpoint URL to generate the 3D images.
using System.Net.Http;
using System.Text;
using Newtonsoft.Json;
using System.Threading.Tasks;
public async Task<string> ExecuteCubeMasterLoad(object requestBody)
{
using (var client = new HttpClient())
{
// Add your TokenID generated from CubeMaster Settings -> Integration
client.DefaultRequestHeaders.Add("TokenID", "YOUR_CUBEMASTER_API_KEY");
var json = JsonConvert.SerializeObject(requestBody);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// Request English units and 3D Graphic generation
string endpoint = "https://api.cubemaster.net/loads?UOM=UnitEnglish&graphicsCreated=true";
var response = await client.PostAsync(endpoint, content);
return await response.Content.ReadAsStringAsync();
}
}
filledContainers array in the JSON response. Map volumeUtilization back to a custom "Optimization Summary" tab on the D365 Load record, and attach the generated 3D visual URL to the DocuRef (Document Handling) table linked to that Load.
When the calculation succeeds, CubeMaster returns a URL in graphics.images[0]. Rather than just saving this as a text link, you can use an Extensible Control (HTML/JS) to render the graphic directly inside a Dynamics 365 form or custom workspace.
<!-- D365 HTML Host Container -->
<div id="cubemaster-3d-viewer" style="width: 100%; min-height: 400px; background: #fff; padding: 10px;">
<!-- The iframe will be injected here via JavaScript -->
</div>
<script>
/**
* Renders the CubeMaster 3D graphic inside the D365 form container
* @param {string} imageUrl - The URL from response.filledContainers[0].graphics.images[0]
*/
function renderCubeMasterGraphics(imageUrl) {
const viewerContainer = document.getElementById('cubemaster-3d-viewer');
if (imageUrl) {
// Render as an iframe inside the container
viewerContainer.innerHTML = `
<div style="border: 1px solid #e0e0e0; border-radius: 8px; overflow: hidden; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
<iframe
src="${imageUrl}"
width="100%"
height="450px"
style="border: none;"
title="CubeMaster 3D Load Plan">
</iframe>
</div>
`;
} else {
viewerContainer.innerHTML = `
<div style="padding: 20px; text-align: center; color: #666; border: 1px dashed #ccc;">
<p>No 3D graphics available or calculation pending.</p>
</div>
`;
}
}
// Example: Called via D365 Form Script when a Load is selected
// const apiResponseUrl = "https://api.cubemaster.net/graphics/container1.png";
// renderCubeMasterGraphics(apiResponseUrl);
</script>