Skip to main content

Stateless Optimization Workflow

This guide explains how to use the automated workflow to execute a complete optimization cycle with Integration API that emulates Stateless API. To support long-running optimizations (e.g., > 1 hour), the workflow is split into three actions: Start, Status, and Results.

Why use Integration API as Stateless API?

While the Stateless API offers maximum flexibility, using the Integration API to emulate a stateless workflow provides significant advantages in terms of integration speed and feature access. This approach leverages the robustness of the stateful system while maintaining the simplicity of a "fire-and-forget" optimization request.

Reduced Integration Complexity via Templates

As detailed in the Simulation Templates guide, the Integration API allows you to pre-configure complex optimization settings (cost functions, constraints, vehicle profiles) once as a "template".

  • Save Time: You don't need to construct and validate a massive JSON configuration object for every request.
  • Maintenance: Operational changes (e.g., adjusting service times or costs) can be made in the template without changing your integration code.
  • Automatic Adjustments: The system automatically handles time window shifting for recurring operations.

Access to Superset of Features

The Integration API supports a wider range of capabilities than the raw Stateless API, as outlined in the Introduction:

  • Advanced Pipelines: Access to multi-stage optimization pipelines (e.g., wave planning, multi-DC) that are managed by the system.
  • Visualization & Debugging: Because the data is temporarily stored as a "Simulation", you can use SWAT's dashboard tools to visualize routes, debug unassigned orders, and analyze performance—capabilities not available with the purely ephemeral Stateless API.
  • Persistent Objects: Option to mix ephemeral data (daily orders) with persistent data (fleet master data), reducing payload size.

Simplified Asynchronous Workflow

For long-running optimizations (> 1 hour), the Integration API's native job management (Processors) provides a robust way to track status and retrieve results, which is wrapped by this workflow to feel like a simple async call.

Workflow Overview

The client initiates the optimization, then polls for status, and finally retrieves the results.

Process Flow

API Usage

Authentication

All API requests must include the following headers.

HeaderRequiredDescription
AuthorizationYesBasic authentication header in the format Basic <base64-encoded-credentials>
Content-TypeYesSpecifies the request body format. Must be set to application/json.

Example:

headers = {
"Authorization": "Basic <base64-encoded-credentials>",
"Content-Type": "application/json"
}

Start Action

Initiates the workflow by uploading data and starting the optimization.

tip

Each order and vehicle must have a unique UID.

For detailed documentation on the underlying APIs, refer to:

  • To populate orders refer to Orders Upload. The format of the object is matching with bookings object
  • To populate vehicles refer to Bulk Vehicle Upload. The format of the object is matching with payload.vehicles object for Vehicle bulk upload operation.
  • To populate inventory (optional), provide a list of factory inventory items. This allows the optimization to respect inventory constraints at pickup locations.
tip

If inventory based optimization is used we anticipate pickup locations to be unknown and pickup_location_lat, pickup_location_lon, pickup_location_name, pickup_location_address can be null or empty for the orders. Otherwise, these are required fields.

  • To populate optimization_setting (optional), refer to Run Optimization. This overrides default settings from the template.
tip

optimization_setting can be omitted entirely or set to null if you wish to use the default settings defined in your simulation template. We recommend omitting it to keep your integration simple.

The body may contain the following optional parameters:

  • simulation_template: Specifies a custom simulation template to use, overriding the default auto-selected one.
  • date_of_service: Defines a specific date for the optimization to begin. By default, the optimization's start time is the earliest known timestamp found among the provided vehicles and orders. This timestamp is important for bounding vehicle working hours, particularly in scenarios where the earliest possible time is otherwise unknown for orders and vehicles.
warning

Each optimization run will create a new simulation that will be retained in SWAT system unless it is cleaned up with delete request. SWAT currently doesn't support having multiple simulations with the same start time created from the same template, the data submited may end up in the prevsiouly created simulation. While the results may still be produce, this can break data isolation and result in unexpected outcomes.

The endpoint triggers the Optimisation pipeline.

Upon successful submission, the system will start processing the Optimisation job and return a simulation_id, which can later be used to check the Optimisation status.

Payload

FieldTypeRequiredDescription
ordersarrayYesList of order objects to be included in the optimisation process
projectintegerYesProject identifier
vehiclesarrayYesList of vehicle configurations available for optimisation
inventoryarrayYesInventory or resource list used in the optimisation model
simulation_templateintegerYesSimulation template identifier used for the optimisation run

Request Body:

{
"project": 839,
"orders": [
{
"id": "750266-1-1",
"sku_code": "BULOX0010000000",
"demand": {
"M3": 2000
},
"product_type": "Liquid",
"max_pickup_time": "2031-01-02T23:00:00+07:00",
"min_pickup_time": "2031-01-01T00:00:00+07:00",
"max_dropoff_time": "2031-01-01T23:00:00+07:00",
"min_dropoff_time": "2031-01-01T00:00:00+07:00",
"dropoff_location_lat": 1.3258751960077857,
"dropoff_location_lon": 103.79996384867766,
"dropoff_service_time": 300,
"dropoff_location_name": "Some Dropoff Location Name",
"dropoff_location_address": "123 Example Street, City, Country",
"customer_name": "Customer A",
"dropoff_time_windows": [
{
"open_time_ts": "2031-01-02T00:00:00+07:00",
"close_time_ts": "2031-01-02T23:00:00+07:00"
}
]
}
],
"vehicles": [
{
"lat": 0,
"lon": 0,
"service_number": "Truck 01",
"capacity": {
"PCS": 80
},
"labels": [
"Cylinder"
],
"end_location_lat": -7.336931135,
"end_location_lon": 112.761382505,
"end_location_name": "Depot Location",
"start_location_lat": -7.336931135,
"start_location_lon": 112.761382505,
"start_location_name": "Depot Location",
"routing_engine_settings": {
"key": "<your_routing_engine_api_key>",
"url": "http://mapbox-osrm-proxy",
"speed": 18.5,
"profile": "",
"road_network": "van_staticjava",
"routing_engine_name": "osrme",
"use_speed_in_routing": true
}
},
{
"lat": 0,
"lon": 0,
"service_number": "Lorry Tank 01",
"capacity": {
"KG": 20000
},
"labels": [
"BUCAR0010000000"
],
"max_pickup_locations": 1,
"max_dropoff_locations": 3,
"end_location_lat": -7.336931135,
"end_location_lon": 112.761382505,
"end_location_name": "Depot Location",
"start_location_lat": -7.336931135,
"start_location_lon": 112.761382505,
"start_location_name": "Depot Location",
"routing_engine_settings": {
"key": "<your_routing_engine_api_key>",
"url": "http://mapbox-osrm-proxy",
"speed": 18.5,
"profile": "",
"road_network": "van_staticjava",
"routing_engine_name": "osrme",
"use_speed_in_routing": true
}
},
{
"lat": 0,
"lon": 0,
"service_number": "Lorry Tank 02",
"capacity": {
"KG": 8500
},
"labels": [
"BUCAR0010000000"
],
"max_pickup_locations": 1,
"max_dropoff_locations": 3,
"end_location_lat": -7.336931135,
"end_location_lon": 112.761382505,
"end_location_name": "Depot Location",
"start_location_lat": -7.336931135,
"start_location_lon": 112.761382505,
"start_location_name": "Depot Location",
"routing_engine_settings": {
"key": "<your_routing_engine_api_key>",
"url": "http://mapbox-osrm-proxy",
"speed": 18.5,
"profile": "",
"road_network": "van_staticjava",
"routing_engine_name": "osrme",
"use_speed_in_routing": true
}
}
],
"simulation_template": 131450,
"inventory": [
{
"factory_name": "Factory A",
"factory_lat": -7.366486,
"factory_lon": 112.663359,
"factory_inventory": [
{
"sku_code": "BUCAR0020000000",
"sku_name": "LIQUID CO2 FOOD GRADE",
"quantity": 5000,
"uom": "KG"
},
{
"sku_code": "CMARGEMP0000060",
"sku_name": "BOTOL ARMIX 6 M3 MP KOSONG",
"quantity": 300,
"uom": "PC"
}
]
},
{
"factory_name": "Factory B",
"factory_lat": -6.178052,
"factory_lon": 106.923023,
"factory_inventory": [
{
"sku_code": "CYCAREMP0000200",
"sku_name": "BOTOL CO2 20 KG MP KOSONG",
"quantity": 4,
"uom": "PC"
},
{
"sku_code": "SMSUP0030000000",
"sku_name": "ACETONE",
"quantity": 20,
"uom": "KG"
},
{
"sku_code": "BULOX0010000000",
"sku_name": "LIQUID 02",
"quantity": 160,
"uom": "M3"
}
]
}
]
}

Response:

{
"simulation_id":236770
}

Status Action

Checks the progress of the optimization using the simulation_id returned from the Start Action.

note

Optimization time can be configured in the simulation template and can vary from seconds to hours for a very large optimization problem.

The endpoint triggers the Check Optimization Status pipeline.

The request payload contains the simulation_id, which identifies the optimisation job whose status is being queried.

Upon successful submission, the system will start processing the optimisation job. The client is required to poll the status API periodically until the current_status field returns completed.

Request Body:

{
"simulation_id": 236770
}

Response:

{'id': None, 'start_time': None, 'current_status': 'pending'}
// Note: Optimization is yet to start

{'id': 62993, 'end_time': '2026-03-05T08:42:15.037425+00:00', 'start_time': '2026-03-05T08:40:15.037425+00:00', 'current_status': 'calculating'}
// Note: Optimization is in progress

{'id': 62989, 'end_time': '2026-03-05T08:02:31.856945+00:00', 'start_time': '2026-03-05T08:00:31.856945+00:00', 'current_status': 'completed'}
// Note: Optimization has completed

Results Action

Retrieves the final results once the status is "completed". This returns the assigned nodes and detailed route information for each vehicle, assigned orders and travel legs. rejected_bookings will contain a list of orders that can not be assigned to vehicles.

For detailed documentation on the Node object structure, refer to:

note

include_navigation is forcing the system to return turn by turn navigation for travel which can be very verbose. If you do not require it, omit this parameter, or set it to false. Travel durations and polylines will still be included, but no turn by turn navigation will be provided.

The endpoint triggers the Get Optimization Results pipeline.

The request payload contains the simulation_id and include_navigation, which identifies the optimisation job whose results are being queried and includes the polylines for maps.

Request Body:

{
"simulation_id": 236770,
"include_navigation": true
}
warning

Path in the route sequence is returned in polyline5 format. Refer to Google official documentation. JSON string with the polyline must be unescaped first to render correct results.

Response:

Details
{
"vehicles": {
"vehicle1" : [
// List of points that the vehicle will travel to. E.g:
{
"id": 17396647,
"lat": 0,
"lon": 0,
"data": {},
"slack": 0.0,
"demand": {
"cbm": 0
},
"status": "assigned",
"node_type": "point",
"break_info": null,
"display_name": "Node Location",
"geofence_ids": [],
"open_time_ts": "2027-03-18T17:00:00+00:00",
"scheduled_ts": "2027-03-18T17:00:00+00:00",
"service_time": 0.0,
"time_windows": null,
"close_time_ts": "2027-03-19T16:59:00+00:00",
"location_name": "Node Location",
"vehicle_labels": null,
"vehicle_characteristics": {}
}

]
},
"no_offers": {
// Object where the keys are the certain checks done. E.g.
// If all checks have been passed, the check will not appear. Otherwise, the checks will show message(s) of where the issues lie
"Inventory vs Demand load Check": [
{
"CYOXGFMP0040050": "Cannot find SKU in factories",
"CYOXGFMR0010061": "Cannot find SKU in factories"
}
],
"Vehicle Capacity vs Demand load Check": [
],
"Factory location vs Order Locations Check": [
],
"LABELS CHECK": [
],
"TIME WINDOW CHECK": [
],
"VEHICLE KEYS CHECK": [
],
"VEHICLE TYPE CHECK": [
],
"ROUTING PROFILE CHECK": [
],
"GEOFENCE CONSTRAINT CHECK": [
],
"TOTAL CAPACITY VIOLATION CHECK": [
]
},
"rejected_bookings": [
// List of bookings that got rejected, e.g:
{
"order_id": "786514-3-1",
"pickup_location_lat": 0,
"pickup_location_lon": 0,
"dropoff_location_lat": 0,
"dropoff_location_lon": 0,
"pickup_location_name": "Pickup Hub",
"dropoff_location_name": "Dropoff Location"
}
]

}

Cleanup Action

Optionally, delete the simulation and associated data after results are retrieved.

The endpoint triggers the Delete Optimization Results pipeline.

The request payload contains the simulation_id, which identifies the optimisation job that would need to be deleted

Request Body:

{
"simulation_id": 236770
}

Response:

{
"message": "Simulation has been deleted",
"status_code": 204
}
warning

This process is irreversible. If a simulation does not get any assigned bookings and this API is triggered, it will be very difficult to understand and debug the issue as there is no way of knowing what went wrong. Hence, when such cases come up, you will need to re-submit the orders from the first API to start the whole process so that we are able to debug.