Understanding the Response

TL;DR

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

ValueMeaning
optimalSolver proved this is the best possible solution (or hit a proof within tolerance). Safe to use directly.
feasibleA 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.
infeasibleNo valid solution exists given the constraints as stated. Check infeasibility_report and unserved for why.
timeoutThe 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).
errorAn 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:

TypeMeaning
startVehicle departs its starting depot.
endVehicle arrives at its ending depot (route closes).
serviceA regular job is serviced.
pickupThe pickup leg of a shipment.
deliveryThe delivery leg of a shipment.
breakA driver break (explicit or auto-generated).
reloadA stop at a dump station to reset capacity.
waitThe vehicle is idle, waiting for a time window to open.

Common fields on an activity:

FieldMeaning
arrival_timeWhen the vehicle reaches this stop's location.
departure_timeWhen the vehicle leaves this stop (after waiting + service).
waiting_timeSeconds spent idle before service could start (vehicle arrived before the window opened).
service_timeSeconds actually spent servicing the stop.
load_on_arrivalVehicle's carried load (per dimension) just before this stop's demand is applied.
load_on_departureVehicle'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:

ReasonWhat it meansWhat to do
no_feasible_vehicleNo 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_infeasibleNo 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_infeasibleEvery 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_mismatchNo eligible resource has the required skill at the required level.Add a skilled resource or lower required skill_levels.
dropped_by_solverThe 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_constraintThe job's pinned day has no available eligible resource.Check resource available_days against the job's day.
penalty_too_lowmandatory=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_restrictionThe 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-2 picking up job-7734 (load rises from 0 to 220kg), taking a scheduled break, dumping its load at dump-1 (load resets to 0), then returning to depot.
  • job-7790 is unserved with reason capacity_infeasible — the reason_detail spells out exactly why, so you know to either add capacity or accept the drop.
  • score breaks 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.
Next steps

FieldGenius VRP API documentation. Generated from the engineering source of truth (.tex docs and app/ source).