Using IFS Applications (PL/SQL & REST)
To use the CubeMaster API, you need an API key (called a TokenID) for authentication. Here's how to get started:
TokenID (e.g., abc123xyz789).Note: The TokenID is used in the HTTP request header for every API call. It identifies your account and controls access. Unlike standard OAuth, CubeMaster uses a custom TokenID header key — not Bearer or Authorization.
TokenID: YOUR_API_KEY_HERE
Content-Type: application/json
A RESTful API (Representational State Transfer) is a standardized way for software systems to communicate over the internet using the same HTTP protocol your browser uses to load web pages. Think of it like a restaurant menu: your IFS system is the customer placing an order (the request), and CubeMaster is the kitchen that prepares and returns the result (the response).
HTTP methods tell the server what action to perform:
In this guide, we exclusively use the POST method to submit a cargo-and-container request and receive an optimized load plan back.
| Property | Value |
|---|---|
| Endpoint URL | https://api.cubemaster.net/loads |
| Method | POST |
| Content-Type | application/json |
| Authentication | TokenID: <your_api_key> (HTTP header) |
| API Version | V2 (used in this guide) |
| Swagger / Interactive Docs | https://api.cubemaster.net/index.html |
These optional parameters can be appended to the URL to control the output:
| Parameter | Values | Description |
|---|---|---|
loadSaved | true / false | When true, the resulting load plan is saved to your CubeMaster account cloud database for later review. |
graphicsCreated | true / false | When true, 3D and composite diagram images are generated and their URLs are returned in the response. |
UOM | UnitMetric / UnitEnglish | Forces a specific unit of measure for all dimensions and weights in this request. Overrides account-level defaults. |
Example full URL:
https://api.cubemaster.net/loads?loadSaved=true&graphicsCreated=true&UOM=UnitMetric
Before configuring IFS, ensure the following conditions are met in your environment:
| Requirement | Details |
|---|---|
| CubeMaster API Key | A valid TokenID from your CubeMaster account (see Step 1). An active subscription plan with API access is required. |
| IFS Solution Manager Access | You must have administrative rights in IFS Solution Manager to create Routing Addresses, Routing Rules, and Custom Events. |
| IFS Connect License | The IFS Connect module must be licensed and active in your IFS 9 installation. |
| PL/SQL Execution Rights | The database account used by IFS Custom Events must have EXECUTE privileges on Plsql_Rest_Sender_API and the ability to query customer_order_line and part_catalog_pub. |
The IFS Application Server (or the middleware component executing PL/SQL REST calls) must be allowed to make outbound HTTPS connections on port 443 to the following hosts:
api.cubemaster.net — the API endpoint for submitting load requests.cubemaster.net — if using the Swagger interactive documentation for testing.Work with your network/security team to whitelist these domains in your corporate firewall and any proxy servers. If your IFS server routes outbound traffic through a proxy, the Plsql_Rest_Sender_API call or your IFS Connect routing address may need to be configured with the proxy host and port.
CubeMaster requires accurate physical dimensions (length, width, height) and weight for every cargo item. Before enabling this integration in production:
part_catalog_pub (or your custom dimension table) have non-null length, width, height, and weight values.UOM parameter you will send to the API.calculationError field of the response.IFS Connect is the native enterprise integration broker built into IFS Applications. A Routing Address defines the external target endpoint (CubeMaster API) that IFS Connect will forward messages to.
Fill in the fields as shown below:
| Field | Value | Notes |
|---|---|---|
| Address Name | CUBEMASTER_API_POST |
This identifier is referenced in your PL/SQL code. Use uppercase with underscores. |
| Description | CubeMaster Load Optimization REST API |
Optional but helpful for documentation. |
| Transport Connector | HTTP |
Select the built-in HTTP/HTTPS connector. |
| URL | https://api.cubemaster.net/loads?loadSaved=true&graphicsCreated=true |
Append &UOM=UnitMetric if your dimensions are in centimeters/kilograms. |
| Method | POST |
Must be POST. The API does not support GET for creating load plans. |
| Retry Count | 3 |
Recommended: allow up to 3 retries on transient network errors. |
| Timeout (seconds) | 60 |
CubeMaster optimization can take several seconds for large loads. 60 seconds is a safe default. |
In the HTTP Header block of the Routing Address form, add the following two headers. These are sent with every outbound request:
TokenID: YOUR_API_KEY_HERE
Content-Type: application/json
TokenID as the header key — not Authorization: Bearer. Using a standard OAuth Bearer token format will result in a 401 Unauthorized error.
api.cubemaster.net.curl -X POST https://api.cubemaster.net/loads \
-H "TokenID: YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{"title":"test","cargoes":[],"emptyContainers":[]}'
200 OK or a validation error JSON response confirms the server can reach the API. A connection timeout indicates a firewall block.A Routing Rule tells IFS Connect which outbound messages should be forwarded to the CubeMaster Routing Address configured in Step 4. It acts as a filter based on the message type.
| Field | Value |
|---|---|
| Rule Name | ROUTE_TO_CUBEMASTER |
| Message Handler | APPLICATION_MESSAGE |
| Condition | MESSAGE_TYPE = 'CUBEMASTER_LOAD_REQUEST' |
| Destination Address | CUBEMASTER_API_POST (from Step 4) |
| Active | Yes |
MESSAGE_TYPE equals CUBEMASTER_LOAD_REQUEST will be routed to the CubeMaster API. All other messages are unaffected.When your PL/SQL block (Step 7) calls Plsql_Rest_Sender_API.Call_Rest_EndPoint_Empty_Body, it places an outbound message with the type CUBEMASTER_LOAD_REQUEST into the IFS Connect message queue. IFS Connect evaluates all active Routing Rules and, matching on MESSAGE_TYPE, forwards the message payload to the configured HTTP Routing Address (CUBEMASTER_API_POST).
This decoupled design means your PL/SQL code does not directly call the CubeMaster API — IFS Connect handles delivery, retry logic, and error recording automatically.
Before writing any PL/SQL, it is critical to understand the exact JSON structure the CubeMaster API expects, and what it returns. Mis-formatted JSON is the most common source of integration errors.
The request body is a single JSON object with four top-level keys:
| Key | Type | Required | Description |
|---|---|---|---|
title | string | Yes | A human-readable label for this load plan. Appears in the CubeMaster UI and logs. |
description | string | No | Optional free-text notes about this load request. |
cargoes | array | Yes | One or more cargo item objects to be packed. At least one item must be present. |
emptyContainers | array | Yes | One or more container/vehicle objects to pack the cargoes into. |
rules | object | No | Optimization rules and algorithm selection. Defaults apply if omitted. |
cargoes)| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | SKU, part number, or item identifier from IFS. |
description | string | No | Human-readable item name. |
style | string | No | Package type. Options: Shipcase, Pallet, Bag, Drum, Cylinder, etc. Defaults to Shipcase. |
qty | integer | Yes | Quantity to pack. |
length | number | Yes | Item length (in cm or inches, per UOM). |
width | number | Yes | Item width. |
height | number | Yes | Item height. |
weight | number | No | Item weight (kg or lbs). Required if isWeightLimited: true in rules. |
orientationsAllowed | string | No | Rotation constraints. Options: OrientationsAll, OrientationsUpright, OrientationsUprightAndTurnedOnFloor. Defaults to OrientationsAll. |
colorKnownName | string | No | Color used for the item in the 3D diagram. E.g., Blue, Red, Brown. |
maxStackCount | integer | No | Maximum number of identical items that may be stacked vertically. |
isFragile | boolean | No | If true, no other items may be placed on top of this item. |
emptyContainers)| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Container name or code (e.g., 40HC, 53FT-Intermodal). |
containerType | string | No | Vehicle category. Options: SeaVan, Dry, Pallet, AirContainer, etc. |
length | number | Yes | Interior usable length. |
width | number | Yes | Interior usable width. |
height | number | Yes | Interior usable height. |
maxWeight | number | No | Maximum cargo weight capacity. Required if isWeightLimited: true. |
qty | integer | No | Number of identical containers to use. Defaults to 1. Increase to allow multiple containers. |
colorKnownName | string | No | Color of the container in the 3D diagram. |
rules)| Field | Type | Default | Description |
|---|---|---|---|
calculationType | string | MixLoad | How to pack: MixLoad (mixed items per container), SingleLoad (one SKU per container). |
algorithmType | string | Optimization | Packing algorithm: Optimization (best fit) or Speed (fast, less optimal). |
isWeightLimited | boolean | false | If true, the packer will not exceed maxWeight of each container. |
fillDirection | string | FrontToRear | Loading direction: FrontToRear, RearToFront, BottomToTop. |
isSequenceUsed | boolean | false | If true, loads items in the order they appear in the cargoes array (useful for stop-sequence delivery routes). |
{
"title": "IFS-SHP-100245",
"description": "Automated load from IFS Applications 9",
"cargoes": [
{
"name": "PART-A01",
"description": "Industrial Valve Assembly",
"style": "Shipcase",
"qty": 45,
"length": 60,
"width": 40,
"height": 40,
"weight": 15.5,
"orientationsAllowed": "OrientationsUpright",
"colorKnownName": "Brown"
},
{
"name": "PART-B05",
"description": "Control Panel Unit",
"style": "Shipcase",
"qty": 12,
"length": 120,
"width": 80,
"height": 100,
"weight": 110.0,
"isFragile": true,
"colorKnownName": "Blue"
}
],
"emptyContainers": [
{
"name": "40HC",
"containerType": "SeaVan",
"length": 1203,
"width": 235,
"height": 269,
"maxWeight": 26000,
"qty": 2
}
],
"rules": {
"calculationType": "MixLoad",
"algorithmType": "Optimization",
"isWeightLimited": true,
"fillDirection": "FrontToRear"
}
}
On success, the API returns HTTP 200 OK with a JSON body similar to the following:
{
"status": "succeed",
"message": "Engine created. 2 cargoes. 2 empty containers. Calculation ended. The load saved successfully.",
"calculationError": "NoErrors",
"document": {
"title": "IFS-SHP-100245",
"isShared": true,
"calculationTimeInSeconds": 0.87,
"createdBy": "user@company.com",
"createdAt": "2025-03-10T08:22:01+09:00"
},
"loadSummary": {
"cargoesLoaded": 57,
"piecesLoaded": 57,
"cargoesLeft": 0,
"volumeLoaded": 17820000,
"weightLoaded": 2017.5,
"containersLoaded": 1
},
"filledContainers": [
{
"name": "#1 40HC",
"sequence": 1,
"loadSummary": {
"cargoesLoaded": 57,
"volumeUtilization": 84.5,
"weightUtilization": 45.2,
"floorUtilization": 91.3
},
"loadSize": {
"length": 1180.5,
"width": 234.0,
"height": 265.2
},
"graphics": {
"images": {
"path3DDiagram": "https://api.cubemaster.net/Pictures/a7b8c9d10.PNG",
"pathComposite": "https://api.cubemaster.net/Pictures/composite_a7b8.PNG"
}
}
}
]
}
With the Routing Address and Routing Rule in place, we can now write the PL/SQL code that extracts IFS order data, builds the JSON payload, and dispatches it through IFS Connect. This code runs as an Execute Online SQL action inside an IFS Custom Event.
| IFS Table / View | Fields Used | Purpose |
|---|---|---|
customer_order_line | order_no, catalog_no, catalog_desc, buy_qty_due | Source of order line items (product, quantity). |
part_catalog_pub | part_no, length, width, height, weight | Physical dimensions and weight per part. |
Plsql_Rest_Sender_API | Call_Rest_EndPoint_Empty_Body | IFS API to place a message into the IFS Connect outbound queue. |
DECLARE
-- -----------------------------------------------
-- Variable declarations
-- -----------------------------------------------
ls_payload CLOB; -- The full JSON payload (CLOB for large orders)
ls_items CLOB := ''; -- Temporary buffer for cargoes array entries
ln_item_count NUMBER := 0; -- Track how many items were added
order_no_ VARCHAR2(50) := '&NEW:ORDER_NO'; -- IFS event parameter
-- -----------------------------------------------
-- Cursor: fetch all order lines with dimensions
-- Only include parts that have valid dimensions
-- -----------------------------------------------
CURSOR get_lines IS
SELECT
l.catalog_no AS part_no,
l.catalog_desc AS part_desc,
l.buy_qty_due AS qty,
NVL(c.length, 0) AS l,
NVL(c.width, 0) AS w,
NVL(c.height, 0) AS h,
NVL(c.weight, 0) AS wt
FROM customer_order_line l
LEFT JOIN part_catalog_pub c ON l.catalog_no = c.part_no
WHERE l.order_no = order_no_
AND l.buy_qty_due > 0; -- Skip zero-quantity lines
BEGIN
-- -----------------------------------------------
-- Step A: Build each cargo item JSON object
-- -----------------------------------------------
FOR rec_ IN get_lines LOOP
-- Skip items with no valid dimensions
IF rec_.l > 0 AND rec_.w > 0 AND rec_.h > 0 THEN
IF ln_item_count > 0 THEN
ls_items := ls_items || ','; -- comma-separate items
END IF;
ls_items := ls_items ||
'{' ||
'"name":"' || rec_.part_no || '",' ||
'"description":"' || REPLACE(rec_.part_desc, '"', '\"') || '",' ||
'"style":"Shipcase",' ||
'"qty":' || TRIM(TO_CHAR(rec_.qty)) || ',' ||
'"length":' || TRIM(TO_CHAR(rec_.l)) || ',' ||
'"width":' || TRIM(TO_CHAR(rec_.w)) || ',' ||
'"height":' || TRIM(TO_CHAR(rec_.h)) || ',' ||
'"weight":' || TRIM(TO_CHAR(rec_.wt)) ||
'}';
ln_item_count := ln_item_count + 1;
END IF;
END LOOP;
-- Guard: do not send an empty cargoes array
IF ln_item_count = 0 THEN
RETURN; -- No valid items found; abort silently
END IF;
-- -----------------------------------------------
-- Step B: Assemble the full JSON payload
-- -----------------------------------------------
ls_payload :=
'{' ||
'"title":"' || order_no_ || '",' ||
'"description":"IFS Auto-Generated Shipment",' ||
-- Cargo items array (built above)
'"cargoes":[' || ls_items || '],' ||
-- Default 40HC container (can be made dynamic via a separate cursor)
'"emptyContainers":[{' ||
'"name":"40HC",' ||
'"containerType":"SeaVan",' ||
'"length":1203,' ||
'"width":235,' ||
'"height":269,' ||
'"maxWeight":26000,' ||
'"qty":3' || -- allow up to 3 containers for large orders
'}],' ||
-- Optimization rules
'"rules":{' ||
'"calculationType":"MixLoad",' ||
'"algorithmType":"Optimization",' ||
'"isWeightLimited":true,' ||
'"fillDirection":"FrontToRear"' ||
'}' ||
'}';
-- -----------------------------------------------
-- Step C: Send through IFS Connect outbound queue
-- -----------------------------------------------
Plsql_Rest_Sender_API.Call_Rest_EndPoint_Empty_Body(
rest_endpoint_ => 'CUBEMASTER_API_POST', -- must match Routing Address name
payload_ => ls_payload,
http_method_ => 'POST'
);
EXCEPTION
WHEN OTHERS THEN
-- Log to IFS Application Error log for debugging
Error_SYS.Record_General(
'CUBEMASTER_INT',
'Payload dispatch failed for order :P1. Error: :P2',
order_no_,
SQLERRM
);
END;
CLOB for ls_payload because large orders with dozens of line items can exceed the 32 KB limit of VARCHAR2.REPLACE(rec_.part_desc, '"', '\"') escapes double quotes in part descriptions to prevent JSON parse errors.IF ln_item_count = 0 THEN RETURN prevents submitting an empty cargoes array, which would cause an API validation error.TRIM(TO_CHAR(...)) for numbers to avoid leading spaces in the JSON output, which can cause parse errors in strict JSON validators.A Custom Event in IFS is the automation trigger that executes your PL/SQL block when a specific business condition occurs. This connects the business process (e.g., order release) to the CubeMaster API call.
| Field | Recommended Value |
|---|---|
| Event Name | CUBEMASTER_LOAD_ON_ORDER_RELEASE |
| Logical Unit | CustomerOrder (or Shipment if triggering from shipment) |
| Firing Condition | Attribute: Objstate, Operation: Changed To, Value: Released |
| Active | Yes |
Execute Online SQL.&NEW:ORDER_NO in the PL/SQL will automatically be replaced with the actual order number at runtime by the IFS event framework.Depending on your business process, you may want to trigger the CubeMaster call at a different point:
| Logical Unit | Firing Attribute | Firing Value | Use Case |
|---|---|---|---|
CustomerOrder | Objstate | Released | Trigger when a sales order is released to warehouse. |
CustomerOrder | Objstate | Planned | Trigger earlier, at planning stage, for proactive container booking. |
Shipment | Objstate | Completed | Trigger when a shipment is fully confirmed and ready to load. |
DeliveryNote | Objstate | Printed | Trigger at delivery note print time for last-mile load planning. |
After CubeMaster processes the request, it returns a JSON response. You can configure IFS to capture and store key fields from this response back into IFS records.
Map CubeMaster's response JSON fields to IFS Custom Fields on the Shipment or Customer Order screen:
| CubeMaster JSON Field | IFS Destination (Custom Field) | Type | Description |
|---|---|---|---|
status |
CF$_CUBEMASTER_STATUS |
String (20) | Overall API call result: succeed or an error string. |
calculationError |
CF$_CALC_ERROR |
String (50) | Specific error code from the engine. NoErrors means success. |
loadSummary.volumeUtilization |
CF$_VOL_UTIL_PCT |
Number | Overall space efficiency (%). Used for KPI dashboards and shipping reports. |
loadSummary.cargoesLoaded |
CF$_LOADED_QTY |
Number | Total pieces loaded. Compare against order quantity to detect items left behind. |
loadSummary.cargoesLeft |
CF$_LEFT_QTY |
Number | Pieces that did not fit. If > 0, additional containers may be required. |
loadSummary.containersLoaded |
CF$_CONTAINERS_USED |
Number | Number of containers actually used. Helps validate container booking. |
loadSummary.weightLoaded |
CF$_WEIGHT_LOADED |
Number | Total loaded weight in configured UOM. Used for freight rate calculation. |
document.calculationTimeInSeconds |
CF$_CALC_SECONDS |
Number | Engine calculation time. Useful for performance monitoring. |
filledContainers[0].graphics.images.path3DDiagram |
CF$_CUBEMASTER_3D_URL |
String (500) / Hyperlink | URL to the 3D load diagram image. Warehouse workers can click to view the packing plan. |
filledContainers[0].graphics.images.pathComposite |
CF$_CUBEMASTER_COMPOSITE_URL |
String (500) / Hyperlink | URL to the composite top/side/front view diagram. |
IFS Connect supports a Response Transformer on each Routing Address. This allows you to define XPath or JSONPath expressions to parse the CubeMaster response and trigger a second IFS event or update record fields automatically.
CUBEMASTER_API_POST Routing Address record, navigate to the Response Handling tab.JSON.| JSONPath Expression | Target Parameter |
|---|---|
$.status | CUBEMASTER_STATUS |
$.loadSummary.volumeUtilization | VOL_UTIL |
$.loadSummary.cargoesLeft | CARGOES_LEFT |
$.filledContainers[0].graphics.images.path3DDiagram | DIAGRAM_URL |
"status": "succeed" and a valid path3DDiagram URL before enabling the IFS event.CUBEMASTER_LOAD_REQUEST to find all outbound messages from your integration.Sent — Successfully forwarded to CubeMaster.Failed — Delivery failed. Click the message to see the Error Text.Cancelled — Manually cancelled or exceeded retry limit.Waiting — In queue, not yet dispatched.Failed messages, click the row to open the message details and review the Error Text field. Common errors are listed in section 10.4 below.CUBEMASTER_LOAD_ON_ORDER_RELEASE.Completed status means the PL/SQL ran successfully and placed a message in the queue.Error status means the PL/SQL itself threw an exception. Review the Error Message column — this will show the Oracle error or the message from Error_SYS.Record_General.| Error / Symptom | Likely Cause | Solution |
|---|---|---|
HTTP 401 Unauthorized |
Missing, expired, or incorrect TokenID header. |
Verify the TokenID in the Routing Address HTTP Header. Regenerate the key in CubeMaster Settings if needed. |
HTTP 400 Bad Request |
Malformed JSON payload (e.g., trailing comma, unescaped quote in a description field). | Copy the payload from the IFS message log and validate it at jsonlint.com. Fix the PL/SQL string concatenation. |
calculationError: InvalidCargoSize |
One or more cargo items have zero or negative dimensions. | Add the IF rec_.l > 0 AND rec_.w > 0 AND rec_.h > 0 guard in the PL/SQL loop. Fix dimension data in part_catalog_pub. |
| Connection timeout / no response | Firewall blocking outbound HTTPS to api.cubemaster.net. |
Work with your network team to whitelist api.cubemaster.net:443. Run a curl test from the IFS server to confirm. |
| Event fires but no message appears in queue | PL/SQL guard clause triggered (e.g., no valid order lines found). | Check that the order has lines with buy_qty_due > 0 and that parts have dimensions in part_catalog_pub. |
ORA-06502: PL/SQL: numeric or value error |
TO_CHAR output contains unexpected formatting or a VARCHAR2 buffer overflow. |
Ensure all numeric conversions use TRIM(TO_CHAR(...)). Switch ls_items to CLOB if order lines exceed 32 KB. |
| Message sends but 3D diagram URL is missing | graphicsCreated=true not appended to the Routing Address URL. |
Update the Routing Address URL to include ?loadSaved=true&graphicsCreated=true. |
&UOM=UnitMetric (cm/kg) or &UOM=UnitEnglish (in/lbs) to the Routing Address URL to explicitly override the default and avoid silent UOM mismatches.
Timeout on the Routing Address to 120 seconds or more.HTTP 429 Too Many Requests. Implement a delay or queue throttle in IFS Connect if needed.DBMS_LOB.APPEND for optimal performance.