Skip to content

Quickstart: your first optimization

~10 min · 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.

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, "demand": [2]}]},
        {"id": 102, "deliveries": [{"id": 1002, "location": [49.24660, -123.06340], "duration": 300, "demand": [1]}]},
        {"id": 103, "deliveries": [{"id": 1003, "location": [49.28150, -123.12070], "duration": 300, "demand": [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, "demand": [2]}]},
            {"id": 102, "deliveries": [{"id": 1002, "location": [49.24660, -123.06340], "duration": 300, "demand": [1]}]},
            {"id": 103, "deliveries": [{"id": 1003, "location": [49.28150, -123.12070], "duration": 300, "demand": [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": "b1f2c3d4-5e6f-7890-abcd-ef1234567890", "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 solve runs you'll get 202; when it's done you'll get 200 with the full solution.

curl https://iq.scheduledroutes.ddswireless.net/raas/optimization/b1f2c3d4-5e6f-7890-abcd-ef1234567890 \
  -H "Authorization: Bearer YOUR_API_KEY"
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 solving — 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"]])

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'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 timezone

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

Related: Authentication · How optimization works · Status codes