Skip to content

Tarot Routing - Route Optimisation API

Request

RoutingProblem

A RoutingProblem is the body of the request sent to the Route Optimisation API endpoint.

Fields:

Name Type Required Description
drivers list of Driver Yes The drivers to perform the jobs.
jobs list of Job Yes The jobs to be optimised.
settings Settings No null (empty settings)

Minimal Example:

ex1.json
    {
      "drivers": [
        {
          "uid": "drvid1",
          "shift_start": 8,
          "shift_end": 17,
          "start": {"lat": -33.867798, "lon": 151.166256},
          "end": "start"
        }
      ],
      "jobs": [
        {
          "uid": "uid1",
          "duration": 2,
          "location": {"lat": -33.849489, "lon": 151.127482}
        },
        {
          "uid": "uid2",
          "duration": 2,
          "location": {"lat": -33.880661, "lon": 151.183096}
        },
        {
          "uid": "uid3",
          "duration": 2,
          "location": {"lat": -33.913168, "lon": 151.262267}
        }
      ],
      "settings": {}
    }

Driver

A Driver represents a driver, their vehicle, or a theoretical run.

Fields:

Name Type Required Default Description
uid string Yes Unique identifier for this driver.
start Location Yes Where the driver begins their run. (Previously location)
end string or Location No "start" Where the driver finishes their run. "start" = returns to start; "anywhere" = finish at last served job; a Location = fixed end different from start. No other values are allowed
shift_start float Yes* Earliest time the driver may begin their (single) shift (24h float, e.g. 8.5). Omit when using multi_shift.
shift_end float Yes* Latest time the driver may end their (single) shift (24h float, e.g. 18.5). Omit when using multi_shift.
multi_shift MultiShift No Several Shifts in one request. Replaces shift_start / shift_end. If any Driver has this, every Driver must have it. See Multi-Shift.
capacity int or str No Capacity of the vehicle.
spec_type string No Only jobs with matching spec_type can be served.
territories string No Only jobs with matching territories can be served.
costs Costs No Cost coefficients for this driver. Required when optimisation_objective = "cost".
speed_multiplier float No 1 Driving-speed multiplier for this Driver. 0.5 means half as fast (travel takes twice as long); 1.2 means 20% faster. Does not change service time, parking, waiting, or distance. Must be finite and greater than 0. See Speed multiplier.
end_location Location Deprecated Deprecated legacy field. Use end instead (e.g. "start" or a Location). Ignored if end supplied.
end_anywhere bool Deprecated false Deprecated legacy flag. Use "anywhere" via the unified end field.
location Location Deprecated Deprecated legacy alias for start. Will be removed in a future release.

* shift_start and shift_end are required on a single-shift Driver. On a multi-shift Driver they are omitted and multi_shift is required instead. You cannot mix the two shapes in one request.

Deprecated Fields: location, end_location, and end_anywhere are accepted for backwards compatibility but will be removed in a future release. Prefer the unified start and end interface. If both new and legacy fields are supplied the request will be rejected (end + end_location / end_anywhere) or the legacy value ignored (location if start present).

Minimal Example (return to start):

{
  "uid": "driver_1",
  "start": {"lat": -33.867798, "lon": 151.166256},
  "end": "start",
  "shift_start": 9.5,
  "shift_end": 18.5
}

Finish Anywhere Example (end at last job visited):

{
  "uid": "driver_2",
  "start": {"lat": -33.867798, "lon": 151.166256},
  "end": "anywhere",
  "shift_start": 9.5,
  "shift_end": 18.5
}

Different Fixed End Location Example:

{
  "uid": "driver_3",
  "start": {"lat": -33.880661, "lon": 151.183096},
  "end": {"lat": -33.900001, "lon": 151.210000},
  "shift_start": 8.0,
  "shift_end": 17.5
}

Multi-Shift Example (two last-mile days):

{
  "uid": "driver_4",
  "start": {"lat": -33.867798, "lon": 151.166256},
  "end": "start",
  "multi_shift": {
    "mode": "reset",
    "shifts": [
      {
        "shift_start": {"day": 1, "time": 8},
        "shift_end": {"day": 1, "time": 17}
      },
      {
        "shift_start": {"day": 2, "time": 8},
        "shift_end": {"day": 2, "time": 17}
      }
    ]
  }
}

Job

A Job represents a task, delivery point, or customer.

Fields:

Name Type Required Default Description
uid string Yes Unique identifier for this job.
location Location Yes Where the job is.
duration float Yes Minutes spent serving this job once on site (after any parking).
parking_duration float No 0 Minutes of parking/docking after ETA, contiguous with duration. Applied only when driving time from the previous stop (including driver start) is nonzero. etd = eta + parking + duration when applied.
pickup_from string No UID of the pickup Job that this Job carries from. Same Driver; the item stays on the vehicle. See Pickup Delivery.
later_than string No UID of a Job that must be arrived at strictly earlier. Time order only — not the same Driver, and not a carried load. See Later Than.
multi_shift JobMultiShift No Multi-shift-only Job fields. Currently serve_within date windows. Only valid when every Driver uses multi_shift.
route_segment string|null No null Where this job may appear in a route. Allowed values: "start", "end", or null. Use "start" to fix a job to the first/start block of a route, "end" to fix it to the final block, or null to allow it anywhere.
arrive_after float No Earliest ETA (arrival, before parking) as a 24h float.
leave_by float No Latest ETD (after parking and service) as a 24h float.
size float or str No Size for capacity constraints. May be negative on deliveries to free load.
spec_type string No Only drivers with matching spec_type can serve this job.
territories string No Only drivers with matching territories can serve this job.
unserved_penalty_factor float No 1 How much this job matters relative to others if something must be left unserved. 2 means “worth two ordinary jobs”. See Unserved penalty factor.

Minimal Example:

{
  "uid": "unique_job_id_1",
  "duration": 10,
  "location": {"lat": -33.849489, "lon": 151.127482}
}

Standard Example:

{
  "uid": "unique_job_id_2",
  "duration": 10,
  "parking_duration": 5,
  "arrive_after": 10,
  "leave_by": 16.5,
  "location": {"lat": -33.84948962, "lon": 151.1274823}
}

Fix First/Last Job Example:

Set route_segment to "start" when a job should be served at the beginning of a route, or "end" for the final block. If multiple "start" jobs are assigned to the same route, they will form the initial block of jobs; their internal order is chosen by the optimiser. The same applies to "end" jobs at the end of the route. Use null (or omit the field) for jobs that may appear anywhere.

{
  "uid": "important_first_customer",
  "duration": 10,
  "route_segment": "start",
  "location": {"lat": -33.84948962, "lon": 151.1274823}
}

Later Than Example:

{
  "uid": "install_site",
  "duration": 40,
  "later_than": "inspect_site",
  "location": {"lat": -33.880661, "lon": 151.183096}
}

Location

A Location defines the geographical position of a driver or job.

Name Type Required Description
lat float Yes Latitude
lon float Yes Longitude

Example:

{
  "lat": -33.88066125,
  "lon": 151.1830961
}

PlanningTime

A point in a multi-shift planning horizon: a one-based Planning Day plus a clock time.

Name Type Required Description
day int Yes Planning Day in this request. 1 is the first day. Maximum 100.
time float or string Yes Clock time on that day. Accepts a 24h float (8, 8.5) or "HH:MM[:SS]". Response always uses "HH:MM:SS".

Example:

{ "day": 2, "time": 8 }
{ "day": 2, "time": "08:00" }

MultiShift

Replaces shift_start / shift_end on a Driver when the request covers more than one Shift. See Multi-Shift.

Name Type Required Default Description
mode string No "reset" "reset" — each Shift is a new trip from start to end. "continue" — one journey; the Driver stays put between Shifts.
shifts list of Shift Yes The Driver's Shifts. May be empty to mark the Driver unavailable.

Reset Example:

{
  "mode": "reset",
  "shifts": [
    {
      "shift_start": {"day": 1, "time": 8},
      "shift_end": {"day": 1, "time": 17}
    },
    {
      "shift_start": {"day": 2, "time": 8},
      "shift_end": {"day": 2, "time": 17}
    }
  ]
}

Continue Example:

{
  "mode": "continue",
  "shifts": [
    {
      "shift_start": {"day": 1, "time": 8},
      "shift_end": {"day": 1, "time": 18}
    },
    {
      "shift_start": {"day": 2, "time": 8},
      "shift_end": {"day": 2, "time": 18}
    }
  ]
}

Shift

One period of availability for a multi-shift Driver.

Name Type Required Description
shift_start PlanningTime Yes When this Shift begins. Must be before shift_end.
shift_end PlanningTime Yes When this Shift ends. May be on a later day.

Shifts on one Driver must not overlap. Back-to-back Shifts are allowed.


JobMultiShift

Multi-shift-only fields on a Job. Omit the object, or use an empty serve_within list, to allow any time in the planning horizon.

Name Type Required Default Description
serve_within list of ServeWithinPeriod No [] Absolute periods in which this Job may be served. Combined with OR. Each period must set arrive_after, leave_by, or both.

Example:

{
  "serve_within": [
    {
      "arrive_after": {"day": 2, "time": 8},
      "leave_by": {"day": 2, "time": 17}
    }
  ]
}

ServeWithinPeriod

One absolute window for a multi-shift Job.

Name Type Required Description
arrive_after PlanningTime No Earliest arrival in this period.
leave_by PlanningTime No Latest departure in this period.

At least one of the two fields is required.

Together with top-level arrive_after / leave_by (recurring clock hours every Planning Day):

recurring service hours
AND
(serve_within[0] OR serve_within[1] OR ...)

Settings

Settings convey parameters which affect the way the optimisation algorithm runs.

Name Type Required Default Description
time_limit int No null (No Limit) Seconds Max seconds allowed for optimisation.
unimproved_time_limit int No n_locs / 20 if no time_limit else null (no limit) When the optimiser's best solution plateaus for this many seconds, finish the optimisation
iter_limit int No null Sets a maximum number of iterations allowed.
unimproved_iter_limit int No null Sets the maximum number of iterations the optimiser is allowed to continue without any improvement between iterations.
traffic_date string No null yyyy-mm-dd Enables traffic optimisation for this date. In a multi-shift request this date is Planning Day 1; later Planning Days follow it.
parallel string No auto Enable or disable parallel solving. Can be false, true, or auto. If auto, parallel solving is enabled if n_locs (total locations) is >= 200.
optimisation_objective string No "time" The objective to minimise: "time" (default), "distance", or "cost". If "cost", requires Costs on every driver. See Concepts.
later_shift_usage_penalty float No 0 Penalty on used time on later declared Shifts, per used second per day-late. Omit, null, and 0 are off. Must be finite and ≥ 0. Same addend on every optimisation_objective. Not a hard constraint. See Later shift usage penalty.
active_vehicle_penalty float No 0 Lump on each compiled vehicle that serves at least one Job. Ordinary and continue: once per Driver; reset: once per Shift. Omit, null, and 0 are off. Must be finite and ≥ 0. Same unscaled addend on every optimisation_objective. Stacks with costs.run in cost mode (different units). Not a hard fleet cap. See Active vehicle penalty.

Minimal Example:

{}

Standard Example:

{
  "time_limit": 120
}

Cost Optimisation Example:

When using optimisation_objective = "cost", you must provide Costs for every driver:

{
  "settings": {
    "optimisation_objective": "cost",
    "time_limit": 120
  },
  "drivers": [
    {
      "uid": "driver_1",
      "start": {"lat": -33.867798, "lon": 151.166256},
      "end": "start",
      "shift_start": 9.0,
      "shift_end": 17.0,
      "costs": {
        "km": 0.20,
        "hour": 25.00,
        "job": 5.00,
        "run": 100.00
      }
    }
  ]
}

See Optimisation Objective in the Concepts guide for more details on when to use each objective.


Costs

Costs are used when Settings.optimisation_objective = "cost" and represent costs to be minimised by the optimiser. Currency is arbitrary but must be consistent across all drivers.

If you set optimisation_objective = "cost", you must provide costs for every Driver.

Name Type Required Default Description
km float No 0 Cost per kilometre driven by this driver.
hour float No 0 Cost per hour that this driver is working. Includes driving, stopped at jobs, waiting for time windows, etc.
job float No 0 Cost per job that this driver performs.
run float No 0 Cost for this driver being active (i.e. serving any jobs). Useful for minimising the number of drivers used.

Tip

Setting different run costs for each driver encourages the optimiser to favour certain drivers over others.

Minimal Example:

{}

Standard Example:

{
  "km": 0.20,
  "hour": 12.00,
  "job": 7.00,
  "run": 150.00
}

Response

RoutingSolution

A RoutingSolution is the main response object returned by the API.

Fields:

Name Type Description
runs list of Run The list of runs (routes) for each driver.
unserved_jobs list of Job Jobs which the optimiser could not find a way to visit.

Run

A Run represents a planned route for a single driver.

Fields:

Name Type Description
driver Driver The driver assigned to this run. In a multi-shift response this includes driver.multi_shift.mode and omits shift_start / shift_end.
jobs list of SolutionJob The sequence of jobs in this run.
multi_shift object Present on every Run in a multi-shift response. shift is the 1-based Shift number; planned_start / planned_end are PlanningTime values (null if the Shift is unused); planned_start_location / planned_end_location are the actual ends of this Shift.

SolutionJob

A SolutionJob is identical to the original Job you sent, but with extra fields describing its placement in the solution.

Fields:

Name Type Description
route_segment string|null Echoes the requested route segment: "start", "end", or null. If omitted in the request, it is returned as null.
run int 1-based index indicating which run this job is planned in. null if unserved.
seq int 1-based sequence of this job within the run. null if unserved.
eta string Arrival at the job, before parking (HH:MM:SS). null if unserved. Omitted on multi-shift Jobs; use multi_shift.eta.

| etd | string | Departure after parking (if applied) and service (HH:MM:SS). null if unserved. Omitted on multi-shift Jobs; use multi_shift.etd. |

| later_than | string | Echo of the requested later_than uid, when set. | | multi_shift | object | Present on every Job in a multi-shift response. eta / etd are PlanningTime values, or null if unserved. |


Example Response:

{
  "runs": [
    {
      "driver": {
        "uid": "drvid1",
        "location": {"lat": -33.84948962, "lon": 151.1274823},
        "shift_start": 9.5,
        "shift_end": 18.5
      },
      "jobs": [
        {
          "uid": "unique_job_id_1",
          "duration": 10,
          "location": {"lat": -33.849489, "lon": 151.127482},
          "route_segment": "start",
          "run": 1,
          "seq": 1,
          "eta": "09:45:00",
          "etd": "09:55:00"
        }
      ]
    }
  ],
  "unserved_jobs": []
}

Asynchronous Route Optimisation API Responses

These response types are specific to the asynchronous Post and Poll endpoints.

PollingStartResponse

The response returned by POST /v2/polling/vrp with status code 202 Accepted.

Fields:

Name Type Description
uid string Unique identifier for this optimization request. Use to query status and retrieve solution.
status_url string Complete URL to GET the optimization status.
solution_url string Complete URL to GET the final solution when complete.

Example Response:

{
  "uid": "01GG7AEX026F47CS4NK2JBCE5G",
  "status_url": "https://opt.route.optimiser.app/v2/polling/vrp/01GG7AEX026F47CS4NK2JBCE5G/status",
  "solution_url": "https://opt.route.optimiser.app/v2/polling/vrp/01GG7AEX026F47CS4NK2JBCE5G"
}

PollingStatusResponse

The response returned by GET /v2/polling/vrp/{uid}/status with status code 200 OK.

Fields:

Name Type Description
uid string The unique identifier from the start request.
timestamp string ISO 8601 timestamp when this status was recorded.
message string Human-readable description of the current optimization state.
solving boolean true if optimization is still running, false if complete.
cost number Current best solution cost. 0 while solving hasn't started computing costs.
next_status_eta string or null ISO 8601 timestamp recommending when to check status again. null when solving is complete.

Example Response (Solving in Progress):

{
  "uid": "01GG7AEX026F47CS4NK2JBCE5G",
  "timestamp": "2022-10-25T12:19:26.129294+02:00",
  "message": "Started solving...",
  "solving": true,
  "cost": 0,
  "next_status_eta": "2022-10-25T12:19:30.129134+02:00"
}

Example Response (Solving Complete):

{
  "uid": "01GG7AEX026F47CS4NK2JBCE5G",
  "timestamp": "2022-10-25T12:19:33.421031+02:00",
  "message": "The Improvement Threshold has been reached.",
  "solving": false,
  "cost": 57516,
  "next_status_eta": null
}