Routing

Optimize jobs and shipments across agents

Signed in? Open this endpoint in the dashboard playground, which uses your organization automatically. Signed out, use Try in Playground below with your API key.

POST
/routeplanner

Optimizes jobs and pickup-delivery shipments across one or more agents.

  • Send mode, agents, and at least one non-empty jobs or shipments array in a JSON body.
  • Coordinates use GeoJSON order: [longitude, latitude]; reusable entries in locations can be referenced by index.
  • Agent capabilities must satisfy task requirements; capacities, priorities, durations, time windows and breaks constrain assignment and order.
  • A task may contain at most 300 unique coordinates across locations, agents, jobs and shipments (300 x 300 = 90,000 matrix pairs); more returns 400. Also at most 100 agents, 1000 jobs, 1000 shipments and 1000 locations.
  • Each returned GeoJSON feature is one agent plan with actions, waypoints, route legs, timing, distance and MultiLineString geometry.
  • Unassigned agents, jobs or shipments are reported in properties.issues.

How it works: the gateway computes a Valhalla matrix honouring mode, type, avoid and max_speed, hands it to the VROOM optimizer, then asks Valhalla for the legs and geometry of each agent's route.

Example:

curl -X POST "https://api.data.graphitelab.ai/v1/routeplanner?apiKey=YOUR_API_KEY" \  -H "Content-Type: application/json" \  -d '{"mode":"drive","agents":[{"start_location":[-86.1581,39.7684]}],"jobs":[{"location":[-86.1478,39.7653]}]}'

Deviation (ignored): traffic is accepted but routes are always free-flow.

Deviation (approximated): an agent with several time_windows is solved against their hull (earliest start to latest end).

Deviation (approximated): avoid rules green_zones, transfers and country_codes are accepted but have no effect; tolls, highways and ferries are soft preferences.

Deviation (unsupported): modes transit and approximated_transit are not supported (no transit data); the request schema does not list them.

Not supported: the transit and approximated_transit travel modes. Every other documented field is read by the gateway.

Authorization

queryapiKey<token>

Your API key from the dashboard, sent as ?apiKey=<key>.

Request Body

Route optimization task. The request body must be JSON.

application/json
  1. body
mode?string

Travel profile used for all agent routes. drive represents passenger cars. transit and approximated_transit are not supported (no transit data).

Value in"walk""hike""scooter""motorcycle""drive""light_truck""bicycle""mountain_bike""road_bike""bus""medium_truck""truck""truck_dangerous_goods""heavy_truck""long_truck"
agents?array<|||>

Resources, such as vehicles or workers, to which jobs and shipments can be assigned.

Deviation (approximated): an agent with several time_windows is solved against their hull (earliest start to latest end); gaps between windows are not enforced. An agent without delivery_capacity/pickup_capacity has effectively unlimited capacity.

Items1 <= items <= 100
jobs*unknown
Items1 <= items
shipments?array<>

Paired pickup-delivery tasks. Pickup always precedes delivery and both are assigned to the same agent.

Itemsitems <= 1000
locations?array<>

Reusable coordinates referenced by zero-based location_index fields. Regular calls may contain at most 300 unique coordinates across the complete task. The gateway rejects a task with more than 300 unique coordinates (agents, jobs, shipments and locations together) with 400; 300 x 300 = 90,000 matrix pairs is the Valhalla limit.

Itemsitems <= 1000
avoid?array<>

Road features, locations, polygons, or countries the calculated agent routes should avoid.

Deviation (approximated): tolls, highways (motorized modes only) and ferries are applied as soft Valhalla preferences scaled by importance; locations and polygons are hard exclusions; green_zones, transfers and country_codes are accepted but have no effect. Rule values are {lat, lon} objects (locations) and arrays of {lat, lon} objects (polygons).

Itemsitems <= 100
traffic?string

Traffic model for motorized modes. free_flow assumes uncongested roads; approximated accounts for likely congestion.

Deviation (ignored): Accepted and echoed in properties.params.traffic, but routes are always computed free-flow; there is no congestion model.

Default"free_flow"
Value in"free_flow""approximated"
type?string

Route preference used for agent travel. balanced balances time and distance; short prioritizes distance; less_maneuvers penalizes turns.

less_maneuvers is only supported for motorized modes; other modes return 400.

Default"balanced"
Value in"balanced""short""less_maneuvers"
max_speed?number

Maximum speed for driving, truck, and bus modes. Use 10 to 252 km/h with units=metric, or 6.5 to 155 mph with units=imperial.

Deviation (approximated): Applied only to motorized modes (drive, motorcycle, scooter, bus, truck modes); ignored for walk, hike and bicycle modes. The gateway enforces 10-252 (metric) or 6.5-155 (imperial) and returns 400 outside that range.

Range6.5 <= value <= 252
units?string

Unit system for returned route distances. metric returns meters; imperial returns miles.

Default"metric"
Value in"metric""imperial"

Response Body

Optimized plan. Each GeoJSON feature is one assigned agent route; collection properties contain the normalized task parameters and any assignment issues. Distances are meters (units=metric) or miles (units=imperial); times are seconds.

application/json
  1. response
type*unknown
features*array<>
bbox?array<number>
Items4 <= items <= 6
properties*
curl -X POST 'https://api.data.graphitelab.ai/v1/routeplanner' \  -H 'Content-Type: application/json' \  -d '{  "mode": "drive",  "agents": [    {      "id": "courier-1",      "start_location": [        -86.1581,        39.7684      ]    }  ],  "jobs": [    {      "id": "job-a",      "location": [        -86.1478,        39.7653      ],      "duration": 300    },    {      "id": "job-b",      "location": [        -86.1805,        39.7791      ],      "duration": 300    },    {      "id": "job-c",      "location": [        -86.1349,        39.7882      ],      "duration": 300    }  ]}'
Example Response
{  "type": "FeatureCollection",  "properties": {    "mode": "drive",    "params": {      "mode": "drive",      "type": "balanced",      "traffic": "free_flow",      "units": "metric",      "agents": [        {          "id": "courier-1",          "start_location": [            -86.1581,            39.7684          ]        }      ],      "jobs": [        {          "id": "job-a",          "location": [            -86.1478,            39.7653          ],          "duration": 300        },        {          "id": "job-b",          "location": [            -86.1805,            39.7791          ],          "duration": 300        },        {          "id": "job-c",          "location": [            -86.1349,            39.7882          ],          "duration": 300        }      ]    }  },  "features": [    {      "type": "Feature",      "geometry": {        "type": "MultiLineString",        "coordinates": [          [            [              -86.158241,              39.768017            ],            [              -86.158201,              39.768008            ],            [              -86.15813,              39.767998            ],            [              -86.1478,              39.765127            ]          ],          [            [              -86.1478,              39.765127            ],            [              -86.148043,              39.765127            ],            [              -86.148252,              39.765115            ],            [              -86.134927,              39.788128            ]          ],          [            [              -86.134927,              39.788128            ],            [              -86.134927,              39.788128            ],            [              -86.13534,              39.788126            ],            [              -86.180569,              39.7791            ]          ],          [            [              -86.180569,              39.7791            ],            [              -86.180571,              39.778877            ],            [              -86.180326,              39.778879            ],            [              -86.158241,              39.768017            ]          ]        ]      },      "bbox": [        -86.181421,        39.764552,        -86.134927,        39.788521      ],      "properties": {        "agent_index": 0,        "agent_id": "courier-1",        "time": 1960,        "start_time": 0,        "end_time": 1960,        "distance": 13437,        "legs": [          {            "time": 213,            "distance": 1547,            "from_waypoint_index": 0,            "to_waypoint_index": 1,            "steps": [              {                "from_index": 0,                "to_index": 1,                "time": 213,                "distance": 1547              }            ]          },          {            "time": 429,            "distance": 4047,            "from_waypoint_index": 1,            "to_waypoint_index": 2,            "steps": [              {                "from_index": 1,                "to_index": 2,                "time": 429,                "distance": 4047              }            ]          },          {            "time": 418,            "distance": 4996,            "from_waypoint_index": 2,            "to_waypoint_index": 3,            "steps": [              {                "from_index": 2,                "to_index": 3,                "time": 418,                "distance": 4996              }            ]          },          {            "time": 297,            "distance": 2847,            "from_waypoint_index": 3,            "to_waypoint_index": 4,            "steps": [              {                "from_index": 3,                "to_index": 4,                "time": 297,                "distance": 2847              }            ]          }        ],        "mode": "drive",        "actions": [          {            "index": 0,            "type": "start",            "start_time": 0,            "duration": 0,            "waypoint_index": 0          },          {            "index": 1,            "type": "job",            "start_time": 213,            "duration": 300,            "waypoint_index": 1,            "job_index": 0,            "job_id": "job-a"          },          {            "index": 2,            "type": "job",            "start_time": 942,            "duration": 300,            "waypoint_index": 2,            "job_index": 2,            "job_id": "job-c"          },          {            "index": 3,            "type": "job",            "start_time": 1660,            "duration": 300,            "waypoint_index": 3,            "job_index": 1,            "job_id": "job-b"          },          {            "index": 4,            "type": "end",            "start_time": 1960,            "duration": 0,            "waypoint_index": 4          }        ],        "waypoints": [          {            "next_leg_index": 0,            "original_location": [              -86.1581,              39.7684            ],            "location": [              -86.1581,              39.7684            ],            "start_time": 0,            "duration": 0,            "actions": [              {                "index": 0,                "type": "start",                "start_time": 0,                "duration": 0,                "waypoint_index": 0              }            ]          },          {            "next_leg_index": 1,            "prev_leg_index": 0,            "original_location": [              -86.1478,              39.7653            ],            "location": [              -86.1478,              39.7653            ],            "start_time": 213,            "duration": 300,            "actions": [              {                "index": 1,                "type": "job",                "start_time": 213,                "duration": 300,                "waypoint_index": 1,                "job_index": 0,                "job_id": "job-a"              }            ]          },          {            "next_leg_index": 2,            "prev_leg_index": 1,            "original_location": [              -86.1349,              39.7882            ],            "location": [              -86.1349,              39.7882            ],            "start_time": 942,            "duration": 300,            "actions": [              {                "index": 2,                "type": "job",                "start_time": 942,                "duration": 300,                "waypoint_index": 2,                "job_index": 2,                "job_id": "job-c"              }            ]          },          {            "next_leg_index": 3,            "prev_leg_index": 2,            "original_location": [              -86.1805,              39.7791            ],            "location": [              -86.1805,              39.7791            ],            "start_time": 1660,            "duration": 300,            "actions": [              {                "index": 3,                "type": "job",                "start_time": 1660,                "duration": 300,                "waypoint_index": 3,                "job_index": 1,                "job_id": "job-b"              }            ]          },          {            "prev_leg_index": 3,            "original_location": [              -86.1581,              39.7684            ],            "location": [              -86.1581,              39.7684            ],            "start_time": 1960,            "duration": 0,            "actions": [              {                "index": 4,                "type": "end",                "start_time": 1960,                "duration": 0,                "waypoint_index": 4              }            ]          }        ]      }    }  ]}