Complete Dynamics 365 Finance & Operations Integration Guide

CubeMaster API Integration Guide

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.

A. Master Data: Released Products V2 Entity
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.
B. Transactional Data: Sales Order Lines vs. Load Lines
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.

Different shipping requirements dictate how you format the JSON payload.

Scenario 1: Simple E-Commerce Parcel Packing (Cartonization)

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
  }
}
Scenario 2: Heavy Machinery Trailer Load (Weight Restricted)

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"
  }
}
Scenario 3: Multi-Tier Palletization

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();
    }
}

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>