Skip to content

Quickstart: your first optimization

~10 min read · Getting started

By the end of this page you'll have submitted a small problem and retrieved a real optimized solution. You need one thing to start: an API key (see Authentication).

The base URL

All calls go to https://iq.scheduledroutes.ddswireless.net. Replace YOUR_API_KEY below with your key.

1. Submit a problem

This "hello-world" problem has 2 vehicles and 3 deliveries, optimizing for the least total travel time.

Change the dates before you run this

The engine rejects any window that has already closed (error 10405). The example is dated 2026-07-31 — replace every timestamp with a date still ahead of your clock, tomorrow is the safe choice, or the run comes back with nothing scheduled.

curl -X POST https://iq.scheduledroutes.ddswireless.net/raas/optimization \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "problem": {
      "fleet": [
        {"id": 1, "capacities": [{"name": "parcels", "units": 40}],
         "shifts": [{"start": {"time": "2026-07-31T08:00:00-07:00", "location": [49.28270, -123.11540]},
                      "end":   {"time": "2026-07-31T17:00:00-07:00", "location": [49.28270, -123.11540]}}]},
        {"id": 2, "capacities": [{"name": "parcels", "units": 40}],
         "shifts": [{"start": {"time": "2026-07-31T08:00:00-07:00", "location": [49.28270, -123.11540]},
                      "end":   {"time": "2026-07-31T17:00:00-07:00", "location": [49.28270, -123.11540]}}]}
      ],
      "jobs": [
        {"id": 101, "deliveries": [{"id": 1001, "location": [49.26340, -123.13830], "duration": 300,
          "serviceWindows": [["2026-07-31T08:00:00-07:00", "2026-07-31T17:00:00-07:00"]],
          "demand": [{"name": "parcels", "units": 2}]}]},
        {"id": 102, "deliveries": [{"id": 1002, "location": [49.24660, -123.06340], "duration": 300,
          "serviceWindows": [["2026-07-31T08:00:00-07:00", "2026-07-31T17:00:00-07:00"]],
          "demand": [{"name": "parcels", "units": 1}]}]},
        {"id": 103, "deliveries": [{"id": 1003, "location": [49.28150, -123.12070], "duration": 300,
          "serviceWindows": [["2026-07-31T08:00:00-07:00", "2026-07-31T17:00:00-07:00"]],
          "demand": [{"name": "parcels", "units": 3}]}]}
      ],
      "objective": 1,
      "configuration": {"units": "metric", "statistics": true, "unassignedTasks": true, "polylineType": "none"}
    }
  }'
import requests

BASE = "https://iq.scheduledroutes.ddswireless.net"
headers = {"Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json"}

problem = {
    "problem": {
        "fleet": [
            {"id": 1, "capacities": [{"name": "parcels", "units": 40}],
             "shifts": [{"start": {"time": "2026-07-31T08:00:00-07:00", "location": [49.28270, -123.11540]},
                         "end":   {"time": "2026-07-31T17:00:00-07:00", "location": [49.28270, -123.11540]}}]},
            {"id": 2, "capacities": [{"name": "parcels", "units": 40}],
             "shifts": [{"start": {"time": "2026-07-31T08:00:00-07:00", "location": [49.28270, -123.11540]},
                         "end":   {"time": "2026-07-31T17:00:00-07:00", "location": [49.28270, -123.11540]}}]},
        ],
        "jobs": [
            {"id": 101, "deliveries": [{"id": 1001, "location": [49.26340, -123.13830], "duration": 300,
              "serviceWindows": [["2026-07-31T08:00:00-07:00", "2026-07-31T17:00:00-07:00"]],
              "demand": [{"name": "parcels", "units": 2}]}]},
            {"id": 102, "deliveries": [{"id": 1002, "location": [49.24660, -123.06340], "duration": 300,
              "serviceWindows": [["2026-07-31T08:00:00-07:00", "2026-07-31T17:00:00-07:00"]],
              "demand": [{"name": "parcels", "units": 1}]}]},
            {"id": 103, "deliveries": [{"id": 1003, "location": [49.28150, -123.12070], "duration": 300,
              "serviceWindows": [["2026-07-31T08:00:00-07:00", "2026-07-31T17:00:00-07:00"]],
              "demand": [{"name": "parcels", "units": 3}]}]},
        ],
        "objective": 1,
        "configuration": {"units": "metric", "statistics": True, "unassignedTasks": True, "polylineType": "none"},
    },
}

r = requests.post(f"{BASE}/raas/optimization", json=problem, headers=headers)
optimization_id = r.json()["id"]
print("Submitted:", optimization_id)
$headers = @{ Authorization = "Bearer YOUR_API_KEY"; "Content-Type" = "application/json" }
$body = Get-Content .\problem.json -Raw   # the JSON from the cURL tab
$r = Invoke-RestMethod -Method Post -Uri "https://iq.scheduledroutes.ddswireless.net/raas/optimization" `
    -Headers $headers -Body $body
$r.id

Response (202 Accepted):

{ "id": "1042318", "status": "accepted", "message": "Optimization request accepted.", "error": null }

Copy that id — you'll poll it next.

2. Retrieve the solution

Poll the id. While the optimization runs you'll get a 202; when it's done you'll get a 200 with the full solution.

curl https://iq.scheduledroutes.ddswireless.net/raas/optimization/1042318 \
  -H "Authorization: Bearer YOUR_API_KEY"

This continues the script from step 1 — same file, same session. It reuses the requests import, BASE, headers, and optimization_id defined there.

import time

while True:
    r = requests.get(f"{BASE}/raas/optimization/{optimization_id}", headers=headers)
    if r.status_code == 200:
        solution = r.json()["solution"]
        break
    time.sleep(2)   # still optimizing — wait and poll again

print(solution["statistics"])
for route in solution["routes"]:
    print("Vehicle", route["vehicleId"], "->",
          [s["taskId"] for shift in route["shifts"] for s in shift["stops"]])
$id = $r.id                     # from step 1
do {
    Start-Sleep -Seconds 2
    $result = Invoke-WebRequest -Method Get `
        -Uri "https://iq.scheduledroutes.ddswireless.net/raas/optimization/$id" `
        -Headers $headers
} while ($result.StatusCode -eq 202)

($result.Content | ConvertFrom-Json).solution

Response (200 OK, trimmed):

{
  "status": "completed",
  "solution": {
    "statistics": { "vehicles": {"used": 2, "unused": 0}, "jobs": {"scheduledTasks": 3, "unassignedTasks": 0} },
    "routes": [
      { "vehicleId": 1, "shifts": [ { "index": 0, "stops": [
        { "ordinal": 1, "jobId": 101, "taskId": 1001, "type": "delivery", "eta": "2026-07-31T08:14:00-07:00" }
      ] } ] }
    ],
    "unassigned": []
  }
}

That is the raw body the GET returns. The Python above reads the solution out of it and prints a digest of the same data:

{'vehicles': {'used': 2, 'unused': 0}, 'jobs': {'scheduledTasks': 3, 'unassignedTasks': 0}}
Vehicle 1 -> [1001]

That's a complete round-trip. 🎉

3. Where to go next

  • How optimization works — the poll pattern in detail (interval, backoff).
  • API reference — every field, live, with Try it out.
  • Recipes — add time windows, skills, capacities, pickups+deliveries, or re-optimization.

Timestamps must carry a time zone

Every time value is ISO 8601 with an offset (e.g. -07:00). Keep the same time zone across the whole payload — the solution comes back in that time zone.

Related: Authentication · How optimization works · Status codes