Understanding the Response
Every OptimizationResponse has a status, a routes array of per-vehicle activity timelines, an unserved array explaining anything that didn't get scheduled, and a score breakdown. Nothing is silently dropped — every job either appears in a route or in unserved with a specific reason.
status
| Value | Meaning |
|---|---|
optimal | Solver proved this is the best possible solution (or hit a proof within tolerance). Safe to use directly. |
feasible | A valid solution was found but the solver was not able to prove optimality (usually because time_limit_seconds was reached first). Usable, but a longer time limit might do better. |
infeasible | No valid solution exists given the constraints as stated. Check infeasibility_report and unserved for why. |
timeout | The solver ran out of time before finding any feasible solution at all (worse than feasible — here there are zero routes, not just an unproven one). |
error | An internal error occurred during solving; check warnings and server logs. |
routes and activities
Each entry in routes is one Route: resource_id, day, a list of activities, a summary, and any violations. Each activity has a type:
| Type | Meaning |
|---|---|
start | Vehicle departs its starting depot. |
end | Vehicle arrives at its ending depot (route closes). |
service | A regular job is serviced. |
pickup | The pickup leg of a shipment. |
delivery | The delivery leg of a shipment. |
break | A driver break (explicit or auto-generated). |
reload | A stop at a dump station to reset capacity. |
wait | The vehicle is idle, waiting for a time window to open. |
Common fields on an activity:
| Field | Meaning |
|---|---|
arrival_time | When the vehicle reaches this stop's location. |
departure_time | When the vehicle leaves this stop (after waiting + service). |
waiting_time | Seconds spent idle before service could start (vehicle arrived before the window opened). |
service_time | Seconds actually spent servicing the stop. |
load_on_arrival | Vehicle's carried load (per dimension) just before this stop's demand is applied. |
load_on_departure | Vehicle's carried load just after this stop's demand is applied (e.g. after a pickup adds load, or a reload zeroes it). |
RouteSummary
summary aggregates the whole route: typically total_distance, total_time, and jobs_served (exact field set may include additional totals such as driving time vs waiting time).
unserved jobs
Every job the solver could not place appears here as an UnservedJob: id, type (job/shipment), reason, and reason_detail (free-form elaboration). The reason is always one of eight codes:
| Reason | What it means | What to do |
|---|---|---|
no_feasible_vehicle | No resource satisfies this job's eligibility constraints at all (skills, allowed_resource_ids, capacity ceiling). | Check the job's skill/eligibility requirements against your fleet; you may need another vehicle. |
time_window_infeasible | No resource can reach the job inside its hard time window given travel times and other commitments. | Widen the window, add early/late_penalty to make it soft, or reduce competing load on that time slot. |
capacity_infeasible | Every eligible vehicle would exceed a capacity dimension if this job were added. | Add capacity, split the job, or add a dump_station/reload point. |
skill_mismatch | No eligible resource has the required skill at the required level. | Add a skilled resource or lower required skill_levels. |
dropped_by_solver | The job was technically feasible but mandatory=false and the solver chose to pay the penalty instead of serving it. | Raise penalty if the job must be served, or accept the tradeoff. |
day_constraint | The job's pinned day has no available eligible resource. | Check resource available_days against the job's day. |
penalty_too_low | mandatory=false and the penalty was cheaper than serving the job even though it was feasible. | Raise the penalty if you actually want the job served. |
zone_restriction | The job's location falls in a zone restricted to resources that aren't eligible/available. | Check zones[].allowed_resource_ids against the assignable fleet. |
ScoreBreakdown
score reports the components that make up the solution's total cost (e.g. total, distance cost, time cost, penalty cost, fairness adjustments). Use it to compare alternative requests (different fleets, different constraint relaxations) on the same numeric basis.
Annotated full example
{
"status": "feasible",
"problem_id": "rotterdam-am-route-07",
"solve_time_ms": 4870,
"routes": [
{
"resource_id": "truck-2",
"day": 0,
"activities": [
{ "type": "start", "location_index": 0, "arrival_time": 0, "departure_time": 0 },
{ "type": "service", "job_id": "job-7734", "location_index": 4, "arrival_time": 1800, "departure_time": 2400, "service_time": 600, "waiting_time": 0, "load_on_arrival": { "weight_kg": 0 }, "load_on_departure": { "weight_kg": 220 } },
{ "type": "break", "arrival_time": 16200, "departure_time": 18000, "service_time": 1800 },
{ "type": "reload", "dump_station_id": "dump-1", "location_index": 9, "arrival_time": 21600, "departure_time": 22500, "service_time": 900, "load_on_arrival": { "weight_kg": 980 }, "load_on_departure": { "weight_kg": 0 } },
{ "type": "end", "location_index": 0, "arrival_time": 27000, "departure_time": 27000 }
],
"summary": { "total_distance": 41200, "total_time": 27000, "jobs_served": 1 },
"violations": []
}
],
"unserved": [
{ "id": "job-7790", "type": "job", "reason": "capacity_infeasible", "reason_detail": "Adding 320kg would exceed truck-2's 1000kg waste capacity after job-7734 and before the next reload." }
],
"score": { "total": 41200, "distance_cost": 20600, "time_cost": 18000, "penalty_cost": 2600 },
"diagnostics": null,
"infeasibility_report": null,
"warnings": []
}
status: feasible— a valid plan exists but the solver wasn't able to prove it's optimal (likely hit its time limit).- The route shows
truck-2picking upjob-7734(load rises from 0 to 220kg), taking a scheduled break, dumping its load atdump-1(load resets to 0), then returning to depot. job-7790is unserved with reasoncapacity_infeasible— thereason_detailspells out exactly why, so you know to either add capacity or accept the drop.scorebreaks total cost into distance, time, and penalty components, making it easy to see that the dropped job's penalty (2,600) is a small fraction of the total.
- Constraints — understand the levers that determine which jobs end up served vs unserved.
- Best Practices — sizing time limits and choosing mandatory/penalty values deliberately.
- OptimizationResponse schema — exhaustive field reference.