Skip to main content
This guide walks through how to run a route optimization using Nash’s REST API. You will learn how to submit an optimization request, poll for completion, and dispatch the resulting routes.

What Is Route Optimization?

Nash’s route optimization engine takes a set of orders and groups them into efficient, constraint-aware routes for your fleet. It solves the Vehicle Routing Problem (VRP) by considering:
  • Capacity constraints (stop count, item count, weight, volume)
  • Time windows (hard pickup and dropoff windows per order)
  • Driver shifts and breaks (shift start/end, mandatory meal breaks)
  • Vehicle profiles (car, truck, bicycle with different speed/access/capacity)
  • Real-time traffic (live traffic data for accurate travel time estimates)
  • Cost modeling (fixed cost, distance tiers, time cost, per-stop cost)

When to Use It

Use route optimization when you have multiple orders to deliver and want to minimize cost, distance, or time across your fleet. Common scenarios include:
  • Daily or shift-based delivery planning
  • Batching orders from a store location into driver routes
  • Optimizing catering, grocery, or pharmacy deliveries with time windows

Prerequisites

Before running an optimization, make sure you have:
  1. API key and Organization ID — see Generating API Key and Org ID
  2. At least two orders created in Nash — the optimizer requires a minimum of two orders
  3. A contract with vehicle optimization parameters — your provider contract must include vehicle parameters (vehicle count, max orders per route, driving limits, cost model). Contact Nash support if you need help configuring this.
  4. Appropriate permissions — your API key must have WRITE_JOB permission to create optimization activities and READ_ORDER permission to query results

End-to-End Flow

The optimization workflow follows three steps:
  1. Submit — Call the optimization endpoint with your orders and parameters
  2. Poll — Query the returned activity ID until status is SUCCESS
  3. Dispatch — Dispatch the optimized routes to your fleet

Step 1: Submit an Optimization Request

Use POST /v1/activities/optimization to submit orders for optimization. There are two ways to specify which orders to optimize:
  • Explicit order IDs — pass a list of orderIds directly
  • Filters — use tags, pickupStoreLocationIds, status, or date ranges to select orders dynamically
Both approaches can be combined (results are merged).

Submit with Explicit Order IDs

submit optimization with order IDs
curl --request POST \
  --url https://api.sandbox.usenash.com/v1/activities/optimization \
  --header 'Authorization: Bearer $TOKEN' \
  --header 'Nash-Org-Id: $ORG_ID' \
  --header 'Content-Type: application/json' \
  --data '{
    "orderIds": ["ord_abc123", "ord_def456", "ord_ghi789"],
    "optimizationParameters": {
        "scenarios": [
            {
                "name": "",
                "value": [
                    {
                        "contractId": "your_contract_id",
                        "providerName": "YourProviderName",
                        "useAllVehicles": false,
                        "vehicleCount": 5
                    }
                ]
            }
        ]
    },
    "async": true
}'

Submit with Tag Filters

submit optimization with tag filters
curl --request POST \
  --url https://api.sandbox.usenash.com/v1/activities/optimization \
  --header 'Authorization: Bearer $TOKEN' \
  --header 'Nash-Org-Id: $ORG_ID' \
  --header 'Content-Type: application/json' \
  --data '{
    "tags": ["morning-batch"],
    "optimizationParameters": {
        "scenarios": [
            {
                "name": "",
                "value": [
                    {
                        "contractId": "your_contract_id",
                        "providerName": "YourProviderName",
                        "useAllVehicles": false,
                        "vehicleCount": 10
                    }
                ]
            }
        ]
    },
    "async": true
}'

Example Response

submit optimization response
{
    "id": "act_abc123def456",
    "createdAt": "2026-02-25T10:00:00Z",
    "action": "act_optimize_orders",
    "status": "QUEUED",
    "externalOptimizationId": null,
    "inputData": {
        "order_ids": ["ord_abc123", "ord_def456", "ord_ghi789"]
    },
    "result": null
}
When async is true (the default), the activity is created with status QUEUED and optimization runs in the background. When async is false, the request blocks until optimization completes and returns the final status directly.

Request Parameters

ParameterTypeRequiredDescription
optimizationParametersObjectYesOptimization configuration (see below)
orderIdsString[]NoExplicit list of order IDs to optimize
tagsString[]NoFilter orders by tags
pickupStoreLocationIdsString[]NoFilter orders by pickup store location
dropoffStoreLocationIdsString[]NoFilter orders by dropoff store location
statusString[]NoFilter orders by status
startDateDateTimeNoFilter by pickup start date
endDateDateTimeNoFilter by pickup end date
storeLocationIdStringNoRun store-location-based optimization (mutually exclusive with order filters)
asyncBooleanNoRun asynchronously (default: true)
sessionIdStringNoOptional session identifier for grouping activities
optimizationStrategyIdsString[]NoFilter by optimization strategy IDs

Optimization Parameters Object

The optimizationParameters object configures how the optimizer builds routes:
optimization parameters structure
{
    "scenarios": [
        {
            "name": "",
            "value": [
                {
                    "contractId": "your_contract_id",
                    "providerName": "YourProviderName",
                    "useAllVehicles": false,
                    "vehicleCount": 5
                }
            ]
        }
    ],
    "softCapabilities": [],
    "searchLevel": null,
    "clusteringLevel": null,
    "softClusterLabel": false
}
FieldTypeDescription
scenariosArrayFleet scenarios to optimize across. Each scenario has a name and a value array of vehicle/contract configurations.
scenarios[].value[].contractIdStringThe contract ID defining vehicle parameters and cost model
scenarios[].value[].providerNameStringThe provider name for this vehicle group
scenarios[].value[].vehicleCountIntegerNumber of vehicles available for this scenario
scenarios[].value[].useAllVehiclesBooleanIf true, forces all vehicles to be used even if fewer would suffice
softCapabilitiesString[]Optional soft constraints (e.g., vehicle capabilities that are preferred but not required)
searchLevelIntegerSearch depth (0-3). Higher values produce better solutions but take longer. null uses the default.
clusteringLevelIntegerControls geographic clustering of orders before optimization. null uses the default.
softClusterLabelBooleanWhen true, cluster labels are soft constraints rather than hard boundaries

Step 2: Poll for Optimization Status

After submitting an optimization request, poll the activity status until it reaches a terminal state.
poll activity status
curl --request GET \
  --url https://api.sandbox.usenash.com/v1/activities/act_abc123def456 \
  --header 'Authorization: Bearer $TOKEN' \
  --header 'Nash-Org-Id: $ORG_ID'

Activity Status Values

StatusDescription
SCHEDULEDActivity is scheduled for future execution
QUEUEDActivity is queued and waiting to be processed
IN_PROGRESSOptimization is currently running
SUCCESSOptimization completed successfully — results are available in the result field
FAILEDOptimization failed — check the result field for error details
CANCELLEDActivity was cancelled
SKIPPEDActivity was skipped (e.g., no eligible orders found)

Polling Strategy

We recommend polling every 5 seconds with a maximum timeout of 5 minutes. Most optimizations complete within 30 seconds, but larger order sets or higher search levels may take longer. Poll GET /v1/activities/{id} repeatedly until the status field is SUCCESS, FAILED, CANCELLED, or SKIPPED.

Example Success Response

When the activity status is SUCCESS, the response contains the externalOptimizationId you will need for dispatch:
poll success response
{
    "id": "act_abc123def456",
    "createdAt": "2026-02-25T10:00:00Z",
    "action": "act_optimize_orders",
    "status": "SUCCESS",
    "externalOptimizationId": "opt_ext_789",
    "inputData": {
        "order_ids": ["ord_abc123", "ord_def456", "ord_ghi789"]
    },
    "result": [
        {
            "optimized_route": {
                "routes": ["..."],
                "unassigned": []
            }
        }
    ]
}

Step 3: Dispatch Optimized Routes

Once optimization completes, you can dispatch the routes. There are two dispatch paths:

Option A: Dispatch Optimized Orders Directly

Use POST /v1/activities/{id}/dispatch to dispatch the optimized orders in a single step. This creates routes, jobs, and (if autoDispatch is true) dispatches them to providers.
dispatch optimized orders
curl --request POST \
  --url https://api.sandbox.usenash.com/v1/activities/act_abc123def456/dispatch \
  --header 'Authorization: Bearer $TOKEN' \
  --header 'Nash-Org-Id: $ORG_ID' \
  --header 'Content-Type: application/json' \
  --data '{
    "autoDispatch": true
}'
Both orderIds and externalOptimizationId are resolved automatically from the activity. You can optionally pass orderIds to dispatch only a subset of the optimized orders.
ParameterTypeRequiredDescription
orderIdsString[]NoOrder IDs to dispatch. If omitted, all orders from the optimization are dispatched.
autoDispatchBooleanNoAutomatically dispatch to provider (default: true)

Option B: Save Routes First, Then Dispatch

For more control, you can save the optimization as routes, review them, and then dispatch individually. Save routes: Use POST /v1/activities/{id}/save-routes to create route objects from the optimization results. No request body is needed — the activity ID in the URL is sufficient.
save optimization routes
curl --request POST \
  --url https://api.sandbox.usenash.com/v1/activities/act_abc123def456/save-routes \
  --header 'Authorization: Bearer $TOKEN' \
  --header 'Nash-Org-Id: $ORG_ID'
This returns the created route objects with their IDs, stops, and order assignments. You can also view these routes in the Nash Portal before dispatching. Dispatch routes: Use POST /v1/routes/dispatch to dispatch one or more saved routes.
dispatch routes
curl --request POST \
  --url https://api.sandbox.usenash.com/v1/routes/dispatch \
  --header 'Authorization: Bearer $TOKEN' \
  --header 'Nash-Org-Id: $ORG_ID' \
  --header 'Content-Type: application/json' \
  --data '{
    "routeIds": ["rte_route_id_1", "rte_route_id_2"],
    "autoDispatch": true
}'
ParameterTypeRequiredDescription
routeIdsString[]YesThe route IDs to dispatch
autoDispatchBooleanNoAutomatically dispatch to provider (default: true)

Common Pitfalls and Troubleshooting

Not Enough Orders

The optimizer requires at least two orders. If you pass fewer, the request returns an error. Make sure your filters match enough orders before submitting.

Missing Vehicle Optimization Parameters

If your contract doesn’t have vehicle_optimization_parameters configured, optimization will fail. These parameters define vehicle capacity, driving limits, and cost model. Contact Nash support to configure them on your contract.

Async Timing Issues

When using async: true (the default), the request returns immediately with status QUEUED. You must poll the activity status before attempting to dispatch. Dispatching before optimization completes will fail.

Mismatched Optimization Mode

The endpoint has two mutually exclusive modes:
  • Order-based: Use orderIds, tags, and other order filter fields (no storeLocationId)
  • Store-location-based: Use storeLocationId (no order filter fields)
Mixing fields from both modes will result in a validation error.

Empty Result / No Routes

If the optimizer cannot fit orders into routes given the constraints (time windows, capacity, vehicle count), the result may contain unassigned orders. Consider:
  • Increasing vehicleCount
  • Relaxing time window constraints on your orders
  • Checking that pickup and dropoff addresses are valid and geocoded

Optimization Strategy IDs

If you use Optimization Strategies (pre-configured optimization profiles), pass their IDs via optimizationStrategyIds. This applies the strategy’s contract, schedule, and constraint configuration automatically.