Skip to main content

Overview

POST /v3/routing/evaluate takes a problem and a plan and tells you what that plan is worth. It computes arrival times, loads and the cost breakdown exactly as a solve would, and lists every hard constraint the plan breaks. It never moves a stop. Typical uses:
  • Check a plan a dispatcher edited by hand before you commit it.
  • Compare your current planning against a solve result on the same cost model.
  • Get the full timeline after you apply a suggestion.
  • Re-score yesterday’s plan against today’s constraints.

The request

object
required
The same problem object as on /v3/routing/solve. See the V3 API model.
object
required
The plan to score: routes[], one entry per vehicle shift that serves something.
Evaluate takes no options: there is no search, so there is nothing to tune. An options key is rejected as an unknown field.

The plan shape

The value of plan:
A stop is one of: Start, end and break stops are not listed; they are placed for you. Every solve and evaluate response returns its routes in this shape as plan, so a result’s plan can be sent back unchanged. A task you leave out of every route is not an error. It is reported in unassigned[], with a category that says whether it could be added: see What unassigned means on evaluate.

Example

The quickstart’s two deliveries, with delivery-1 due by 11:00 local time and a hand-made plan that visits delivery-2 first:

The response

The response has the same four parts as a solve response: summary, routes, plan and unassigned. The figures below are illustrative; yours depend on live travel times.
The truck reaches delivery-1 at 09:29:20 UTC, 1,760 seconds after its window closed at 09:00:00 UTC. The plan is still scored in full, so you can see what it would cost and how late it would be.

How it differs from a solve response

Everything else, including the stop timeline and score.components, reads exactly as on solve. See the Quickstart for the stop fields and Objective function for the cost breakdown. In a request that contains shipments, summary.jobs_assigned counts a shipment in the plan twice, once for each of its stops, and a shipment left out of the plan once. Use the length of unassigned[], which has one entry per job or shipment, to count what the plan leaves out.

What unassigned means on evaluate

Evaluate never adds a task to your plan. For each task the plan leaves out, unassigned[].category tells you whether it could be added to the plan as it stands: A task that fits is reported with reason code SOLVER_LIMIT and a message about a time budget. That wording comes from solve; evaluate has no time budget. To place such a task, add it to plan or ask /v3/routing/suggest for its best position. The reason codes are listed in Errors.

Violations

Each violation is { "type", "message" }. type is a stable string to branch on; message is for people. New types can be added as new constraints ship. Handle the ones you care about and treat anything else as a generic violation.
A time window priced as soft, through time_windows[].per_late_hour or objective.costs.per_late_hour, is not a violation when it is missed. The lateness shows up in the stop’s lateness_s and in score.components.lateness instead.

What evaluate checks, and when

Evaluate needs real travel times to compute a timeline, so it fetches them the same way solve does. What it skips is the search.
  1. The request is validated. Schema, references and limits are checked first. A problem here is a 400 and no travel times are fetched.
  2. Travel times are fetched.
  3. The plan is matched to the problem. A plan that cannot be laid out at all is a 400 with pointer /plan/routes/{i} or /plan/routes/{i}/stops/{k}: an unknown vehicle, shift, stop or depot id; a route or stop listed twice; a stop whose type does not match the task; a shipment whose pickup and delivery are not both on one route, pickup first; a misplaced reload; more than 8 reloads at one depot; more trips than max_trips; a locked_count larger than the number of stops.
  4. The plan is scored. Everything else, such as a missed window or an overloaded vehicle, is reported as a violation in a 200 response.

validate_only

POST /v3/routing/evaluate?validate_only=true runs step 1 only and returns 200 {"valid": true, "warnings": []} or the 400 the real call would return. It checks problem; it does not look at plan, because matching the plan needs the later steps.

Errors

Evaluate returns the same error body and status codes as solve. A plan with violations is not an error: it is a 200 with summary.status: "infeasible".

Suggest

Find the best slot for a new task in a plan you keep.

Errors

The error body, every code, and what to do about each.

Constraints

The rules behind each violation type.

API reference

Request and response schema for every endpoint.