How to Edit an Optimized Route Plan
- API or service
- Route Optimization SDK + Route Planner API
- Task
- Optimized result and dispatcher changes → updated route plan
- Examples
- Difficulty
- Intermediate
- Time
- 12 min
Edit an optimized route plan
A dispatcher may need to change a plan after optimization because a driver becomes unavailable, a customer cancels, a new urgent task arrives, or the preferred stop order changes.
Use @geoapify/route-planner-sdk to create a RoutePlannerResultEditor from an SDK result. The editor can reassign, add, or remove jobs and shipments; move a waypoint; add a schedule delay; reoptimize one agent; and return an updated result snapshot.
Task flow: optimized RoutePlannerResult → editor operation and strategy → validate affected agents → read and persist the modified result.
Understand the Geoapify Route Optimization SDK
@geoapify/route-planner-sdk is a dependency-free TypeScript library for browser and Node.js applications. It wraps the Route Planner API with input builders, typed result objects, editing helpers, and timeline visualization.
| SDK component | Purpose |
|---|---|
RoutePlanner |
Build and execute Route Planner API requests |
Agent, Job, Shipment, ShipmentStep, Location, Break, Avoid |
Build typed optimization input |
RoutePlannerResult |
Read raw or normalized results and find plans by stable ID or index |
AgentPlan, JobPlan, ShipmentPlan |
Inspect assignments, schedules, waypoints, route legs, and violations |
RoutePlannerResultEditor |
Reassign, add, remove, reorder, delay, and reoptimize planned work |
RoutePlannerTimeline |
Render time- or distance-based agent schedules in a web interface |
Use the SDK when an application needs to construct or edit route plans in JavaScript or TypeScript. Direct HTTP requests remain appropriate for other languages, thin server integrations, or systems that already generate and validate the API's JSON contract.
This guide uses the current version 2 method signatures. Version 1 applications should follow the SDK migration guide because result method names and editor option signatures changed.
Create an editable route plan with JavaScript
Install the SDK and use RoutePlanner.plan() to receive the RoutePlannerResult required by the editor.
npm install @geoapify/route-planner-sdk
import {
Agent,
Job,
RoutePlanner,
RoutePlannerResultEditor
} from "@geoapify/route-planner-sdk";
const planner = new RoutePlanner({ apiKey: "YOUR_API_KEY" });
planner
.setMode("drive")
.addAgent(
new Agent()
.setId("agent-a")
.setStartLocation(13.4132, 52.5219)
.setEndLocation(13.4132, 52.5219)
)
.addAgent(
new Agent()
.setId("agent-b")
.setStartLocation(13.3904, 52.5076)
.setEndLocation(13.3904, 52.5076)
)
.addJob(
new Job()
.setId("job-101")
.setLocation(13.3777, 52.5163)
.setDuration(300)
)
.addJob(
new Job()
.setId("job-102")
.setLocation(13.4397, 52.505)
.setDuration(300)
);
const result = await planner.plan();
const editor = new RoutePlannerResultEditor(result);
SDK coordinate setters receive longitude first and latitude second, matching the Route Planner API's [longitude, latitude] order.
The editor clones the supplied result. It does not mutate result; retrieve the edited snapshot with editor.getModifiedResult().
Choose an editing operation
| Dispatcher action | Editor method |
|---|---|
| Move existing jobs to another agent | assignJobs(agent, jobs, options) |
| Move linked pickup-delivery orders | assignShipments(agent, shipments, options) |
| Add new independent work | addNewJobs(agent, jobs, options) |
| Add new pickup-delivery work | addNewShipments(agent, shipments, options) |
| Cancel or unassign jobs | removeJobs(jobs, options) |
| Cancel or unassign shipments | removeShipments(shipments, options) |
| Move a stop within one agent route | moveWaypoint(agent, fromIndex, toIndex) |
| Add schedule delay after a stop | addDelayAfterWaypoint(agent, waypointIndex, seconds) |
| Reoptimize one agent plan | reoptimizeAgentPlan(agent, options) |
| Read the current edited snapshot | getModifiedResult() |
Agent, job, and shipment arguments accept stable string IDs or zero-based indexes. Prefer IDs in application code because an ID keeps its meaning when arrays are filtered or rebuilt.
Assigning a shipment always moves its pickup and delivery together. Use moveWaypoint() only when the application deliberately edits one agent's visit order; validate the result afterward because waypoint movement can conflict with time windows, capacities, or pickup-delivery precedence.
Choose an editing strategy
Assignment, addition, and removal operations support two strategies:
| Requirement | Options | Processing |
|---|---|---|
| Find the best updated plan | { strategy: "reoptimize" } or omit strategy |
Calls Route Planner API and may reorder affected work |
| Keep existing stops ordered and find an insertion point | { strategy: "preserveOrder" } |
Uses Route Matrix API to choose the insertion position |
| Insert after a known job or shipment | { strategy: "preserveOrder", afterId: "job-101" } |
Constrains matrix-assisted insertion after the matching waypoint |
| Insert after a waypoint index | { strategy: "preserveOrder", afterWaypointIndex: 1 } |
Constrains insertion after that waypoint |
| Append without an optimization call | { strategy: "preserveOrder", append: true } |
Adds work at the end of the agent route locally |
| Insert directly after a position | { strategy: "preserveOrder", afterId: "job-101", append: true } |
Inserts locally after the selected position |
Use full reoptimization after material plan changes when solution quality matters most. Use preserveOrder when dispatchers have already committed to the current sequence or need a faster, less disruptive edit.
Regular edits are soft: the SDK applies the requested change and records constraint violations on affected agent plans. For a strict cleanup pass, call reoptimizeAgentPlan(agent, { allowViolations: false }). Set includeUnassigned: true only when unassigned work should be considered for that agent.
Reassign and inspect a job with JavaScript
This function moves job-101 to agent-b without reordering the agent's existing stops. It returns the modified SDK result and the violations that the application must review.
import { RoutePlannerResultEditor } from "@geoapify/route-planner-sdk";
export async function reassignJob(plannerResult) {
const editor = new RoutePlannerResultEditor(plannerResult);
const changed = await editor.assignJobs(
"agent-b",
["job-101"],
{ strategy: "preserveOrder" }
);
if (!changed) {
throw new Error("The route plan was not changed");
}
const modifiedResult = editor.getModifiedResult();
const jobPlan = modifiedResult.getJobPlan("job-101");
const agentPlan = modifiedResult.getAgentPlan("agent-b");
return {
modifiedResult,
assignedAgentId: jobPlan?.getAgentId(),
violations: agentPlan?.getViolations() ?? []
};
}
The input must be a RoutePlannerResult, normally returned by RoutePlanner.plan(). A raw object returned by a manual fetch() call is not the same SDK wrapper.
After the edit, assignedAgentId should be agent-b. Do not publish or dispatch the modified plan until violations has been reviewed.
Validate and persist route edits
- Read the edited snapshot from
getModifiedResult()after every accepted operation. The original result passed to the editor remains unchanged. - Inspect
getViolations()on every affected agent. Soft editing operations may preserve the requested manual change while reporting capacity, capability, time-window, or break violations. - Use
reoptimizeAgentPlan(agent, { allowViolations: false })when an invalid edited route must not be accepted. - Prevent overlapping edits against the same plan. Queue dispatcher actions or apply optimistic concurrency when several users can edit simultaneously.
- Persist stable agent, job, and shipment IDs with the plan version. Avoid saving only current array indexes.
- Record the operation, strategy, actor, and previous snapshot when the application requires audit history or undo.
- Expect API calls from
reoptimizeand somepreserveOrderoperations. Show pending and failure states and do not replace the last usable plan until the operation succeeds. - Restrict browser API keys to allowed origins. For server-side planners, keep the key in environment or secret configuration.
- Update maps and timelines from the new
RoutePlannerResult.RoutePlannerTimeline.setResult()can refresh an SDK timeline after an edit.
The SDK simplifies input construction, result inspection, editing, and timeline rendering. Your application still owns authorization, collaborative-editing rules, persistence, audit history, and the final decision to dispatch a modified plan.