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
JavaScript
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 reoptimize and some preserveOrder operations. 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.