{"_id":"5b2c2fa8f4eae600035b716c","category":"5b2c2fa8f4eae600035b7166","project":"546559525871e90800f503c0","user":"5465590bf42a472000b0c6b7","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":[],"next":{"pages":[],"description":""},"createdAt":"2014-11-24T23:28:11.689Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"never","params":[],"url":""},"isReference":false,"order":0,"body":"This is the *ultimate* solution to automate and optimize your routing and scheduling operations. With Routific's Engine API, you can integrate our proprietary algorithms into your software. Countless businesses benefit from route optimization. Here's just a sample of some of the most popular use-cases:\n\n- meal delivery\n- grocery delivery\n- parcel delivery\n- field services\n- moving companies\n- house calls\n- moving boxes\n- storage solutions\n- distribution logistics\n- bakeries\n- flower shops\n- realtors\n- pharmacies\n- medical equipment delivery\n- waste management\n\nAll these businesses have something in common – the need to plan daily routes to visit multiple stops, either with a single vehicle or a **fleet of vehicles**.\n[block:image]\n{\n  \"images\": [\n    {\n      \"caption\": \"Vehicle Routing Problem\",\n      \"image\": [\n        \"https://files.readme.io/73caf4d-vrp.jpg\",\n        \"vrp.jpg\",\n        800,\n        1232,\n        \"#e9ecde\"\n      ]\n    }\n  ],\n  \"sidebar\": true\n}\n[/block]\nWhile scheduled deliveries derive the most [value from route optimization](http://recode.net/2014/09/15/the-case-against-everything-on-demand/), routing remains a useful method to aid (or even automate) on-demand services and their manual dispatching operations.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Planning horizon\",\n  \"body\": \"It is assumed that the planning horizon does not exceed 96 hours, starting from 00:00 to 96:00.\\n\\nNote that Routific would consider it one continuous route, without returns to a central depot. Having such a long shift is only useful if you have a *really* long continuous route. Note that you can define multiple breaks for your drivers to ensure they get enough rest :)\\n\\nIf instead you needed to plan separate routes across multiple days, you can define a separate driver for each day, that start and end at the central depot.\\n\\nReach us at [info@routific.com](mailto:info@routific.com) if you have any questions.\"\n}\n[/block]\nCall the API with inputs that accurately describe your real-life situation, and it will respond with an optimized assignment as well as the ordering of visits across your fleet, while trying to meet all the constraints provided. If some visits cannot be served because of the latter, we will return them as unserved.\n\nThe output will also include idle time (if any) at locations where the driver needs to wait for the start of the time-window. The algorithm will automatically minimize the total idle time on your routes, which may result in a delayed departure time.\n\nIf our API lacks support of a fundamental element to your logistics, do not hesitate to contact us at [info@routific.com](mailto:info@routific.com).","excerpt":"The most versatile route optimization API","slug":"api-reference","type":"basic","title":"Routific Engine API","__v":0,"childrenPages":[]}

Routific Engine API

The most versatile route optimization API

This is the *ultimate* solution to automate and optimize your routing and scheduling operations. With Routific's Engine API, you can integrate our proprietary algorithms into your software. Countless businesses benefit from route optimization. Here's just a sample of some of the most popular use-cases: - meal delivery - grocery delivery - parcel delivery - field services - moving companies - house calls - moving boxes - storage solutions - distribution logistics - bakeries - flower shops - realtors - pharmacies - medical equipment delivery - waste management All these businesses have something in common – the need to plan daily routes to visit multiple stops, either with a single vehicle or a **fleet of vehicles**. [block:image] { "images": [ { "caption": "Vehicle Routing Problem", "image": [ "https://files.readme.io/73caf4d-vrp.jpg", "vrp.jpg", 800, 1232, "#e9ecde" ] } ], "sidebar": true } [/block] While scheduled deliveries derive the most [value from route optimization](http://recode.net/2014/09/15/the-case-against-everything-on-demand/), routing remains a useful method to aid (or even automate) on-demand services and their manual dispatching operations. [block:callout] { "type": "info", "title": "Planning horizon", "body": "It is assumed that the planning horizon does not exceed 96 hours, starting from 00:00 to 96:00.\n\nNote that Routific would consider it one continuous route, without returns to a central depot. Having such a long shift is only useful if you have a *really* long continuous route. Note that you can define multiple breaks for your drivers to ensure they get enough rest :)\n\nIf instead you needed to plan separate routes across multiple days, you can define a separate driver for each day, that start and end at the central depot.\n\nReach us at [info@routific.com](mailto:info@routific.com) if you have any questions." } [/block] Call the API with inputs that accurately describe your real-life situation, and it will respond with an optimized assignment as well as the ordering of visits across your fleet, while trying to meet all the constraints provided. If some visits cannot be served because of the latter, we will return them as unserved. The output will also include idle time (if any) at locations where the driver needs to wait for the start of the time-window. The algorithm will automatically minimize the total idle time on your routes, which may result in a delayed departure time. If our API lacks support of a fundamental element to your logistics, do not hesitate to contact us at [info@routific.com](mailto:info@routific.com).
This is the *ultimate* solution to automate and optimize your routing and scheduling operations. With Routific's Engine API, you can integrate our proprietary algorithms into your software. Countless businesses benefit from route optimization. Here's just a sample of some of the most popular use-cases: - meal delivery - grocery delivery - parcel delivery - field services - moving companies - house calls - moving boxes - storage solutions - distribution logistics - bakeries - flower shops - realtors - pharmacies - medical equipment delivery - waste management All these businesses have something in common – the need to plan daily routes to visit multiple stops, either with a single vehicle or a **fleet of vehicles**. [block:image] { "images": [ { "caption": "Vehicle Routing Problem", "image": [ "https://files.readme.io/73caf4d-vrp.jpg", "vrp.jpg", 800, 1232, "#e9ecde" ] } ], "sidebar": true } [/block] While scheduled deliveries derive the most [value from route optimization](http://recode.net/2014/09/15/the-case-against-everything-on-demand/), routing remains a useful method to aid (or even automate) on-demand services and their manual dispatching operations. [block:callout] { "type": "info", "title": "Planning horizon", "body": "It is assumed that the planning horizon does not exceed 96 hours, starting from 00:00 to 96:00.\n\nNote that Routific would consider it one continuous route, without returns to a central depot. Having such a long shift is only useful if you have a *really* long continuous route. Note that you can define multiple breaks for your drivers to ensure they get enough rest :)\n\nIf instead you needed to plan separate routes across multiple days, you can define a separate driver for each day, that start and end at the central depot.\n\nReach us at [info@routific.com](mailto:info@routific.com) if you have any questions." } [/block] Call the API with inputs that accurately describe your real-life situation, and it will respond with an optimized assignment as well as the ordering of visits across your fleet, while trying to meet all the constraints provided. If some visits cannot be served because of the latter, we will return them as unserved. The output will also include idle time (if any) at locations where the driver needs to wait for the start of the time-window. The algorithm will automatically minimize the total idle time on your routes, which may result in a delayed departure time. If our API lacks support of a fundamental element to your logistics, do not hesitate to contact us at [info@routific.com](mailto:info@routific.com).
{"_id":"5b2c2fa8f4eae600035b716d","category":"5b2c2fa8f4eae600035b7166","project":"546559525871e90800f503c0","user":"5465590bf42a472000b0c6b7","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":["556d591fe24c5a0d00703405"],"next":{"pages":[],"description":""},"createdAt":"2014-11-14T01:22:27.968Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"never","params":[{"_id":"5473c2cc1a20c70800e18a89","ref":"","in":"body","required":false,"desc":"","default":"","type":"string","name":"visits"},{"_id":"5473c2cc1a20c70800e18a88","ref":"","in":"body","required":true,"desc":"","default":"","type":"string","name":"network"}],"url":"/vrp"},"isReference":false,"order":1,"body":"Send our API the addresses of your visits and your fleet. We will return the optimal allocation and order in which you should visit them. Simple and straightforward!\n\nThe following is a tiny example of one vehicle and three visits in Vancouver.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl https://routific.com/demo.json | \\\\\\ncurl https://api.routific.com/v1/vrp \\\\\\n      -X POST \\\\\\n      -H \\\"Content-Type: application/json\\\" \\\\\\n      -H \\\"Authorization: bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1MzEzZDZiYTNiMDBkMzA4MDA2ZTliOGEiLCJpYXQiOjEzOTM4MDkwODJ9.PR5qTHsqPogeIIe0NyH2oheaGR-SJXDsxPTcUQNq90E\\\" \\\\\\n      -d @-\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"// Step 1: npm install routific\\n\\n// Step 2: Initialize client\\nconst Routific = require('routific')\\n\\n// This is your demo token\\nconst token   = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1MzEzZDZiYTNiMDBkMzA4MDA2ZTliOGEiLCJpYXQiOjEzOTM4MDkwODJ9.PR5qTHsqPogeIIe0NyH2oheaGR-SJXDsxPTcUQNq90E'\\n\\nconst options = {token: token}\\nconst client  = new Routific.Client(options);\\n\\n// Step 3: Initialize VRP service\\nconst vrp = new Routific.Vrp();\\n\\n// Step 4: Add your visits\\nconst visits = [\\n  {\\n    id: \\\"visit_1\\\",\\n    location: {name: \\\"Jack Smith\\\", lat: 49.227607, lng: -123.1363085},\\n    start: \\\"8:00\\\",\\n    end: \\\"16:00\\\",\\n    duration: 10\\n  },\\n  {\\n    id: \\\"visit_2\\\",\\n    location: {name: \\\"Bill Mayers\\\", lat: 49.227607, lng: -123.1363085},\\n    start: \\\"8:00\\\",\\n    end: \\\"16:00\\\",\\n    duration: 10\\n  },\\n  {\\n    id: \\\"visit_3\\\",\\n    location: {name: \\\"Marc Kuo\\\", lat: 49.227607, lng: -123.1363085},\\n    start: \\\"8:00\\\",\\n    end: \\\"16:00\\\",\\n    duration: 10\\n  }\\n]\\n\\nvisits.map((visit) => {\\n  vrp.addVisit(visit.id, visit);\\n})\\n\\n// Step 5: Add your vehicles\\nconst vehicles = [\\n  {\\n    id: \\\"vehicle_1\\\",\\n    start_location: {\\n        id: \\\"depot\\\",\\n        lat: 49.2553636,\\n        lng: -123.0873365\\n    },\\n    end_location: {\\n        id: \\\"depot\\\",\\n        lat: 49.2553636,\\n        lng: -123.0873365\\n    }\\n  }\\n]\\n\\nvehicles.map((vehicle) => {\\n  vrp.addVehicle(vehicle.id, vehicle);\\n})\\n\\n// Step 6: Add traffic speed\\nvrp.addOption(\\\"traffic\\\", \\\"slow\\\");\\n\\n// Step 7: Send request\\nclient.route(vrp, (err, solution, jobId) => {\\n  if (err) {\\n    console.log(\\\"An error occurred\\\");\\n    console.log(err);\\n  } else if (solution.status == \\\"success\\\") {\\n    console.log(\\\"Solution is:\\\")\\n    console.log(solution)\\n  }\\n})\",\n      \"language\": \"javascript\",\n      \"name\": \"Node\"\n    },\n    {\n      \"code\": \"# Step1: Install the Routific gem: gem install routific\\n\\n# Step 2: Initialize the client\\nrequire 'routific'\\n\\n# This is your demo token\\ntoken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1MzEzZDZiYTNiMDBkMzA4MDA2ZTliOGEiLCJpYXQiOjEzOTM4MDkwODJ9.PR5qTHsqPogeIIe0NyH2oheaGR-SJXDsxPTcUQNq90E'\\n\\nRoutific.set_token(token)\\nroutific = Routific.new\\n\\n# Step 3: Set your visits\\nvisits = [\\n  {\\n    \\\"id\\\" => \\\"order_1\\\",\\n    \\\"start\\\" => \\\"9:00\\\",\\n    \\\"end\\\" => \\\"12:00\\\",\\n    \\\"duration\\\" => 10,\\n    \\\"location\\\" => {\\n      \\\"name\\\" => \\\"6800 Cambie\\\",\\n      \\\"lat\\\" => 49.227107,\\n      \\\"lng\\\" => -123.1163085,\\n    }\\n  },\\n  {\\n    \\\"id\\\" => \\\"order_2\\\",\\n    \\\"start\\\" => \\\"9:00\\\",\\n      \\\"end\\\" => \\\"12:00\\\",\\n      \\\"duration\\\" => 10,\\n      \\\"location\\\" => {\\n        \\\"name\\\"=> \\\"3780 Arbutus\\\",\\n        \\\"lat\\\"=> 49.2474624,\\n        \\\"lng\\\"=> -123.1532338\\n      }\\n  },\\n  {\\n    \\\"id\\\" => \\\"order_5\\\",\\n    \\\"start\\\" => \\\"9:00\\\",\\n    \\\"end\\\" => \\\"12:00\\\",\\n    \\\"duration\\\" => 10,\\n    \\\"location\\\" => {\\n      \\\"name\\\" => \\\"6800 Cambie\\\",\\n      \\\"lat\\\" => 49.227107,\\n      \\\"lng\\\" => -123.1163085,\\n    }\\n  },\\n]\\n\\nvisits.each do |visit|\\n  routific.set_visit(visit[\\\"id\\\"], visit)\\nend\\n\\n# Step 4: Set your vehicles\\nvehicles = [\\n  {\\n    \\\"id\\\" => \\\"vehicle_1\\\",\\n    \\\"start_location\\\" => {\\n      \\\"name\\\" => \\\"800 Kingsway\\\",\\n      \\\"lat\\\" => 49.2553636,\\n      \\\"lng\\\" => -123.0873365,\\n    },\\n    \\\"end_location\\\" => {\\n      \\\"name\\\" => \\\"800 Kingsway\\\",\\n      \\\"lat\\\" => 49.2553636,\\n      \\\"lng\\\" => -123.0873365,\\n    },\\n    \\\"shift_start\\\" => \\\"8:00\\\",\\n    \\\"shift_end\\\" => \\\"12:00\\\",\\n  },\\n  {\\n    \\\"id\\\" => \\\"vehicle_2\\\",\\n    \\\"start_location\\\" => {\\n      \\\"name\\\" => \\\"800 Kingsway\\\",\\n      \\\"lat\\\" => 49.2553636,\\n      \\\"lng\\\" => -123.0873365,\\n    },\\n    \\\"end_location\\\" => {\\n      \\\"name\\\" => \\\"800 Kingsway\\\",\\n      \\\"lat\\\" => 49.2553636,\\n      \\\"lng\\\" => -123.0873365,\\n    },\\n    \\\"shift_start\\\" => \\\"8:00\\\",\\n    \\\"shift_end\\\" => \\\"12:00\\\",\\n  }\\n]\\n\\nvehicles.each do |vehicle|\\n  routific.set_vehicle(vehicle[\\\"id\\\"], vehicle)\\nend\\n\\n# Step 5: Retrieve route\\nroute = routific.get_route()\\n\\nputs route.status # => \\\"success\\\"\\nputs route.total_travel_time # => 29\\n\\nvehicle_routes = route.vehicle_routes\\n\\nv1_route = vehicle_routes[\\\"vehicle_1\\\"]\\nv2_route = vehicle_routes[\\\"vehicle_2\\\"]\\n\\n# Step 6: Print out route\\nputs v1_route.length\\nv1_route.each do |w|\\n  puts \\\"#{w.location_id}: #{w.arrival_time} ~ #{w.finish_time}\\\"\\nend\",\n      \"language\": \"ruby\",\n      \"name\": \"Ruby\"\n    },\n    {\n      \"code\": \"# Step 1: Import http client and set routific vrp url\\nimport urllib2\\nimport json\\n\\nURL   = \\\"https://api.routific.com/v1/vrp\\\"\\n\\n# Step 2: Prepare visits\\nvisits = {\\n    \\\"order_1\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"6800 Cambie\\\",\\n        \\\"lat\\\": 49.227107,\\n        \\\"lng\\\": -123.1163085\\n      }\\n    },\\n    \\\"order_2\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"3780 Arbutus\\\",\\n        \\\"lat\\\": 49.2474624,\\n        \\\"lng\\\": -123.1532338\\n      }\\n    },\\n    \\\"order_3\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"800 Robson\\\",\\n        \\\"lat\\\": 49.2819229,\\n        \\\"lng\\\": -123.1211844\\n      }\\n    }\\n}\\n\\n# Step 3: Prepare vehicles\\nfleet = {\\n    \\\"vehicle_1\\\": {\\n      \\\"start_location\\\": {\\n        \\\"id\\\": \\\"depot\\\",\\n        \\\"name\\\": \\\"800 Kingsway\\\",\\n        \\\"lat\\\": 49.2553636,\\n        \\\"lng\\\": -123.0873365\\n      }\\n    },\\n    \\\"vehicle_2\\\": {\\n      \\\"start_location\\\": {\\n        \\\"id\\\": \\\"depot\\\",\\n        \\\"name\\\": \\\"800 Kingsway\\\",\\n        \\\"lat\\\": 49.2553636,\\n        \\\"lng\\\": -123.0873365\\n      }\\n    }\\n}\\n\\n# Step 4: Prepare data payload\\ndata = {\\n    \\\"visits\\\": visits,\\n    \\\"fleet\\\": fleet\\n}\\n\\n# Step 5: Put together request\\n# This is your demo token\\ntoken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1MzEzZDZiYTNiMDBkMzA4MDA2ZTliOGEiLCJpYXQiOjEzOTM4MDkwODJ9.PR5qTHsqPogeIIe0NyH2oheaGR-SJXDsxPTcUQNq90E'\\n\\nreq = urllib2.Request(URL, json.dumps(data))\\nreq.add_header('Content-Type', 'application/json')\\nreq.add_header('Authorization', \\\"bearer \\\" + token)\\n\\n# Step 6: Get route\\nres = urllib2.urlopen(req).read()\\n\\nprint res\",\n      \"language\": \"python\",\n      \"name\": \"Python\"\n    },\n    {\n      \"code\": \"<?php\\n\\n// Step 1: Prepare http client and set routific base url\\n\\nrequire 'vendor/autoload.php';\\nuse GuzzleHttpClient;\\n$url = 'https://api.routific.com/v1/';\\n$client = new Client([\\n    'base_uri' => $url,\\n]);\\n\\n// Step 2: Prepare visits\\n$order1 = array(\\n  \\\"location\\\" => array(\\n    \\\"name\\\" => \\\"6800 Cambie\\\",\\n    \\\"lat\\\" => 49.227107,\\n    \\\"lng\\\" => -123.1163085\\n));\\n$order2 = array(\\n  \\\"location\\\" => array(\\n    \\\"name\\\" => \\\"3780 Arbutus\\\",\\n    \\\"lat\\\" => 49.2474624,\\n    \\\"lng\\\" => -123.1532338\\n));\\n$order3 = array(\\n  \\\"location\\\" => array(\\n    \\\"name\\\" => \\\"800 Robson\\\",\\n    \\\"lat\\\" => 49.2819229,\\n    \\\"lng\\\" => -123.1211844\\n));\\n$visits = array(\\n  \\\"order_1\\\" => $order1,\\n  \\\"order_2\\\" => $order2,\\n  \\\"order_3\\\" => $order3\\n);\\n\\n// Step 3: Prepare vehicles\\n$vehicle1 = array(\\n  \\\"start_location\\\" => array(\\n    \\\"id\\\" => \\\"depot\\\",\\n    \\\"name\\\" => \\\"800 Kingsway\\\",\\n    \\\"lat\\\" => 49.2553636,\\n    \\\"lng\\\" => -123.0873365\\n));\\n\\n$vehicle2 = array(\\n  \\\"start_location\\\" => array(\\n    \\\"id\\\" => \\\"depot\\\",\\n    \\\"name\\\" => \\\"800 Kingsway\\\",\\n    \\\"lat\\\" => 49.2553636,\\n    \\\"lng\\\" => -123.0873365\\n));\\n\\n$vehicles = array(\\n  \\\"vehicle_1\\\" => $vehicle1,\\n  \\\"vehicle_2\\\" => $vehicle2,\\n);\\n\\n// Step 4: Prepare data payload\\n$payload = array(\\n  \\\"visits\\\" => $visits,\\n  \\\"fleet\\\" => $vehicles\\n);\\n\\n// Step 5: Send request\\n// This is your demo token\\n$token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1MzEzZDZiYTNiMDBkMzA4MDA2ZTliOGEiLCJpYXQiOjEzOTM4MDkwODJ9.PR5qTHsqPogeIIe0NyH2oheaGR-SJXDsxPTcUQNq90E';\\n\\n$response = $client->post('vrp', [\\n  'json' => $payload,\\n  'headers' => [\\n    \\\"Content-type\\\" => \\\"application/json\\\",\\n    \\\"Authorization\\\" => \\\"bearer \\\" . $token\\n  ]\\n]);\\necho $response->getBody();\\n?>\",\n      \"language\": \"text\",\n      \"name\": \"PHP\"\n    }\n  ]\n}\n[/block]\nThis example is populated with a demo token, so you can copy and paste the above for a working example. [Sign up](https://routific.com/portal/account/#/signup) for an account to get your API access token.\n\nThe contents of the JSON input and output are shown to the right.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Time formats\",\n  \"body\": \"All examples in this documentation uses the `hh:mm` time formats with a 24-hour military notation. Our API also supports [UNIX times](https://en.wikipedia.org/wiki/Unix_time), which would make dealing with routing across multiple timezones easier.\\n\\nUNIX time values are defined as number of seconds since epoch time in UTC (00:00:00, January 1st, 1970).\\n\\nWhen the input uses UNIX time formats, the output will also returned in UNIX time. When the input is in `hh:mm` format, so will the output.  Note: Unix time stamps are numbers.\\n\\nHere's an example:\\n\\n```\\n\\\"order_1\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"6800 Cambie\\\",\\n        \\\"lat\\\": 49.227107,\\n        \\\"lng\\\": -123.1163085\\n      },\\n      \\\"start\\\": 1531324800,\\n      \\\"end\\\": 1531335600,\\n      \\\"duration\\\": 10\\n    }\\n```\"\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  \\\"visits\\\": {\\n    \\\"order_1\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"6800 Cambie\\\",\\n        \\\"lat\\\": 49.227107,\\n        \\\"lng\\\": -123.1163085\\n      },\\n      \\\"start\\\": \\\"9:00\\\",\\n      \\\"end\\\": \\\"12:00\\\",\\n      \\\"duration\\\": 10\\n    },\\n    \\\"order_2\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"3780 Arbutus\\\",\\n        \\\"lat\\\": 49.2474624,\\n        \\\"lng\\\": -123.1532338\\n      },\\n      \\\"start\\\": \\\"9:00\\\",\\n      \\\"end\\\": \\\"12:00\\\",\\n      \\\"duration\\\": 10\\n    },\\n    \\\"order_3\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"800 Robson\\\",\\n        \\\"lat\\\": 49.2819229,\\n        \\\"lng\\\": -123.1211844\\n      },\\n      \\\"start\\\": \\\"8:00\\\",\\n      \\\"end\\\": \\\"9:00\\\",\\n      \\\"duration\\\": 10\\n    }\\n  },\\n  \\\"fleet\\\": {\\n    \\\"vehicle_1\\\": {\\n      \\\"start_location\\\": {\\n        \\\"id\\\": \\\"depot\\\",\\n        \\\"name\\\": \\\"800 Kingsway\\\",\\n        \\\"lat\\\": 49.2553636,\\n        \\\"lng\\\": -123.0873365\\n      },\\n      \\\"end_location\\\": {\\n        \\\"id\\\": \\\"depot\\\",\\n        \\\"name\\\": \\\"800 Kingsway\\\",\\n        \\\"lat\\\": 49.2553636,\\n        \\\"lng\\\": -123.0873365\\n      },\\n      \\\"shift_start\\\": \\\"8:00\\\",\\n      \\\"shift_end\\\": \\\"12:00\\\"\\n    }\\n  }\\n}\\n\",\n      \"language\": \"json\",\n      \"name\": \"Input\"\n    },\n    {\n      \"code\": \"{\\n  \\\"status\\\": \\\"success\\\",\\n  \\\"total_travel_time\\\": 31.983334,\\n  \\\"total_idle_time\\\": 0,\\n  \\\"num_unserved\\\": 0,\\n  \\\"unserved\\\": null,\\n  \\\"solution\\\": {\\n    \\\"vehicle_1\\\": [\\n      {\\n        \\\"location_id\\\": \\\"depot\\\",\\n        \\\"location_name\\\": \\\"800 Kingsway\\\",\\n        \\\"arrival_time\\\": \\\"08:00\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_3\\\",\\n        \\\"location_name\\\": \\\"800 Robson\\\",\\n        \\\"arrival_time\\\": \\\"08:10\\\",\\n        \\\"finish_time\\\": \\\"08:20\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_2\\\",\\n        \\\"location_name\\\": \\\"3780 Arbutus\\\",\\n        \\\"arrival_time\\\": \\\"08:29\\\",\\n        \\\"finish_time\\\": \\\"09:10\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_1\\\",\\n        \\\"location_name\\\": \\\"6800 Cambie\\\",\\n        \\\"arrival_time\\\": \\\"09:19\\\",\\n        \\\"finish_time\\\": \\\"09:29\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"depot\\\",\\n        \\\"location_name\\\": \\\"800 Kingsway\\\",\\n        \\\"arrival_time\\\": \\\"09:39\\\"\\n      }\\n    ]\\n  }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Output\"\n    }\n  ],\n  \"sidebar\": true\n}\n[/block]\nTo play around with a few worked examples we recommend a REST client called [Postman](https://www.getpostman.com/). Simply tap the button below to import a pre-made collection of API requests.\n\n[![Run in Postman](https://run.pstmn.io/button.svg)](https://app.getpostman.com/run-collection/36e5a36c27e7ca9b9873)","excerpt":"This will get you on the road in no time.","slug":"getting-started","type":"basic","title":"Quickstart","__v":13,"childrenPages":[]}

Quickstart

This will get you on the road in no time.

Send our API the addresses of your visits and your fleet. We will return the optimal allocation and order in which you should visit them. Simple and straightforward! The following is a tiny example of one vehicle and three visits in Vancouver. [block:code] { "codes": [ { "code": "curl https://routific.com/demo.json | \\\ncurl https://api.routific.com/v1/vrp \\\n -X POST \\\n -H \"Content-Type: application/json\" \\\n -H \"Authorization: bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1MzEzZDZiYTNiMDBkMzA4MDA2ZTliOGEiLCJpYXQiOjEzOTM4MDkwODJ9.PR5qTHsqPogeIIe0NyH2oheaGR-SJXDsxPTcUQNq90E\" \\\n -d @-", "language": "curl" }, { "code": "// Step 1: npm install routific\n\n// Step 2: Initialize client\nconst Routific = require('routific')\n\n// This is your demo token\nconst token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1MzEzZDZiYTNiMDBkMzA4MDA2ZTliOGEiLCJpYXQiOjEzOTM4MDkwODJ9.PR5qTHsqPogeIIe0NyH2oheaGR-SJXDsxPTcUQNq90E'\n\nconst options = {token: token}\nconst client = new Routific.Client(options);\n\n// Step 3: Initialize VRP service\nconst vrp = new Routific.Vrp();\n\n// Step 4: Add your visits\nconst visits = [\n {\n id: \"visit_1\",\n location: {name: \"Jack Smith\", lat: 49.227607, lng: -123.1363085},\n start: \"8:00\",\n end: \"16:00\",\n duration: 10\n },\n {\n id: \"visit_2\",\n location: {name: \"Bill Mayers\", lat: 49.227607, lng: -123.1363085},\n start: \"8:00\",\n end: \"16:00\",\n duration: 10\n },\n {\n id: \"visit_3\",\n location: {name: \"Marc Kuo\", lat: 49.227607, lng: -123.1363085},\n start: \"8:00\",\n end: \"16:00\",\n duration: 10\n }\n]\n\nvisits.map((visit) => {\n vrp.addVisit(visit.id, visit);\n})\n\n// Step 5: Add your vehicles\nconst vehicles = [\n {\n id: \"vehicle_1\",\n start_location: {\n id: \"depot\",\n lat: 49.2553636,\n lng: -123.0873365\n },\n end_location: {\n id: \"depot\",\n lat: 49.2553636,\n lng: -123.0873365\n }\n }\n]\n\nvehicles.map((vehicle) => {\n vrp.addVehicle(vehicle.id, vehicle);\n})\n\n// Step 6: Add traffic speed\nvrp.addOption(\"traffic\", \"slow\");\n\n// Step 7: Send request\nclient.route(vrp, (err, solution, jobId) => {\n if (err) {\n console.log(\"An error occurred\");\n console.log(err);\n } else if (solution.status == \"success\") {\n console.log(\"Solution is:\")\n console.log(solution)\n }\n})", "language": "javascript", "name": "Node" }, { "code": "# Step1: Install the Routific gem: gem install routific\n\n# Step 2: Initialize the client\nrequire 'routific'\n\n# This is your demo token\ntoken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1MzEzZDZiYTNiMDBkMzA4MDA2ZTliOGEiLCJpYXQiOjEzOTM4MDkwODJ9.PR5qTHsqPogeIIe0NyH2oheaGR-SJXDsxPTcUQNq90E'\n\nRoutific.set_token(token)\nroutific = Routific.new\n\n# Step 3: Set your visits\nvisits = [\n {\n \"id\" => \"order_1\",\n \"start\" => \"9:00\",\n \"end\" => \"12:00\",\n \"duration\" => 10,\n \"location\" => {\n \"name\" => \"6800 Cambie\",\n \"lat\" => 49.227107,\n \"lng\" => -123.1163085,\n }\n },\n {\n \"id\" => \"order_2\",\n \"start\" => \"9:00\",\n \"end\" => \"12:00\",\n \"duration\" => 10,\n \"location\" => {\n \"name\"=> \"3780 Arbutus\",\n \"lat\"=> 49.2474624,\n \"lng\"=> -123.1532338\n }\n },\n {\n \"id\" => \"order_5\",\n \"start\" => \"9:00\",\n \"end\" => \"12:00\",\n \"duration\" => 10,\n \"location\" => {\n \"name\" => \"6800 Cambie\",\n \"lat\" => 49.227107,\n \"lng\" => -123.1163085,\n }\n },\n]\n\nvisits.each do |visit|\n routific.set_visit(visit[\"id\"], visit)\nend\n\n# Step 4: Set your vehicles\nvehicles = [\n {\n \"id\" => \"vehicle_1\",\n \"start_location\" => {\n \"name\" => \"800 Kingsway\",\n \"lat\" => 49.2553636,\n \"lng\" => -123.0873365,\n },\n \"end_location\" => {\n \"name\" => \"800 Kingsway\",\n \"lat\" => 49.2553636,\n \"lng\" => -123.0873365,\n },\n \"shift_start\" => \"8:00\",\n \"shift_end\" => \"12:00\",\n },\n {\n \"id\" => \"vehicle_2\",\n \"start_location\" => {\n \"name\" => \"800 Kingsway\",\n \"lat\" => 49.2553636,\n \"lng\" => -123.0873365,\n },\n \"end_location\" => {\n \"name\" => \"800 Kingsway\",\n \"lat\" => 49.2553636,\n \"lng\" => -123.0873365,\n },\n \"shift_start\" => \"8:00\",\n \"shift_end\" => \"12:00\",\n }\n]\n\nvehicles.each do |vehicle|\n routific.set_vehicle(vehicle[\"id\"], vehicle)\nend\n\n# Step 5: Retrieve route\nroute = routific.get_route()\n\nputs route.status # => \"success\"\nputs route.total_travel_time # => 29\n\nvehicle_routes = route.vehicle_routes\n\nv1_route = vehicle_routes[\"vehicle_1\"]\nv2_route = vehicle_routes[\"vehicle_2\"]\n\n# Step 6: Print out route\nputs v1_route.length\nv1_route.each do |w|\n puts \"#{w.location_id}: #{w.arrival_time} ~ #{w.finish_time}\"\nend", "language": "ruby", "name": "Ruby" }, { "code": "# Step 1: Import http client and set routific vrp url\nimport urllib2\nimport json\n\nURL = \"https://api.routific.com/v1/vrp\"\n\n# Step 2: Prepare visits\nvisits = {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n }\n },\n \"order_2\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n }\n },\n \"order_3\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n }\n }\n}\n\n# Step 3: Prepare vehicles\nfleet = {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n }\n },\n \"vehicle_2\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n }\n }\n}\n\n# Step 4: Prepare data payload\ndata = {\n \"visits\": visits,\n \"fleet\": fleet\n}\n\n# Step 5: Put together request\n# This is your demo token\ntoken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1MzEzZDZiYTNiMDBkMzA4MDA2ZTliOGEiLCJpYXQiOjEzOTM4MDkwODJ9.PR5qTHsqPogeIIe0NyH2oheaGR-SJXDsxPTcUQNq90E'\n\nreq = urllib2.Request(URL, json.dumps(data))\nreq.add_header('Content-Type', 'application/json')\nreq.add_header('Authorization', \"bearer \" + token)\n\n# Step 6: Get route\nres = urllib2.urlopen(req).read()\n\nprint res", "language": "python", "name": "Python" }, { "code": "<?php\n\n// Step 1: Prepare http client and set routific base url\n\nrequire 'vendor/autoload.php';\nuse GuzzleHttpClient;\n$url = 'https://api.routific.com/v1/';\n$client = new Client([\n 'base_uri' => $url,\n]);\n\n// Step 2: Prepare visits\n$order1 = array(\n \"location\" => array(\n \"name\" => \"6800 Cambie\",\n \"lat\" => 49.227107,\n \"lng\" => -123.1163085\n));\n$order2 = array(\n \"location\" => array(\n \"name\" => \"3780 Arbutus\",\n \"lat\" => 49.2474624,\n \"lng\" => -123.1532338\n));\n$order3 = array(\n \"location\" => array(\n \"name\" => \"800 Robson\",\n \"lat\" => 49.2819229,\n \"lng\" => -123.1211844\n));\n$visits = array(\n \"order_1\" => $order1,\n \"order_2\" => $order2,\n \"order_3\" => $order3\n);\n\n// Step 3: Prepare vehicles\n$vehicle1 = array(\n \"start_location\" => array(\n \"id\" => \"depot\",\n \"name\" => \"800 Kingsway\",\n \"lat\" => 49.2553636,\n \"lng\" => -123.0873365\n));\n\n$vehicle2 = array(\n \"start_location\" => array(\n \"id\" => \"depot\",\n \"name\" => \"800 Kingsway\",\n \"lat\" => 49.2553636,\n \"lng\" => -123.0873365\n));\n\n$vehicles = array(\n \"vehicle_1\" => $vehicle1,\n \"vehicle_2\" => $vehicle2,\n);\n\n// Step 4: Prepare data payload\n$payload = array(\n \"visits\" => $visits,\n \"fleet\" => $vehicles\n);\n\n// Step 5: Send request\n// This is your demo token\n$token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1MzEzZDZiYTNiMDBkMzA4MDA2ZTliOGEiLCJpYXQiOjEzOTM4MDkwODJ9.PR5qTHsqPogeIIe0NyH2oheaGR-SJXDsxPTcUQNq90E';\n\n$response = $client->post('vrp', [\n 'json' => $payload,\n 'headers' => [\n \"Content-type\" => \"application/json\",\n \"Authorization\" => \"bearer \" . $token\n ]\n]);\necho $response->getBody();\n?>", "language": "text", "name": "PHP" } ] } [/block] This example is populated with a demo token, so you can copy and paste the above for a working example. [Sign up](https://routific.com/portal/account/#/signup) for an account to get your API access token. The contents of the JSON input and output are shown to the right. [block:callout] { "type": "info", "title": "Time formats", "body": "All examples in this documentation uses the `hh:mm` time formats with a 24-hour military notation. Our API also supports [UNIX times](https://en.wikipedia.org/wiki/Unix_time), which would make dealing with routing across multiple timezones easier.\n\nUNIX time values are defined as number of seconds since epoch time in UTC (00:00:00, January 1st, 1970).\n\nWhen the input uses UNIX time formats, the output will also returned in UNIX time. When the input is in `hh:mm` format, so will the output. Note: Unix time stamps are numbers.\n\nHere's an example:\n\n```\n\"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n },\n \"start\": 1531324800,\n \"end\": 1531335600,\n \"duration\": 10\n }\n```" } [/block] [block:code] { "codes": [ { "code": "{\n \"visits\": {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n },\n \"start\": \"9:00\",\n \"end\": \"12:00\",\n \"duration\": 10\n },\n \"order_2\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n },\n \"start\": \"9:00\",\n \"end\": \"12:00\",\n \"duration\": 10\n },\n \"order_3\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n },\n \"start\": \"8:00\",\n \"end\": \"9:00\",\n \"duration\": 10\n }\n },\n \"fleet\": {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"end_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"shift_start\": \"8:00\",\n \"shift_end\": \"12:00\"\n }\n }\n}\n", "language": "json", "name": "Input" }, { "code": "{\n \"status\": \"success\",\n \"total_travel_time\": 31.983334,\n \"total_idle_time\": 0,\n \"num_unserved\": 0,\n \"unserved\": null,\n \"solution\": {\n \"vehicle_1\": [\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\",\n \"arrival_time\": \"08:00\"\n },\n {\n \"location_id\": \"order_3\",\n \"location_name\": \"800 Robson\",\n \"arrival_time\": \"08:10\",\n \"finish_time\": \"08:20\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"3780 Arbutus\",\n \"arrival_time\": \"08:29\",\n \"finish_time\": \"09:10\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"6800 Cambie\",\n \"arrival_time\": \"09:19\",\n \"finish_time\": \"09:29\"\n },\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\",\n \"arrival_time\": \"09:39\"\n }\n ]\n }\n}", "language": "json", "name": "Output" } ], "sidebar": true } [/block] To play around with a few worked examples we recommend a REST client called [Postman](https://www.getpostman.com/). Simply tap the button below to import a pre-made collection of API requests. [![Run in Postman](https://run.pstmn.io/button.svg)](https://app.getpostman.com/run-collection/36e5a36c27e7ca9b9873)
Send our API the addresses of your visits and your fleet. We will return the optimal allocation and order in which you should visit them. Simple and straightforward! The following is a tiny example of one vehicle and three visits in Vancouver. [block:code] { "codes": [ { "code": "curl https://routific.com/demo.json | \\\ncurl https://api.routific.com/v1/vrp \\\n -X POST \\\n -H \"Content-Type: application/json\" \\\n -H \"Authorization: bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1MzEzZDZiYTNiMDBkMzA4MDA2ZTliOGEiLCJpYXQiOjEzOTM4MDkwODJ9.PR5qTHsqPogeIIe0NyH2oheaGR-SJXDsxPTcUQNq90E\" \\\n -d @-", "language": "curl" }, { "code": "// Step 1: npm install routific\n\n// Step 2: Initialize client\nconst Routific = require('routific')\n\n// This is your demo token\nconst token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1MzEzZDZiYTNiMDBkMzA4MDA2ZTliOGEiLCJpYXQiOjEzOTM4MDkwODJ9.PR5qTHsqPogeIIe0NyH2oheaGR-SJXDsxPTcUQNq90E'\n\nconst options = {token: token}\nconst client = new Routific.Client(options);\n\n// Step 3: Initialize VRP service\nconst vrp = new Routific.Vrp();\n\n// Step 4: Add your visits\nconst visits = [\n {\n id: \"visit_1\",\n location: {name: \"Jack Smith\", lat: 49.227607, lng: -123.1363085},\n start: \"8:00\",\n end: \"16:00\",\n duration: 10\n },\n {\n id: \"visit_2\",\n location: {name: \"Bill Mayers\", lat: 49.227607, lng: -123.1363085},\n start: \"8:00\",\n end: \"16:00\",\n duration: 10\n },\n {\n id: \"visit_3\",\n location: {name: \"Marc Kuo\", lat: 49.227607, lng: -123.1363085},\n start: \"8:00\",\n end: \"16:00\",\n duration: 10\n }\n]\n\nvisits.map((visit) => {\n vrp.addVisit(visit.id, visit);\n})\n\n// Step 5: Add your vehicles\nconst vehicles = [\n {\n id: \"vehicle_1\",\n start_location: {\n id: \"depot\",\n lat: 49.2553636,\n lng: -123.0873365\n },\n end_location: {\n id: \"depot\",\n lat: 49.2553636,\n lng: -123.0873365\n }\n }\n]\n\nvehicles.map((vehicle) => {\n vrp.addVehicle(vehicle.id, vehicle);\n})\n\n// Step 6: Add traffic speed\nvrp.addOption(\"traffic\", \"slow\");\n\n// Step 7: Send request\nclient.route(vrp, (err, solution, jobId) => {\n if (err) {\n console.log(\"An error occurred\");\n console.log(err);\n } else if (solution.status == \"success\") {\n console.log(\"Solution is:\")\n console.log(solution)\n }\n})", "language": "javascript", "name": "Node" }, { "code": "# Step1: Install the Routific gem: gem install routific\n\n# Step 2: Initialize the client\nrequire 'routific'\n\n# This is your demo token\ntoken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1MzEzZDZiYTNiMDBkMzA4MDA2ZTliOGEiLCJpYXQiOjEzOTM4MDkwODJ9.PR5qTHsqPogeIIe0NyH2oheaGR-SJXDsxPTcUQNq90E'\n\nRoutific.set_token(token)\nroutific = Routific.new\n\n# Step 3: Set your visits\nvisits = [\n {\n \"id\" => \"order_1\",\n \"start\" => \"9:00\",\n \"end\" => \"12:00\",\n \"duration\" => 10,\n \"location\" => {\n \"name\" => \"6800 Cambie\",\n \"lat\" => 49.227107,\n \"lng\" => -123.1163085,\n }\n },\n {\n \"id\" => \"order_2\",\n \"start\" => \"9:00\",\n \"end\" => \"12:00\",\n \"duration\" => 10,\n \"location\" => {\n \"name\"=> \"3780 Arbutus\",\n \"lat\"=> 49.2474624,\n \"lng\"=> -123.1532338\n }\n },\n {\n \"id\" => \"order_5\",\n \"start\" => \"9:00\",\n \"end\" => \"12:00\",\n \"duration\" => 10,\n \"location\" => {\n \"name\" => \"6800 Cambie\",\n \"lat\" => 49.227107,\n \"lng\" => -123.1163085,\n }\n },\n]\n\nvisits.each do |visit|\n routific.set_visit(visit[\"id\"], visit)\nend\n\n# Step 4: Set your vehicles\nvehicles = [\n {\n \"id\" => \"vehicle_1\",\n \"start_location\" => {\n \"name\" => \"800 Kingsway\",\n \"lat\" => 49.2553636,\n \"lng\" => -123.0873365,\n },\n \"end_location\" => {\n \"name\" => \"800 Kingsway\",\n \"lat\" => 49.2553636,\n \"lng\" => -123.0873365,\n },\n \"shift_start\" => \"8:00\",\n \"shift_end\" => \"12:00\",\n },\n {\n \"id\" => \"vehicle_2\",\n \"start_location\" => {\n \"name\" => \"800 Kingsway\",\n \"lat\" => 49.2553636,\n \"lng\" => -123.0873365,\n },\n \"end_location\" => {\n \"name\" => \"800 Kingsway\",\n \"lat\" => 49.2553636,\n \"lng\" => -123.0873365,\n },\n \"shift_start\" => \"8:00\",\n \"shift_end\" => \"12:00\",\n }\n]\n\nvehicles.each do |vehicle|\n routific.set_vehicle(vehicle[\"id\"], vehicle)\nend\n\n# Step 5: Retrieve route\nroute = routific.get_route()\n\nputs route.status # => \"success\"\nputs route.total_travel_time # => 29\n\nvehicle_routes = route.vehicle_routes\n\nv1_route = vehicle_routes[\"vehicle_1\"]\nv2_route = vehicle_routes[\"vehicle_2\"]\n\n# Step 6: Print out route\nputs v1_route.length\nv1_route.each do |w|\n puts \"#{w.location_id}: #{w.arrival_time} ~ #{w.finish_time}\"\nend", "language": "ruby", "name": "Ruby" }, { "code": "# Step 1: Import http client and set routific vrp url\nimport urllib2\nimport json\n\nURL = \"https://api.routific.com/v1/vrp\"\n\n# Step 2: Prepare visits\nvisits = {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n }\n },\n \"order_2\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n }\n },\n \"order_3\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n }\n }\n}\n\n# Step 3: Prepare vehicles\nfleet = {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n }\n },\n \"vehicle_2\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n }\n }\n}\n\n# Step 4: Prepare data payload\ndata = {\n \"visits\": visits,\n \"fleet\": fleet\n}\n\n# Step 5: Put together request\n# This is your demo token\ntoken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1MzEzZDZiYTNiMDBkMzA4MDA2ZTliOGEiLCJpYXQiOjEzOTM4MDkwODJ9.PR5qTHsqPogeIIe0NyH2oheaGR-SJXDsxPTcUQNq90E'\n\nreq = urllib2.Request(URL, json.dumps(data))\nreq.add_header('Content-Type', 'application/json')\nreq.add_header('Authorization', \"bearer \" + token)\n\n# Step 6: Get route\nres = urllib2.urlopen(req).read()\n\nprint res", "language": "python", "name": "Python" }, { "code": "<?php\n\n// Step 1: Prepare http client and set routific base url\n\nrequire 'vendor/autoload.php';\nuse GuzzleHttpClient;\n$url = 'https://api.routific.com/v1/';\n$client = new Client([\n 'base_uri' => $url,\n]);\n\n// Step 2: Prepare visits\n$order1 = array(\n \"location\" => array(\n \"name\" => \"6800 Cambie\",\n \"lat\" => 49.227107,\n \"lng\" => -123.1163085\n));\n$order2 = array(\n \"location\" => array(\n \"name\" => \"3780 Arbutus\",\n \"lat\" => 49.2474624,\n \"lng\" => -123.1532338\n));\n$order3 = array(\n \"location\" => array(\n \"name\" => \"800 Robson\",\n \"lat\" => 49.2819229,\n \"lng\" => -123.1211844\n));\n$visits = array(\n \"order_1\" => $order1,\n \"order_2\" => $order2,\n \"order_3\" => $order3\n);\n\n// Step 3: Prepare vehicles\n$vehicle1 = array(\n \"start_location\" => array(\n \"id\" => \"depot\",\n \"name\" => \"800 Kingsway\",\n \"lat\" => 49.2553636,\n \"lng\" => -123.0873365\n));\n\n$vehicle2 = array(\n \"start_location\" => array(\n \"id\" => \"depot\",\n \"name\" => \"800 Kingsway\",\n \"lat\" => 49.2553636,\n \"lng\" => -123.0873365\n));\n\n$vehicles = array(\n \"vehicle_1\" => $vehicle1,\n \"vehicle_2\" => $vehicle2,\n);\n\n// Step 4: Prepare data payload\n$payload = array(\n \"visits\" => $visits,\n \"fleet\" => $vehicles\n);\n\n// Step 5: Send request\n// This is your demo token\n$token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1MzEzZDZiYTNiMDBkMzA4MDA2ZTliOGEiLCJpYXQiOjEzOTM4MDkwODJ9.PR5qTHsqPogeIIe0NyH2oheaGR-SJXDsxPTcUQNq90E';\n\n$response = $client->post('vrp', [\n 'json' => $payload,\n 'headers' => [\n \"Content-type\" => \"application/json\",\n \"Authorization\" => \"bearer \" . $token\n ]\n]);\necho $response->getBody();\n?>", "language": "text", "name": "PHP" } ] } [/block] This example is populated with a demo token, so you can copy and paste the above for a working example. [Sign up](https://routific.com/portal/account/#/signup) for an account to get your API access token. The contents of the JSON input and output are shown to the right. [block:callout] { "type": "info", "title": "Time formats", "body": "All examples in this documentation uses the `hh:mm` time formats with a 24-hour military notation. Our API also supports [UNIX times](https://en.wikipedia.org/wiki/Unix_time), which would make dealing with routing across multiple timezones easier.\n\nUNIX time values are defined as number of seconds since epoch time in UTC (00:00:00, January 1st, 1970).\n\nWhen the input uses UNIX time formats, the output will also returned in UNIX time. When the input is in `hh:mm` format, so will the output. Note: Unix time stamps are numbers.\n\nHere's an example:\n\n```\n\"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n },\n \"start\": 1531324800,\n \"end\": 1531335600,\n \"duration\": 10\n }\n```" } [/block] [block:code] { "codes": [ { "code": "{\n \"visits\": {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n },\n \"start\": \"9:00\",\n \"end\": \"12:00\",\n \"duration\": 10\n },\n \"order_2\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n },\n \"start\": \"9:00\",\n \"end\": \"12:00\",\n \"duration\": 10\n },\n \"order_3\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n },\n \"start\": \"8:00\",\n \"end\": \"9:00\",\n \"duration\": 10\n }\n },\n \"fleet\": {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"end_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"shift_start\": \"8:00\",\n \"shift_end\": \"12:00\"\n }\n }\n}\n", "language": "json", "name": "Input" }, { "code": "{\n \"status\": \"success\",\n \"total_travel_time\": 31.983334,\n \"total_idle_time\": 0,\n \"num_unserved\": 0,\n \"unserved\": null,\n \"solution\": {\n \"vehicle_1\": [\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\",\n \"arrival_time\": \"08:00\"\n },\n {\n \"location_id\": \"order_3\",\n \"location_name\": \"800 Robson\",\n \"arrival_time\": \"08:10\",\n \"finish_time\": \"08:20\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"3780 Arbutus\",\n \"arrival_time\": \"08:29\",\n \"finish_time\": \"09:10\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"6800 Cambie\",\n \"arrival_time\": \"09:19\",\n \"finish_time\": \"09:29\"\n },\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\",\n \"arrival_time\": \"09:39\"\n }\n ]\n }\n}", "language": "json", "name": "Output" } ], "sidebar": true } [/block] To play around with a few worked examples we recommend a REST client called [Postman](https://www.getpostman.com/). Simply tap the button below to import a pre-made collection of API requests. [![Run in Postman](https://run.pstmn.io/button.svg)](https://app.getpostman.com/run-collection/36e5a36c27e7ca9b9873)
{"_id":"5b2c2fa8f4eae600035b716e","category":"5b2c2fa8f4eae600035b7166","user":"5465590bf42a472000b0c6b7","project":"546559525871e90800f503c0","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":["556ceb79c14029190092d2ee"],"next":{"pages":[],"description":""},"createdAt":"2015-05-26T01:08:44.251Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"language":"json","code":"{}","name":"","status":200},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":2,"body":"Route optimization can come in many different flavors, with many different constraints. There are two major classes of routing problems: [basic vehicle routing](/docs/api-endpoints) and [same-day pickup and delivery routing](/docs/overview).\n\nBasic vehicle routing – available at `/vrp` – is about finding the optimal routes for your fleet to serve all your visits. \n\nHowever, if you run a same-day pickup and delivery operation, your visits will have 2 locations that depend on each other: a pickup location and a delivery location. For these kinds of routing problems you may use the `/pdp` endpoint.\n\nThe default endpoints work great if your requests are relatively small, and can be solved quickly. When we receive the POST request, we will respond immediately with the optimized routes. \n\nFor larger routing problems (requests with more than 60 visits) it is generally better to use long-running tasks, which are either `/vrp-long` or `/pdp-long`.  \n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"On the synchronous endpoints we will return a `408` timeout error if the request takes longer than 20 seconds. The synchronous endpoints should only be used for small and frequent route requests. It **does not support** the full algorithm capabilities.  It is recommended to use the asynchronous endpoints by default.\",\n  \"title\": \"\"\n}\n[/block]\nThese are the available endpoints:\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"[https://api.routific.com/v1/vrp](doc:api-endpoints)\",\n    \"1-0\": \"[https://api.routific.com/v1/vrp-long](doc:vrp-long)\",\n    \"2-0\": \"[https://api.routific.com/v1/pdp](doc:overview)\",\n    \"3-0\": \"[https://api.routific.com/v1/pdp-long](doc:overview)\",\n    \"0-1\": \"Synchronous Vehicle Routing API\",\n    \"1-1\": \"Long-running task for VRP\",\n    \"2-1\": \"Pickup and Delivery API\",\n    \"3-1\": \"Long-running task for PDP\"\n  },\n  \"cols\": 2,\n  \"rows\": 4\n}\n[/block]","excerpt":"","slug":"api-endpoints-1","type":"basic","title":"API Endpoints","__v":0,"childrenPages":[]}

API Endpoints


Route optimization can come in many different flavors, with many different constraints. There are two major classes of routing problems: [basic vehicle routing](/docs/api-endpoints) and [same-day pickup and delivery routing](/docs/overview). Basic vehicle routing – available at `/vrp` – is about finding the optimal routes for your fleet to serve all your visits. However, if you run a same-day pickup and delivery operation, your visits will have 2 locations that depend on each other: a pickup location and a delivery location. For these kinds of routing problems you may use the `/pdp` endpoint. The default endpoints work great if your requests are relatively small, and can be solved quickly. When we receive the POST request, we will respond immediately with the optimized routes. For larger routing problems (requests with more than 60 visits) it is generally better to use long-running tasks, which are either `/vrp-long` or `/pdp-long`. [block:callout] { "type": "warning", "body": "On the synchronous endpoints we will return a `408` timeout error if the request takes longer than 20 seconds. The synchronous endpoints should only be used for small and frequent route requests. It **does not support** the full algorithm capabilities. It is recommended to use the asynchronous endpoints by default.", "title": "" } [/block] These are the available endpoints: [block:parameters] { "data": { "0-0": "[https://api.routific.com/v1/vrp](doc:api-endpoints)", "1-0": "[https://api.routific.com/v1/vrp-long](doc:vrp-long)", "2-0": "[https://api.routific.com/v1/pdp](doc:overview)", "3-0": "[https://api.routific.com/v1/pdp-long](doc:overview)", "0-1": "Synchronous Vehicle Routing API", "1-1": "Long-running task for VRP", "2-1": "Pickup and Delivery API", "3-1": "Long-running task for PDP" }, "cols": 2, "rows": 4 } [/block]
Route optimization can come in many different flavors, with many different constraints. There are two major classes of routing problems: [basic vehicle routing](/docs/api-endpoints) and [same-day pickup and delivery routing](/docs/overview). Basic vehicle routing – available at `/vrp` – is about finding the optimal routes for your fleet to serve all your visits. However, if you run a same-day pickup and delivery operation, your visits will have 2 locations that depend on each other: a pickup location and a delivery location. For these kinds of routing problems you may use the `/pdp` endpoint. The default endpoints work great if your requests are relatively small, and can be solved quickly. When we receive the POST request, we will respond immediately with the optimized routes. For larger routing problems (requests with more than 60 visits) it is generally better to use long-running tasks, which are either `/vrp-long` or `/pdp-long`. [block:callout] { "type": "warning", "body": "On the synchronous endpoints we will return a `408` timeout error if the request takes longer than 20 seconds. The synchronous endpoints should only be used for small and frequent route requests. It **does not support** the full algorithm capabilities. It is recommended to use the asynchronous endpoints by default.", "title": "" } [/block] These are the available endpoints: [block:parameters] { "data": { "0-0": "[https://api.routific.com/v1/vrp](doc:api-endpoints)", "1-0": "[https://api.routific.com/v1/vrp-long](doc:vrp-long)", "2-0": "[https://api.routific.com/v1/pdp](doc:overview)", "3-0": "[https://api.routific.com/v1/pdp-long](doc:overview)", "0-1": "Synchronous Vehicle Routing API", "1-1": "Long-running task for VRP", "2-1": "Pickup and Delivery API", "3-1": "Long-running task for PDP" }, "cols": 2, "rows": 4 } [/block]
{"_id":"5b2c2fa8f4eae600035b716f","category":"5b2c2fa8f4eae600035b7166","project":"546559525871e90800f503c0","user":"5465590bf42a472000b0c6b7","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":[],"next":{"pages":[],"description":""},"createdAt":"2014-11-29T01:37:39.317Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"language":"json","code":"{}","name":"","status":400}]},"settings":"","auth":"never","params":[],"url":""},"isReference":false,"order":3,"body":"[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"https://api.routific.com/v1/vrp-long\",\n      \"language\": \"curl\"\n    }\n  ]\n}\n[/block]\nThe `vrp-long` and `pdp-long` endpoints will trigger a long-running background task on our servers, while we give you a URL to ping to fetch the results. This is necessary for larger requests that take longer than 20 seconds. Here are some processing times to give you a rough idea:\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Number of visits\",\n    \"h-1\": \"Processing time\",\n    \"1-0\": \"50\",\n    \"1-1\": \"8s\",\n    \"0-0\": \"< 30\",\n    \"0-1\": \"< 2s\",\n    \"2-0\": \"100\",\n    \"2-1\": \"35s\",\n    \"3-0\": \"500\",\n    \"3-1\": \"280s\",\n    \"4-0\": \"1000\",\n    \"4-1\": \"600s\"\n  },\n  \"cols\": 2,\n  \"rows\": 5\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Processing times may vary\",\n  \"body\": \"Keep in mind that the above processing times are averages; exact processing times may vary greatly, depending on the fleet size, as well as number of constraints.\"\n}\n[/block]\nWhen you POST to the above URL, it will return immediately with a `202` HTTP code and a `job_id`:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{ \\\"job_id\\\": \\\"[someID]\\\" }\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\nWith this `job_id` you can query the status with a GET request to the following URL:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"https://api.routific.com/jobs/[someID]\",\n      \"language\": \"curl\"\n    }\n  ]\n}\n[/block]\nWhen the job is still busy, the status will be `pending` or `processing`. Once it is finished, the status is `finished`. The response that you would normally get directly from the synchronous endpoint, is now in `output`. \n\nIf there was an error during processing, the status will be `error` and the error message will be a string in the `output`. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  \\\"visits\\\": {\\n    \\\"order_1\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"6800 Cambie\\\",\\n        \\\"lat\\\": 49.227107,\\n        \\\"lng\\\": -123.1163085\\n      }\\n    },\\n    \\\"order_2\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"3780 Arbutus\\\",\\n        \\\"lat\\\": 49.2474624,\\n        \\\"lng\\\": -123.1532338\\n      }\\n    },\\n    \\\"order_3\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"800 Robson\\\",\\n        \\\"lat\\\": 49.2819229,\\n        \\\"lng\\\": -123.1211844\\n      }\\n    }\\n  },\\n  \\\"fleet\\\": {\\n    \\\"vehicle_1\\\": {\\n      \\\"start_location\\\": {\\n        \\\"id\\\": \\\"depot\\\",\\n        \\\"name\\\": \\\"800 Kingsway\\\",\\n        \\\"lat\\\": 49.2553636,\\n        \\\"lng\\\": -123.0873365\\n      }\\n    }\\n  }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Input\"\n    },\n    {\n      \"code\": \"{ \\\"job_id\\\": \\\"[someID]\\\" }\",\n      \"language\": \"json\",\n      \"name\": \"Response\"\n    },\n    {\n      \"code\": \"{\\n  \\\"status\\\": \\\"pending\\\",\\n  \\\"input\\\": { ... },\\n  \\\"id\\\": \\\"[someID]\\\",\\n  \\\"started_at\\\": [timestamp]\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Pending\"\n    },\n    {\n      \"code\": \"{\\n  \\\"status\\\": \\\"finished\\\",\\n  \\\"output\\\": {\\n    \\\"status\\\": \\\"success\\\",\\n    \\\"fitness\\\": 31,\\n    \\\"unserved:\\\": null,\\n    \\\"solution\\\": { ... }\\n  },\\n  \\\"id\\\": \\\"[someID]\\\",\\n  \\\"started_at\\\": [timestamp],\\n  \\\"finished_at\\\": [timestamp],\\n  \\\"input\\\": { ... }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Finished\"\n    },\n    {\n      \"code\": \"{\\n  \\\"status\\\": \\\"error\\\",\\n  \\\"input\\\": { ... },\\n  \\\"id\\\": \\\"[someID]\\\",\\n  \\\"started_at\\\": [timestamp],\\n  \\\"output\\\": \\\"Sorry - we couldn't find a route for you today. Can you check your driver/stop inputs?\\\"\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Error\"\n    }\n  ],\n  \"sidebar\": true\n}\n[/block]","excerpt":"","slug":"vrp-long","type":"basic","title":"Long-running tasks","__v":0,"childrenPages":[]}

Long-running tasks


[block:code] { "codes": [ { "code": "https://api.routific.com/v1/vrp-long", "language": "curl" } ] } [/block] The `vrp-long` and `pdp-long` endpoints will trigger a long-running background task on our servers, while we give you a URL to ping to fetch the results. This is necessary for larger requests that take longer than 20 seconds. Here are some processing times to give you a rough idea: [block:parameters] { "data": { "h-0": "Number of visits", "h-1": "Processing time", "1-0": "50", "1-1": "8s", "0-0": "< 30", "0-1": "< 2s", "2-0": "100", "2-1": "35s", "3-0": "500", "3-1": "280s", "4-0": "1000", "4-1": "600s" }, "cols": 2, "rows": 5 } [/block] [block:callout] { "type": "warning", "title": "Processing times may vary", "body": "Keep in mind that the above processing times are averages; exact processing times may vary greatly, depending on the fleet size, as well as number of constraints." } [/block] When you POST to the above URL, it will return immediately with a `202` HTTP code and a `job_id`: [block:code] { "codes": [ { "code": "{ \"job_id\": \"[someID]\" }", "language": "json" } ] } [/block] With this `job_id` you can query the status with a GET request to the following URL: [block:code] { "codes": [ { "code": "https://api.routific.com/jobs/[someID]", "language": "curl" } ] } [/block] When the job is still busy, the status will be `pending` or `processing`. Once it is finished, the status is `finished`. The response that you would normally get directly from the synchronous endpoint, is now in `output`. If there was an error during processing, the status will be `error` and the error message will be a string in the `output`. [block:code] { "codes": [ { "code": "{\n \"visits\": {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n }\n },\n \"order_2\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n }\n },\n \"order_3\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n }\n }\n },\n \"fleet\": {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n }\n }\n }\n}", "language": "json", "name": "Input" }, { "code": "{ \"job_id\": \"[someID]\" }", "language": "json", "name": "Response" }, { "code": "{\n \"status\": \"pending\",\n \"input\": { ... },\n \"id\": \"[someID]\",\n \"started_at\": [timestamp]\n}", "language": "json", "name": "Pending" }, { "code": "{\n \"status\": \"finished\",\n \"output\": {\n \"status\": \"success\",\n \"fitness\": 31,\n \"unserved:\": null,\n \"solution\": { ... }\n },\n \"id\": \"[someID]\",\n \"started_at\": [timestamp],\n \"finished_at\": [timestamp],\n \"input\": { ... }\n}", "language": "json", "name": "Finished" }, { "code": "{\n \"status\": \"error\",\n \"input\": { ... },\n \"id\": \"[someID]\",\n \"started_at\": [timestamp],\n \"output\": \"Sorry - we couldn't find a route for you today. Can you check your driver/stop inputs?\"\n}", "language": "json", "name": "Error" } ], "sidebar": true } [/block]
[block:code] { "codes": [ { "code": "https://api.routific.com/v1/vrp-long", "language": "curl" } ] } [/block] The `vrp-long` and `pdp-long` endpoints will trigger a long-running background task on our servers, while we give you a URL to ping to fetch the results. This is necessary for larger requests that take longer than 20 seconds. Here are some processing times to give you a rough idea: [block:parameters] { "data": { "h-0": "Number of visits", "h-1": "Processing time", "1-0": "50", "1-1": "8s", "0-0": "< 30", "0-1": "< 2s", "2-0": "100", "2-1": "35s", "3-0": "500", "3-1": "280s", "4-0": "1000", "4-1": "600s" }, "cols": 2, "rows": 5 } [/block] [block:callout] { "type": "warning", "title": "Processing times may vary", "body": "Keep in mind that the above processing times are averages; exact processing times may vary greatly, depending on the fleet size, as well as number of constraints." } [/block] When you POST to the above URL, it will return immediately with a `202` HTTP code and a `job_id`: [block:code] { "codes": [ { "code": "{ \"job_id\": \"[someID]\" }", "language": "json" } ] } [/block] With this `job_id` you can query the status with a GET request to the following URL: [block:code] { "codes": [ { "code": "https://api.routific.com/jobs/[someID]", "language": "curl" } ] } [/block] When the job is still busy, the status will be `pending` or `processing`. Once it is finished, the status is `finished`. The response that you would normally get directly from the synchronous endpoint, is now in `output`. If there was an error during processing, the status will be `error` and the error message will be a string in the `output`. [block:code] { "codes": [ { "code": "{\n \"visits\": {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n }\n },\n \"order_2\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n }\n },\n \"order_3\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n }\n }\n },\n \"fleet\": {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n }\n }\n }\n}", "language": "json", "name": "Input" }, { "code": "{ \"job_id\": \"[someID]\" }", "language": "json", "name": "Response" }, { "code": "{\n \"status\": \"pending\",\n \"input\": { ... },\n \"id\": \"[someID]\",\n \"started_at\": [timestamp]\n}", "language": "json", "name": "Pending" }, { "code": "{\n \"status\": \"finished\",\n \"output\": {\n \"status\": \"success\",\n \"fitness\": 31,\n \"unserved:\": null,\n \"solution\": { ... }\n },\n \"id\": \"[someID]\",\n \"started_at\": [timestamp],\n \"finished_at\": [timestamp],\n \"input\": { ... }\n}", "language": "json", "name": "Finished" }, { "code": "{\n \"status\": \"error\",\n \"input\": { ... },\n \"id\": \"[someID]\",\n \"started_at\": [timestamp],\n \"output\": \"Sorry - we couldn't find a route for you today. Can you check your driver/stop inputs?\"\n}", "language": "json", "name": "Error" } ], "sidebar": true } [/block]
{"_id":"5b2c2fa8f4eae600035b7172","category":"5b2c2fa8f4eae600035b7167","project":"546559525871e90800f503c0","user":"5465590bf42a472000b0c6b7","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":[],"next":{"pages":[],"description":""},"createdAt":"2014-11-28T20:38:08.930Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"language":"json","code":"{}","name":"","status":200},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"never","params":[],"url":""},"isReference":false,"order":0,"body":"[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"https://api.routific.com/v1/vrp\",\n      \"language\": \"curl\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"For requests with more than 60 visits, it is necessary to use the asynchronous endpoint `/vrp-long` for [long-running tasks](/v1.0/docs/vrp-long) to avoid timeouts. We recommend that you to use this endpoint even for smaller requests.\",\n  \"title\": \"Choosing which endpoint to use\"\n}\n[/block]\nThe `/vrp` endpoint can solve the [Traveling Salesman Problem](http://en.wikipedia.org/wiki/Travelling_salesman_problem) as well as the [Vehicle Routing Problem](http://en.wikipedia.org/wiki/Vehicle_routing_problem). It supports the following:\n\n- Time-windows\n- Capacity constraints\n- Visit durations\n- Multiple depots\n- Open-ended routes\n- Type constraints\n- Driver shifts\n\nThere are two objects required in your input: [Visits](doc:input) and [Fleet](doc:fleet). A third [Options](doc:options) object is optional.\n\nSee the sidebar for a very simple example with the minimum required parameters.\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  \\\"visits\\\": {\\n    \\\"order_1\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"6800 Cambie\\\",\\n        \\\"lat\\\": 49.227107,\\n        \\\"lng\\\": -123.1163085\\n      }\\n    },\\n    \\\"order_2\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"3780 Arbutus\\\",\\n        \\\"lat\\\": 49.2474624,\\n        \\\"lng\\\": -123.1532338\\n      }\\n    },\\n    \\\"order_3\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"800 Robson\\\",\\n        \\\"lat\\\": 49.2819229,\\n        \\\"lng\\\": -123.1211844\\n      }\\n    }\\n  },\\n  \\\"fleet\\\": {\\n    \\\"vehicle_1\\\": {\\n      \\\"start_location\\\": {\\n        \\\"id\\\": \\\"depot\\\",\\n        \\\"name\\\": \\\"800 Kingsway\\\",\\n        \\\"lat\\\": 49.2553636,\\n        \\\"lng\\\": -123.0873365\\n      }\\n    }\\n  }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Input\"\n    },\n    {\n      \"code\": \"{\\n  \\\"status\\\": \\\"success\\\",\\n  \\\"fitness\\\": 1450,\\n  \\\"total_travel_time\\\": 24.166666,\\n  \\\"total_idle_time\\\": 0,\\n  \\\"num_unserved\\\": 0,\\n  \\\"unserved\\\": null,\\n  \\\"solution\\\": {\\n    \\\"vehicle_1\\\": [\\n      {\\n        \\\"location_id\\\": \\\"depot\\\",\\n        \\\"location_name\\\": \\\"800 Kingsway\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_3\\\",\\n        \\\"location_name\\\": \\\"800 Robson\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_2\\\",\\n        \\\"location_name\\\": \\\"3780 Arbutus\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_1\\\",\\n        \\\"location_name\\\": \\\"6800 Cambie\\\"\\n      }\\n    ]\\n  }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Output\"\n    }\n  ],\n  \"sidebar\": true\n}\n[/block]","excerpt":"","slug":"api-endpoints","type":"basic","title":"Vehicle Routing Overview","__v":0,"childrenPages":[]}

Vehicle Routing Overview


[block:code] { "codes": [ { "code": "https://api.routific.com/v1/vrp", "language": "curl" } ] } [/block] [block:callout] { "type": "info", "body": "For requests with more than 60 visits, it is necessary to use the asynchronous endpoint `/vrp-long` for [long-running tasks](/v1.0/docs/vrp-long) to avoid timeouts. We recommend that you to use this endpoint even for smaller requests.", "title": "Choosing which endpoint to use" } [/block] The `/vrp` endpoint can solve the [Traveling Salesman Problem](http://en.wikipedia.org/wiki/Travelling_salesman_problem) as well as the [Vehicle Routing Problem](http://en.wikipedia.org/wiki/Vehicle_routing_problem). It supports the following: - Time-windows - Capacity constraints - Visit durations - Multiple depots - Open-ended routes - Type constraints - Driver shifts There are two objects required in your input: [Visits](doc:input) and [Fleet](doc:fleet). A third [Options](doc:options) object is optional. See the sidebar for a very simple example with the minimum required parameters. [block:code] { "codes": [ { "code": "{\n \"visits\": {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n }\n },\n \"order_2\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n }\n },\n \"order_3\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n }\n }\n },\n \"fleet\": {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n }\n }\n }\n}", "language": "json", "name": "Input" }, { "code": "{\n \"status\": \"success\",\n \"fitness\": 1450,\n \"total_travel_time\": 24.166666,\n \"total_idle_time\": 0,\n \"num_unserved\": 0,\n \"unserved\": null,\n \"solution\": {\n \"vehicle_1\": [\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\"\n },\n {\n \"location_id\": \"order_3\",\n \"location_name\": \"800 Robson\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"3780 Arbutus\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"6800 Cambie\"\n }\n ]\n }\n}", "language": "json", "name": "Output" } ], "sidebar": true } [/block]
[block:code] { "codes": [ { "code": "https://api.routific.com/v1/vrp", "language": "curl" } ] } [/block] [block:callout] { "type": "info", "body": "For requests with more than 60 visits, it is necessary to use the asynchronous endpoint `/vrp-long` for [long-running tasks](/v1.0/docs/vrp-long) to avoid timeouts. We recommend that you to use this endpoint even for smaller requests.", "title": "Choosing which endpoint to use" } [/block] The `/vrp` endpoint can solve the [Traveling Salesman Problem](http://en.wikipedia.org/wiki/Travelling_salesman_problem) as well as the [Vehicle Routing Problem](http://en.wikipedia.org/wiki/Vehicle_routing_problem). It supports the following: - Time-windows - Capacity constraints - Visit durations - Multiple depots - Open-ended routes - Type constraints - Driver shifts There are two objects required in your input: [Visits](doc:input) and [Fleet](doc:fleet). A third [Options](doc:options) object is optional. See the sidebar for a very simple example with the minimum required parameters. [block:code] { "codes": [ { "code": "{\n \"visits\": {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n }\n },\n \"order_2\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n }\n },\n \"order_3\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n }\n }\n },\n \"fleet\": {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n }\n }\n }\n}", "language": "json", "name": "Input" }, { "code": "{\n \"status\": \"success\",\n \"fitness\": 1450,\n \"total_travel_time\": 24.166666,\n \"total_idle_time\": 0,\n \"num_unserved\": 0,\n \"unserved\": null,\n \"solution\": {\n \"vehicle_1\": [\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\"\n },\n {\n \"location_id\": \"order_3\",\n \"location_name\": \"800 Robson\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"3780 Arbutus\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"6800 Cambie\"\n }\n ]\n }\n}", "language": "json", "name": "Output" } ], "sidebar": true } [/block]
{"_id":"5b2c2fa8f4eae600035b7173","category":"5b2c2fa8f4eae600035b7168","project":"546559525871e90800f503c0","user":"5465590bf42a472000b0c6b7","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":[],"next":{"pages":[],"description":""},"createdAt":"2014-11-24T23:46:24.559Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"never","params":[],"url":""},"isReference":false,"order":0,"body":"The **visits** object is a hash of each visit and their properties, where the key is the visit ID. Each visit object has to contain a location object with the geographic coordinates (`lat` and `lng`). Note that the `name` parameter in the `location` object is optional.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\\"visits\\\": {\\n  \\\"order_1\\\": {\\n    \\\"location\\\": {\\n      \\\"name\\\": \\\"6800 Cambie\\\",\\n      \\\"lat\\\": 49.227107,\\n      \\\"lng\\\": -123.1163085\\n    },\\n    \\\"start\\\": \\\"9:00\\\",\\n    \\\"end\\\": \\\"12:00\\\",\\n    \\\"duration\\\": 10,\\n    \\\"load\\\": 1,\\n    \\\"type\\\": \\\"A\\\",\\n    \\\"priority\\\": \\\"high\\\"\\n  }\\n}\\n\",\n      \"language\": \"json\"\n    }\n  ],\n  \"sidebar\": true\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"success\",\n  \"title\": \"Address geocoding (new)\",\n  \"body\": \"If you don't want to specify the latitude and longitude of the `location` object, you can also send the full address and Routific will geocode it for you.\\n\\n```\\n\\\"location\\\": {\\n      \\\"name\\\": \\\"Routific World Headquarters\\\",\\n      \\\"address\\\": \\\"555 W Hastings Street, Vancouver, BC V6B4N6, Canada\\\"\\n    }\\n```\\n\\nIf our server is unable to locate an address, don't worry - Routific will still parse the remaining valid addresses. Together with the route solution our API will return a `failedGeocoding` object (an array of strings) specifying which visits were unable to be geocoded.\\n\\n```\\n\\\"output\\\": {\\n\\t\\t\\\"failedGeocoding\\\": [\\\"123 Routific Avenue\\\"],\\n\\t\\t\\\"message\\\": \\\"Failed to geocode some locations\\\"\\n\\t}\\n```\\n\\nAddress geocoding only works on our `/vrp-long` and `/pdp-long` endpoints.\"\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"PROPERTY\",\n    \"h-1\": \"TYPE\",\n    \"h-2\": \"REQUIRED\",\n    \"0-0\": \"location\",\n    \"0-1\": \"Location object\",\n    \"0-2\": \"required\",\n    \"1-0\": \"start\",\n    \"1-1\": \"String (\\\"hh:mm\\\")\",\n    \"1-2\": \"optional\",\n    \"2-0\": \"end\",\n    \"2-1\": \"String (\\\"hh:mm\\\")\",\n    \"2-2\": \"optional\",\n    \"3-0\": \"duration\",\n    \"3-1\": \"Number (minutes)\",\n    \"3-2\": \"optional\",\n    \"4-0\": \"load\",\n    \"4-1\": \"Number (any unit) or Object\",\n    \"4-2\": \"optional\",\n    \"5-0\": \"type\",\n    \"5-1\": \"String or Array\",\n    \"5-2\": \"optional\",\n    \"6-0\": \"priority\",\n    \"6-1\": \"String (low, regular(default), high) or Number\",\n    \"6-2\": \"optional\",\n    \"7-0\": \"time_windows\",\n    \"7-1\": \"Array\",\n    \"7-2\": \"optional\",\n    \"8-0\": \"notes\",\n    \"8-1\": \"String\",\n    \"8-2\": \"optional\",\n    \"9-0\": \"customNotes\",\n    \"9-1\": \"Object\",\n    \"9-2\": \"optional\"\n  },\n  \"cols\": 3,\n  \"rows\": 10\n}\n[/block]\n\nEach visit can have a time-window constraint, defined by `start` and `end`. Time windows are optional; when they are not provided, it implies that any time will do. You can also say \"anytime after 9am\" by setting the `start` time to `9:00` and omitting the `end` parameter.\n\n`duration` specifies how many minutes the visit takes. If a delivery takes 30 minutes and is given a time-window of 12:00-13:00, the algorithm will make sure that you arrive by 12:30 at the latest. Note that if the duration does not fit in the time-window, the visit will not be assigned to any vehicle. It is good practice to always specify a `duration`. If you don't, the engine will not return estimated arrival times for each visit.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Pro tip:\",\n  \"body\": \"The duration parameter may be used as a buffer parameter to accommodate for real-life delays such as parking and traffic lights, and thus avoid arriving late at a location. The only drawback of using too large a buffer, is that it leaves the algorithm less room to optimize.\\n\\nYou may also want to consider simulating slow **traffic**, see the [traffic](/docs/options) parameter below.\"\n}\n[/block]\n`load` is used when you want to account for the capacity of your vehicles. This capacity must be defined with your fleet as well, otherwise this parameter will be ignored.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Multiple loads & capacities\",\n  \"body\": \"You may also specify multiple load parameters if you provide an object. This is useful if you define your load across multiple dimensions, for example weight and volume:\\n\\n```\\n\\\"load\\\": { \\n  \\\"weight\\\": 10,\\n  \\\"volume\\\": 200\\n}\\n```\\n\\nThe entire load has to fit in the remaining vehicle capacity for it to be assigned. Now you can distinguish heavy goods that are small from large goods that are light :)\\n\\nAnother way to use multiple loads is to specify product-level details:\\n\\n```\\n\\\"load\\\": {\\n  \\\"large_item\\\": 1,\\n  \\\"small_item\\\": 5,\\n  \\\"other_stuff\\\": 2\\n}\\n```\\n\\nNote that if you specify multiple loads, these loads need to correspond with the `capacity` parameter in the vehicle object. If not, they will be unserved with the message `\\\"The loads cannot fit in any vehicle.\\\"`\"\n}\n[/block]\n`type` is an optional parameter if you want to restrict a visit so it can only be served by a particular type of vehicle. The value of this parameter can be a String or an Array of Strings for multiple types. For example, if a visit is of type `[\"A\",\"B\"]` it can be served by a vehicle of type `\"A\"` or `\"B\"`. If none of the vehicles match the type, it will be unserved. Visits without any type parameters can be served by vehicles with or without a type associated with it.\n\n`priority` allows you to make certain visits a priority over others. In some cases you have more visits than you can serve, resulting in a few unserved. But if you want to make sure your high priority visits take precedence, use this parameter and set it to `\"high\"`.\n\nFor more control, you can also specify a priority number between 1 and 10,000. Visits with a higher priority number will take precedence over the lower priority visits. So if you have a visit (A) that has a priority level of 10 and is far away, and 3 other visits (B, C, D) with priority level 5 that are close by, then in a situation where you can feasibly visit *either* A *or* (B + C + D), the solution Routific will return is the latter, because the total combined priority score is 15. \n\nIf instead you wanted visit A to be served while discarding B, C, and D, then you'll need to increase the priority number for A. \n\nJust for reference: \"low\" corresponds to 1, regular is 5, whereas \"high\" maps to 10.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Second time-window\",\n  \"body\": \"You can also specify two time-windows using the `time_windows` parameter instead of `start` and `end`. This is especially useful if you need to avoid delivery between a certain time. For example, the delivery should happen between 9:00-12:00 OR between 13:30-18:00.\\n\\nYou can specify this as follows: \\n\\n```\\n\\\"time_windows\\\": [\\n    {\\n      \\\"start\\\": \\\"09:00\\\",\\n      \\\"end\\\": \\\"12:00\\\"\\n    },\\n    {\\n      \\\"start\\\": \\\"13:30\\\",\\n      \\\"end\\\": \\\"18:00\\\"\\n    }\\n  ]\\n```\\n\\nNote that the `time_windows` array needs to be in chronological order.\"\n}\n[/block]\nIf you want to send notes to a driver for a given visit (e.g. the number of packages in an order or delivery instructions), you can add add a `notes` parameter to the visits object. These notes will be preserved in the json returned by the Routing Engine and will be displayed on our web and driver apps if you have an API integration enabled with Routific.\n[block:callout]\n{\n  \"type\": \"success\",\n  \"title\": \"Custom notes (new)\",\n  \"body\": \"If you want to add additional information such as weight or price to a visit, you can also create a custom notes parameter and add it to the `visits` object. Just as with the `notes` parameter, this information will be shown on our web and driver apps if you have an API integration with Routific (Contact [support](mailto:support@routific.com) if you want to enable an API integration).\\n\\n```\\n\\\"customNotes\\\": {\\n   \\\"weight\\\": \\\"100 kg\\\",\\n   \\\"price\\\": \\\"$50\\\"\\n}\\n```\"\n}\n[/block]","excerpt":"","slug":"input","type":"basic","title":"Visits","__v":0,"childrenPages":[]}

Visits


The **visits** object is a hash of each visit and their properties, where the key is the visit ID. Each visit object has to contain a location object with the geographic coordinates (`lat` and `lng`). Note that the `name` parameter in the `location` object is optional. [block:code] { "codes": [ { "code": "\"visits\": {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n },\n \"start\": \"9:00\",\n \"end\": \"12:00\",\n \"duration\": 10,\n \"load\": 1,\n \"type\": \"A\",\n \"priority\": \"high\"\n }\n}\n", "language": "json" } ], "sidebar": true } [/block] [block:callout] { "type": "success", "title": "Address geocoding (new)", "body": "If you don't want to specify the latitude and longitude of the `location` object, you can also send the full address and Routific will geocode it for you.\n\n```\n\"location\": {\n \"name\": \"Routific World Headquarters\",\n \"address\": \"555 W Hastings Street, Vancouver, BC V6B4N6, Canada\"\n }\n```\n\nIf our server is unable to locate an address, don't worry - Routific will still parse the remaining valid addresses. Together with the route solution our API will return a `failedGeocoding` object (an array of strings) specifying which visits were unable to be geocoded.\n\n```\n\"output\": {\n\t\t\"failedGeocoding\": [\"123 Routific Avenue\"],\n\t\t\"message\": \"Failed to geocode some locations\"\n\t}\n```\n\nAddress geocoding only works on our `/vrp-long` and `/pdp-long` endpoints." } [/block] [block:parameters] { "data": { "h-0": "PROPERTY", "h-1": "TYPE", "h-2": "REQUIRED", "0-0": "location", "0-1": "Location object", "0-2": "required", "1-0": "start", "1-1": "String (\"hh:mm\")", "1-2": "optional", "2-0": "end", "2-1": "String (\"hh:mm\")", "2-2": "optional", "3-0": "duration", "3-1": "Number (minutes)", "3-2": "optional", "4-0": "load", "4-1": "Number (any unit) or Object", "4-2": "optional", "5-0": "type", "5-1": "String or Array", "5-2": "optional", "6-0": "priority", "6-1": "String (low, regular(default), high) or Number", "6-2": "optional", "7-0": "time_windows", "7-1": "Array", "7-2": "optional", "8-0": "notes", "8-1": "String", "8-2": "optional", "9-0": "customNotes", "9-1": "Object", "9-2": "optional" }, "cols": 3, "rows": 10 } [/block] Each visit can have a time-window constraint, defined by `start` and `end`. Time windows are optional; when they are not provided, it implies that any time will do. You can also say "anytime after 9am" by setting the `start` time to `9:00` and omitting the `end` parameter. `duration` specifies how many minutes the visit takes. If a delivery takes 30 minutes and is given a time-window of 12:00-13:00, the algorithm will make sure that you arrive by 12:30 at the latest. Note that if the duration does not fit in the time-window, the visit will not be assigned to any vehicle. It is good practice to always specify a `duration`. If you don't, the engine will not return estimated arrival times for each visit. [block:callout] { "type": "info", "title": "Pro tip:", "body": "The duration parameter may be used as a buffer parameter to accommodate for real-life delays such as parking and traffic lights, and thus avoid arriving late at a location. The only drawback of using too large a buffer, is that it leaves the algorithm less room to optimize.\n\nYou may also want to consider simulating slow **traffic**, see the [traffic](/docs/options) parameter below." } [/block] `load` is used when you want to account for the capacity of your vehicles. This capacity must be defined with your fleet as well, otherwise this parameter will be ignored. [block:callout] { "type": "info", "title": "Multiple loads & capacities", "body": "You may also specify multiple load parameters if you provide an object. This is useful if you define your load across multiple dimensions, for example weight and volume:\n\n```\n\"load\": { \n \"weight\": 10,\n \"volume\": 200\n}\n```\n\nThe entire load has to fit in the remaining vehicle capacity for it to be assigned. Now you can distinguish heavy goods that are small from large goods that are light :)\n\nAnother way to use multiple loads is to specify product-level details:\n\n```\n\"load\": {\n \"large_item\": 1,\n \"small_item\": 5,\n \"other_stuff\": 2\n}\n```\n\nNote that if you specify multiple loads, these loads need to correspond with the `capacity` parameter in the vehicle object. If not, they will be unserved with the message `\"The loads cannot fit in any vehicle.\"`" } [/block] `type` is an optional parameter if you want to restrict a visit so it can only be served by a particular type of vehicle. The value of this parameter can be a String or an Array of Strings for multiple types. For example, if a visit is of type `["A","B"]` it can be served by a vehicle of type `"A"` or `"B"`. If none of the vehicles match the type, it will be unserved. Visits without any type parameters can be served by vehicles with or without a type associated with it. `priority` allows you to make certain visits a priority over others. In some cases you have more visits than you can serve, resulting in a few unserved. But if you want to make sure your high priority visits take precedence, use this parameter and set it to `"high"`. For more control, you can also specify a priority number between 1 and 10,000. Visits with a higher priority number will take precedence over the lower priority visits. So if you have a visit (A) that has a priority level of 10 and is far away, and 3 other visits (B, C, D) with priority level 5 that are close by, then in a situation where you can feasibly visit *either* A *or* (B + C + D), the solution Routific will return is the latter, because the total combined priority score is 15. If instead you wanted visit A to be served while discarding B, C, and D, then you'll need to increase the priority number for A. Just for reference: "low" corresponds to 1, regular is 5, whereas "high" maps to 10. [block:callout] { "type": "info", "title": "Second time-window", "body": "You can also specify two time-windows using the `time_windows` parameter instead of `start` and `end`. This is especially useful if you need to avoid delivery between a certain time. For example, the delivery should happen between 9:00-12:00 OR between 13:30-18:00.\n\nYou can specify this as follows: \n\n```\n\"time_windows\": [\n {\n \"start\": \"09:00\",\n \"end\": \"12:00\"\n },\n {\n \"start\": \"13:30\",\n \"end\": \"18:00\"\n }\n ]\n```\n\nNote that the `time_windows` array needs to be in chronological order." } [/block] If you want to send notes to a driver for a given visit (e.g. the number of packages in an order or delivery instructions), you can add add a `notes` parameter to the visits object. These notes will be preserved in the json returned by the Routing Engine and will be displayed on our web and driver apps if you have an API integration enabled with Routific. [block:callout] { "type": "success", "title": "Custom notes (new)", "body": "If you want to add additional information such as weight or price to a visit, you can also create a custom notes parameter and add it to the `visits` object. Just as with the `notes` parameter, this information will be shown on our web and driver apps if you have an API integration with Routific (Contact [support](mailto:support@routific.com) if you want to enable an API integration).\n\n```\n\"customNotes\": {\n \"weight\": \"100 kg\",\n \"price\": \"$50\"\n}\n```" } [/block]
The **visits** object is a hash of each visit and their properties, where the key is the visit ID. Each visit object has to contain a location object with the geographic coordinates (`lat` and `lng`). Note that the `name` parameter in the `location` object is optional. [block:code] { "codes": [ { "code": "\"visits\": {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n },\n \"start\": \"9:00\",\n \"end\": \"12:00\",\n \"duration\": 10,\n \"load\": 1,\n \"type\": \"A\",\n \"priority\": \"high\"\n }\n}\n", "language": "json" } ], "sidebar": true } [/block] [block:callout] { "type": "success", "title": "Address geocoding (new)", "body": "If you don't want to specify the latitude and longitude of the `location` object, you can also send the full address and Routific will geocode it for you.\n\n```\n\"location\": {\n \"name\": \"Routific World Headquarters\",\n \"address\": \"555 W Hastings Street, Vancouver, BC V6B4N6, Canada\"\n }\n```\n\nIf our server is unable to locate an address, don't worry - Routific will still parse the remaining valid addresses. Together with the route solution our API will return a `failedGeocoding` object (an array of strings) specifying which visits were unable to be geocoded.\n\n```\n\"output\": {\n\t\t\"failedGeocoding\": [\"123 Routific Avenue\"],\n\t\t\"message\": \"Failed to geocode some locations\"\n\t}\n```\n\nAddress geocoding only works on our `/vrp-long` and `/pdp-long` endpoints." } [/block] [block:parameters] { "data": { "h-0": "PROPERTY", "h-1": "TYPE", "h-2": "REQUIRED", "0-0": "location", "0-1": "Location object", "0-2": "required", "1-0": "start", "1-1": "String (\"hh:mm\")", "1-2": "optional", "2-0": "end", "2-1": "String (\"hh:mm\")", "2-2": "optional", "3-0": "duration", "3-1": "Number (minutes)", "3-2": "optional", "4-0": "load", "4-1": "Number (any unit) or Object", "4-2": "optional", "5-0": "type", "5-1": "String or Array", "5-2": "optional", "6-0": "priority", "6-1": "String (low, regular(default), high) or Number", "6-2": "optional", "7-0": "time_windows", "7-1": "Array", "7-2": "optional", "8-0": "notes", "8-1": "String", "8-2": "optional", "9-0": "customNotes", "9-1": "Object", "9-2": "optional" }, "cols": 3, "rows": 10 } [/block] Each visit can have a time-window constraint, defined by `start` and `end`. Time windows are optional; when they are not provided, it implies that any time will do. You can also say "anytime after 9am" by setting the `start` time to `9:00` and omitting the `end` parameter. `duration` specifies how many minutes the visit takes. If a delivery takes 30 minutes and is given a time-window of 12:00-13:00, the algorithm will make sure that you arrive by 12:30 at the latest. Note that if the duration does not fit in the time-window, the visit will not be assigned to any vehicle. It is good practice to always specify a `duration`. If you don't, the engine will not return estimated arrival times for each visit. [block:callout] { "type": "info", "title": "Pro tip:", "body": "The duration parameter may be used as a buffer parameter to accommodate for real-life delays such as parking and traffic lights, and thus avoid arriving late at a location. The only drawback of using too large a buffer, is that it leaves the algorithm less room to optimize.\n\nYou may also want to consider simulating slow **traffic**, see the [traffic](/docs/options) parameter below." } [/block] `load` is used when you want to account for the capacity of your vehicles. This capacity must be defined with your fleet as well, otherwise this parameter will be ignored. [block:callout] { "type": "info", "title": "Multiple loads & capacities", "body": "You may also specify multiple load parameters if you provide an object. This is useful if you define your load across multiple dimensions, for example weight and volume:\n\n```\n\"load\": { \n \"weight\": 10,\n \"volume\": 200\n}\n```\n\nThe entire load has to fit in the remaining vehicle capacity for it to be assigned. Now you can distinguish heavy goods that are small from large goods that are light :)\n\nAnother way to use multiple loads is to specify product-level details:\n\n```\n\"load\": {\n \"large_item\": 1,\n \"small_item\": 5,\n \"other_stuff\": 2\n}\n```\n\nNote that if you specify multiple loads, these loads need to correspond with the `capacity` parameter in the vehicle object. If not, they will be unserved with the message `\"The loads cannot fit in any vehicle.\"`" } [/block] `type` is an optional parameter if you want to restrict a visit so it can only be served by a particular type of vehicle. The value of this parameter can be a String or an Array of Strings for multiple types. For example, if a visit is of type `["A","B"]` it can be served by a vehicle of type `"A"` or `"B"`. If none of the vehicles match the type, it will be unserved. Visits without any type parameters can be served by vehicles with or without a type associated with it. `priority` allows you to make certain visits a priority over others. In some cases you have more visits than you can serve, resulting in a few unserved. But if you want to make sure your high priority visits take precedence, use this parameter and set it to `"high"`. For more control, you can also specify a priority number between 1 and 10,000. Visits with a higher priority number will take precedence over the lower priority visits. So if you have a visit (A) that has a priority level of 10 and is far away, and 3 other visits (B, C, D) with priority level 5 that are close by, then in a situation where you can feasibly visit *either* A *or* (B + C + D), the solution Routific will return is the latter, because the total combined priority score is 15. If instead you wanted visit A to be served while discarding B, C, and D, then you'll need to increase the priority number for A. Just for reference: "low" corresponds to 1, regular is 5, whereas "high" maps to 10. [block:callout] { "type": "info", "title": "Second time-window", "body": "You can also specify two time-windows using the `time_windows` parameter instead of `start` and `end`. This is especially useful if you need to avoid delivery between a certain time. For example, the delivery should happen between 9:00-12:00 OR between 13:30-18:00.\n\nYou can specify this as follows: \n\n```\n\"time_windows\": [\n {\n \"start\": \"09:00\",\n \"end\": \"12:00\"\n },\n {\n \"start\": \"13:30\",\n \"end\": \"18:00\"\n }\n ]\n```\n\nNote that the `time_windows` array needs to be in chronological order." } [/block] If you want to send notes to a driver for a given visit (e.g. the number of packages in an order or delivery instructions), you can add add a `notes` parameter to the visits object. These notes will be preserved in the json returned by the Routing Engine and will be displayed on our web and driver apps if you have an API integration enabled with Routific. [block:callout] { "type": "success", "title": "Custom notes (new)", "body": "If you want to add additional information such as weight or price to a visit, you can also create a custom notes parameter and add it to the `visits` object. Just as with the `notes` parameter, this information will be shown on our web and driver apps if you have an API integration with Routific (Contact [support](mailto:support@routific.com) if you want to enable an API integration).\n\n```\n\"customNotes\": {\n \"weight\": \"100 kg\",\n \"price\": \"$50\"\n}\n```" } [/block]
{"_id":"5b2c2fa8f4eae600035b7174","category":"5b2c2fa8f4eae600035b7168","project":"546559525871e90800f503c0","user":"5465590bf42a472000b0c6b7","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":["5597129646e90a0d00eb6a4b","565e1138009b3019007c7436"],"next":{"pages":[],"description":""},"createdAt":"2015-05-26T01:47:21.123Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"language":"json","code":"{}","name":"","status":200},{"name":"","status":400,"language":"json","code":"{}"}]},"settings":"","auth":"never","params":[],"url":""},"isReference":false,"order":1,"body":"The **fleet** consists of your drivers. Each driver is defined by their `start_location` and (optionally) an `end_location`.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\\"fleet\\\": {\\n  \\\"driver_1\\\": {\\n    \\\"start_location\\\": {\\n      \\\"id\\\": \\\"depot\\\",\\n      \\\"name\\\": \\\"800 Kingsway\\\",\\n      \\\"lat\\\": 49.2553636,\\n      \\\"lng\\\": -123.0873365\\n    },\\n    \\\"end_location\\\": {\\n      \\\"id\\\": \\\"depot\\\",\\n      \\\"name\\\": \\\"800 Kingsway\\\",\\n      \\\"lat\\\": 49.2553636,\\n      \\\"lng\\\": -123.0873365\\n    },\\n    \\\"shift_start\\\": \\\"8:00\\\",\\n    \\\"shift_end\\\": \\\"17:00\\\",\\n    \\\"min_visits\\\": 14,\\n    \\\"capacity\\\": 10,\\n    \\\"type\\\": [\\\"A\\\", \\\"B\\\"],\\n    \\\"strict_start\\\": true,\\n    \\\"breaks\\\" : [\\n      {\\n        \\\"id\\\": \\\"lunch\\\",\\n        \\\"start\\\": \\\"12:00\\\",\\n        \\\"end\\\": \\\"13:00\\\"\\n      },\\n      {\\n        \\\"id\\\": \\\"client call\\\",\\n        \\\"start\\\": \\\"15:00\\\",\\n        \\\"end\\\": \\\"15:30\\\",\\n        \\\"in_transit\\\": true\\n      }\\n    ]\\n  },\\n  \\\"driver_2\\\": {\\n    \\\"start_location\\\": {\\n      \\\"id\\\": \\\"depot\\\",\\n      \\\"name\\\": \\\"800 Kingsway\\\",\\n      \\\"lat\\\": 49.2553636,\\n      \\\"lng\\\": -123.0873365\\n    },\\n    \\\"end_location\\\": {\\n      \\\"id\\\": \\\"depot\\\",\\n      \\\"name\\\": \\\"800 Kingsway\\\",\\n      \\\"lat\\\": 49.2553636,\\n      \\\"lng\\\": -123.0873365\\n    },\\n    \\\"shift_start\\\": \\\"8:00\\\",\\n    \\\"shift_end\\\": \\\"17:00\\\",\\n    \\\"capacity\\\": 5\\n  }\\n}\",\n      \"language\": \"json\"\n    }\n  ],\n  \"sidebar\": true\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"PROPERTY\",\n    \"h-1\": \"TYPE\",\n    \"h-2\": \"REQUIRED\",\n    \"0-0\": \"start_location\",\n    \"0-1\": \"Location object\",\n    \"0-2\": \"required\",\n    \"1-0\": \"end_location\",\n    \"1-1\": \"Location object\",\n    \"1-2\": \"optional\",\n    \"2-0\": \"shift_start\",\n    \"2-1\": \"String (\\\"hh:mm\\\")\",\n    \"2-2\": \"optional\",\n    \"3-0\": \"shift_end\",\n    \"3-1\": \"String (\\\"hh:mm\\\")\",\n    \"3-2\": \"optional\",\n    \"4-0\": \"capacity\",\n    \"4-1\": \"Number (any unit)\",\n    \"4-2\": \"optional\",\n    \"5-0\": \"type\",\n    \"5-1\": \"String or Array\",\n    \"5-2\": \"optional\",\n    \"6-0\": \"speed\",\n    \"6-1\": \"String(faster, fast, normal(default), slow, very slow, bike) or Number\",\n    \"6-2\": \"optional\",\n    \"7-0\": \"strict_start\",\n    \"7-1\": \"Boolean\",\n    \"7-2\": \"optional\",\n    \"8-0\": \"min_visits\",\n    \"8-1\": \"Number\",\n    \"8-2\": \"optional\",\n    \"9-0\": \"breaks\",\n    \"9-1\": \"Array of Objects\",\n    \"9-2\": \"optional\"\n  },\n  \"cols\": 3,\n  \"rows\": 10\n}\n[/block]\nThe end-location is optional and may be omitted. It may be useful in cases to have [open-ended routes](/docs/without-returning-to-depot) in some situations.\n\n`shift_start` and `shift_end` specify when the driver starts driving and when he/she needs to be finished. If you have an `end_location`, then the `shift_end` means the latest time that the driver has to arrive there; otherwise it is the latest time that the driver can do their last job. Both parameters are optional. Without a `shift_start`, the algorithm will automatically infer the best time to depart, depending on your visits' time-windows.\n\n`capacity` is an optional parameter to define the total capacity that can fit in the vehicle (using the same unit as the `load` for your visits). The algorithm will make sure that this capacity will not be exceeded.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Capacity + loads\",\n  \"body\": \"In order to use the capacity constraint, make sure that you also define the `load` parameters on the visits. If loads are not set, it is assumed that the visit does not take up any room in the capacity of the fleet.\\n\\nIf you'd like to use capacity as a limit of **x** number of orders, then use `load: 1` for each visit.\"\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Multiple capacities\",\n  \"body\": \"You may also specify multiple load and capacity parameters if you provide an object instead of a number. This is useful if you define your capacity across multiple dimensions, for example weight and volume:\\n\\n```\\n\\\"capacity\\\": { \\n  \\\"weight\\\": 1000,\\n  \\\"volume\\\": 200\\n}\\n```\\n\\nYou can specify your own dimensions as well. See `load` parameter on the [Visits](doc:input) section for more examples.\\n\\nNote that if you specify multiple capacities, for loads to fit, it has to fit across all dimensions. So if you have plenty of weight capacity left, but in terms of volume it's already full, then the load won't fit.\"\n}\n[/block]\nIf you are using type restrictions on your visits, make sure you also define the same types for your vehicles in the `type` parameter. This value can be either a String — depicting a single type — or an Array of Strings for multiple types. Vehicles without any type will still be able to serve the visits that have no type restrictions.\n\n`speed`: Not all your drivers are as experienced and may cruise the roads at different speeds. Use this parameter to specify the driver's speed. The default value for `speed` is **normal** or **1**. Each step increases or decreases the vehicle speed by **25%**, so for example **very slow** would describe a driver travelling at **50%** of a normal driver's speed. For more control over the speed, you can also pass in a (decimal) number from **0.1** to **2**. A speed of **0.1** would mean the vehicle is travelling at **10%** speed while **2** means the vehicle is travelling at twice the speed.  \n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"If your fleet consists of bikes, you may use `bike` as the `speed` parameter, which reduces the speed to **25%** of a normal vehicle.\"\n}\n[/block]\n`strict_start` is a flag to force the departure time of a driver to be at `shift_start`. By default this flag is set to `false`, which means that the algorithm will attempt to delay the departure of a driver, if it results in reduced `idle_time` along the route.\n\n`min_visits` is an optional parameter that allow you to specify a minimum number of visits that should be assigned to this vehicle. Specifying `min_visits` will override the global `min_visits_per_vehicle` parameter (see Options below). This is useful to balance the orders across your fleet when your drivers work different shift lengths.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"You can specify one or more breaks for your drivers. This could be a lunch break, some personal errand, or even a pre-scheduled call your driver needs to take while transiting. It basically allows you to block off parts of your shift; Routific will optimize your stops around it.\\n\\n`breaks` expects an array of objects. Each object requires an `id`, `start` and `end` times of the break, and you can optionally specify that the break can be taken `in_transit` – e.g. a call that you take in the car. Here's an example:\\n\\n```\\n\\\"breaks\\\" : [\\n      {\\n        \\\"id\\\": \\\"lunch\\\",\\n        \\\"start\\\": \\\"12:00\\\",\\n        \\\"end\\\": \\\"13:00\\\",\\n      },\\n      {\\n        \\\"id\\\": \\\"client call\\\",\\n        \\\"start\\\": \\\"15:00\\\",\\n        \\\"end\\\": \\\"15:30\\\",\\n        \\\"in_transit\\\": true\\n      }\\n    ]\\n```\\n\\nIn the solution, a break in your schedule is returned as follows:\\n\\n```\\n{\\n  id: \\\"lunch\\\",\\n  break: true,\\n  arrival_time: \\\"12:11\\\",\\n  finish_time: \\\"13:00\\\",\\n  start: \\\"12:30\\\",\\n  end: \\\"13:00\\\",\\n  in_transit: false\\n}\\n```\\n\\nNote: Driver breaks are not supported on our `/pdp` and `pdp-long` endpoints.\",\n  \"title\": \"Breaks\"\n}\n[/block]","excerpt":"","slug":"fleet","type":"basic","title":"Fleet","__v":0,"childrenPages":[]}

Fleet


The **fleet** consists of your drivers. Each driver is defined by their `start_location` and (optionally) an `end_location`. [block:code] { "codes": [ { "code": "\"fleet\": {\n \"driver_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"end_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"shift_start\": \"8:00\",\n \"shift_end\": \"17:00\",\n \"min_visits\": 14,\n \"capacity\": 10,\n \"type\": [\"A\", \"B\"],\n \"strict_start\": true,\n \"breaks\" : [\n {\n \"id\": \"lunch\",\n \"start\": \"12:00\",\n \"end\": \"13:00\"\n },\n {\n \"id\": \"client call\",\n \"start\": \"15:00\",\n \"end\": \"15:30\",\n \"in_transit\": true\n }\n ]\n },\n \"driver_2\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"end_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"shift_start\": \"8:00\",\n \"shift_end\": \"17:00\",\n \"capacity\": 5\n }\n}", "language": "json" } ], "sidebar": true } [/block] [block:parameters] { "data": { "h-0": "PROPERTY", "h-1": "TYPE", "h-2": "REQUIRED", "0-0": "start_location", "0-1": "Location object", "0-2": "required", "1-0": "end_location", "1-1": "Location object", "1-2": "optional", "2-0": "shift_start", "2-1": "String (\"hh:mm\")", "2-2": "optional", "3-0": "shift_end", "3-1": "String (\"hh:mm\")", "3-2": "optional", "4-0": "capacity", "4-1": "Number (any unit)", "4-2": "optional", "5-0": "type", "5-1": "String or Array", "5-2": "optional", "6-0": "speed", "6-1": "String(faster, fast, normal(default), slow, very slow, bike) or Number", "6-2": "optional", "7-0": "strict_start", "7-1": "Boolean", "7-2": "optional", "8-0": "min_visits", "8-1": "Number", "8-2": "optional", "9-0": "breaks", "9-1": "Array of Objects", "9-2": "optional" }, "cols": 3, "rows": 10 } [/block] The end-location is optional and may be omitted. It may be useful in cases to have [open-ended routes](/docs/without-returning-to-depot) in some situations. `shift_start` and `shift_end` specify when the driver starts driving and when he/she needs to be finished. If you have an `end_location`, then the `shift_end` means the latest time that the driver has to arrive there; otherwise it is the latest time that the driver can do their last job. Both parameters are optional. Without a `shift_start`, the algorithm will automatically infer the best time to depart, depending on your visits' time-windows. `capacity` is an optional parameter to define the total capacity that can fit in the vehicle (using the same unit as the `load` for your visits). The algorithm will make sure that this capacity will not be exceeded. [block:callout] { "type": "info", "title": "Capacity + loads", "body": "In order to use the capacity constraint, make sure that you also define the `load` parameters on the visits. If loads are not set, it is assumed that the visit does not take up any room in the capacity of the fleet.\n\nIf you'd like to use capacity as a limit of **x** number of orders, then use `load: 1` for each visit." } [/block] [block:callout] { "type": "info", "title": "Multiple capacities", "body": "You may also specify multiple load and capacity parameters if you provide an object instead of a number. This is useful if you define your capacity across multiple dimensions, for example weight and volume:\n\n```\n\"capacity\": { \n \"weight\": 1000,\n \"volume\": 200\n}\n```\n\nYou can specify your own dimensions as well. See `load` parameter on the [Visits](doc:input) section for more examples.\n\nNote that if you specify multiple capacities, for loads to fit, it has to fit across all dimensions. So if you have plenty of weight capacity left, but in terms of volume it's already full, then the load won't fit." } [/block] If you are using type restrictions on your visits, make sure you also define the same types for your vehicles in the `type` parameter. This value can be either a String — depicting a single type — or an Array of Strings for multiple types. Vehicles without any type will still be able to serve the visits that have no type restrictions. `speed`: Not all your drivers are as experienced and may cruise the roads at different speeds. Use this parameter to specify the driver's speed. The default value for `speed` is **normal** or **1**. Each step increases or decreases the vehicle speed by **25%**, so for example **very slow** would describe a driver travelling at **50%** of a normal driver's speed. For more control over the speed, you can also pass in a (decimal) number from **0.1** to **2**. A speed of **0.1** would mean the vehicle is travelling at **10%** speed while **2** means the vehicle is travelling at twice the speed. [block:callout] { "type": "info", "body": "If your fleet consists of bikes, you may use `bike` as the `speed` parameter, which reduces the speed to **25%** of a normal vehicle." } [/block] `strict_start` is a flag to force the departure time of a driver to be at `shift_start`. By default this flag is set to `false`, which means that the algorithm will attempt to delay the departure of a driver, if it results in reduced `idle_time` along the route. `min_visits` is an optional parameter that allow you to specify a minimum number of visits that should be assigned to this vehicle. Specifying `min_visits` will override the global `min_visits_per_vehicle` parameter (see Options below). This is useful to balance the orders across your fleet when your drivers work different shift lengths. [block:callout] { "type": "info", "body": "You can specify one or more breaks for your drivers. This could be a lunch break, some personal errand, or even a pre-scheduled call your driver needs to take while transiting. It basically allows you to block off parts of your shift; Routific will optimize your stops around it.\n\n`breaks` expects an array of objects. Each object requires an `id`, `start` and `end` times of the break, and you can optionally specify that the break can be taken `in_transit` – e.g. a call that you take in the car. Here's an example:\n\n```\n\"breaks\" : [\n {\n \"id\": \"lunch\",\n \"start\": \"12:00\",\n \"end\": \"13:00\",\n },\n {\n \"id\": \"client call\",\n \"start\": \"15:00\",\n \"end\": \"15:30\",\n \"in_transit\": true\n }\n ]\n```\n\nIn the solution, a break in your schedule is returned as follows:\n\n```\n{\n id: \"lunch\",\n break: true,\n arrival_time: \"12:11\",\n finish_time: \"13:00\",\n start: \"12:30\",\n end: \"13:00\",\n in_transit: false\n}\n```\n\nNote: Driver breaks are not supported on our `/pdp` and `pdp-long` endpoints.", "title": "Breaks" } [/block]
The **fleet** consists of your drivers. Each driver is defined by their `start_location` and (optionally) an `end_location`. [block:code] { "codes": [ { "code": "\"fleet\": {\n \"driver_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"end_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"shift_start\": \"8:00\",\n \"shift_end\": \"17:00\",\n \"min_visits\": 14,\n \"capacity\": 10,\n \"type\": [\"A\", \"B\"],\n \"strict_start\": true,\n \"breaks\" : [\n {\n \"id\": \"lunch\",\n \"start\": \"12:00\",\n \"end\": \"13:00\"\n },\n {\n \"id\": \"client call\",\n \"start\": \"15:00\",\n \"end\": \"15:30\",\n \"in_transit\": true\n }\n ]\n },\n \"driver_2\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"end_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"shift_start\": \"8:00\",\n \"shift_end\": \"17:00\",\n \"capacity\": 5\n }\n}", "language": "json" } ], "sidebar": true } [/block] [block:parameters] { "data": { "h-0": "PROPERTY", "h-1": "TYPE", "h-2": "REQUIRED", "0-0": "start_location", "0-1": "Location object", "0-2": "required", "1-0": "end_location", "1-1": "Location object", "1-2": "optional", "2-0": "shift_start", "2-1": "String (\"hh:mm\")", "2-2": "optional", "3-0": "shift_end", "3-1": "String (\"hh:mm\")", "3-2": "optional", "4-0": "capacity", "4-1": "Number (any unit)", "4-2": "optional", "5-0": "type", "5-1": "String or Array", "5-2": "optional", "6-0": "speed", "6-1": "String(faster, fast, normal(default), slow, very slow, bike) or Number", "6-2": "optional", "7-0": "strict_start", "7-1": "Boolean", "7-2": "optional", "8-0": "min_visits", "8-1": "Number", "8-2": "optional", "9-0": "breaks", "9-1": "Array of Objects", "9-2": "optional" }, "cols": 3, "rows": 10 } [/block] The end-location is optional and may be omitted. It may be useful in cases to have [open-ended routes](/docs/without-returning-to-depot) in some situations. `shift_start` and `shift_end` specify when the driver starts driving and when he/she needs to be finished. If you have an `end_location`, then the `shift_end` means the latest time that the driver has to arrive there; otherwise it is the latest time that the driver can do their last job. Both parameters are optional. Without a `shift_start`, the algorithm will automatically infer the best time to depart, depending on your visits' time-windows. `capacity` is an optional parameter to define the total capacity that can fit in the vehicle (using the same unit as the `load` for your visits). The algorithm will make sure that this capacity will not be exceeded. [block:callout] { "type": "info", "title": "Capacity + loads", "body": "In order to use the capacity constraint, make sure that you also define the `load` parameters on the visits. If loads are not set, it is assumed that the visit does not take up any room in the capacity of the fleet.\n\nIf you'd like to use capacity as a limit of **x** number of orders, then use `load: 1` for each visit." } [/block] [block:callout] { "type": "info", "title": "Multiple capacities", "body": "You may also specify multiple load and capacity parameters if you provide an object instead of a number. This is useful if you define your capacity across multiple dimensions, for example weight and volume:\n\n```\n\"capacity\": { \n \"weight\": 1000,\n \"volume\": 200\n}\n```\n\nYou can specify your own dimensions as well. See `load` parameter on the [Visits](doc:input) section for more examples.\n\nNote that if you specify multiple capacities, for loads to fit, it has to fit across all dimensions. So if you have plenty of weight capacity left, but in terms of volume it's already full, then the load won't fit." } [/block] If you are using type restrictions on your visits, make sure you also define the same types for your vehicles in the `type` parameter. This value can be either a String — depicting a single type — or an Array of Strings for multiple types. Vehicles without any type will still be able to serve the visits that have no type restrictions. `speed`: Not all your drivers are as experienced and may cruise the roads at different speeds. Use this parameter to specify the driver's speed. The default value for `speed` is **normal** or **1**. Each step increases or decreases the vehicle speed by **25%**, so for example **very slow** would describe a driver travelling at **50%** of a normal driver's speed. For more control over the speed, you can also pass in a (decimal) number from **0.1** to **2**. A speed of **0.1** would mean the vehicle is travelling at **10%** speed while **2** means the vehicle is travelling at twice the speed. [block:callout] { "type": "info", "body": "If your fleet consists of bikes, you may use `bike` as the `speed` parameter, which reduces the speed to **25%** of a normal vehicle." } [/block] `strict_start` is a flag to force the departure time of a driver to be at `shift_start`. By default this flag is set to `false`, which means that the algorithm will attempt to delay the departure of a driver, if it results in reduced `idle_time` along the route. `min_visits` is an optional parameter that allow you to specify a minimum number of visits that should be assigned to this vehicle. Specifying `min_visits` will override the global `min_visits_per_vehicle` parameter (see Options below). This is useful to balance the orders across your fleet when your drivers work different shift lengths. [block:callout] { "type": "info", "body": "You can specify one or more breaks for your drivers. This could be a lunch break, some personal errand, or even a pre-scheduled call your driver needs to take while transiting. It basically allows you to block off parts of your shift; Routific will optimize your stops around it.\n\n`breaks` expects an array of objects. Each object requires an `id`, `start` and `end` times of the break, and you can optionally specify that the break can be taken `in_transit` – e.g. a call that you take in the car. Here's an example:\n\n```\n\"breaks\" : [\n {\n \"id\": \"lunch\",\n \"start\": \"12:00\",\n \"end\": \"13:00\",\n },\n {\n \"id\": \"client call\",\n \"start\": \"15:00\",\n \"end\": \"15:30\",\n \"in_transit\": true\n }\n ]\n```\n\nIn the solution, a break in your schedule is returned as follows:\n\n```\n{\n id: \"lunch\",\n break: true,\n arrival_time: \"12:11\",\n finish_time: \"13:00\",\n start: \"12:30\",\n end: \"13:00\",\n in_transit: false\n}\n```\n\nNote: Driver breaks are not supported on our `/pdp` and `pdp-long` endpoints.", "title": "Breaks" } [/block]
{"_id":"5b2c2fa8f4eae600035b7175","category":"5b2c2fa8f4eae600035b7168","project":"546559525871e90800f503c0","user":"5465590bf42a472000b0c6b7","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":[],"next":{"pages":[],"description":""},"createdAt":"2014-11-28T20:41:05.816Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"language":"json","code":"{}","name":"","status":200},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"never","params":[],"url":""},"isReference":false,"order":2,"body":"The options object belongs in the main request body and allows you to tweak how the Routing Engine runs.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\\"options\\\": {\\n   \\\"traffic\\\": \\\"slow\\\",\\n   \\\"min_visits_per_vehicle\\\": 5,\\n   \\\"balance\\\": true,\\n   \\\"min_vehicles\\\": true,\\n   \\\"shortest_distance\\\": true,\\n   \\\"squash_durations\\\": 1,\\n   \\\"max_vehicle_overtime\\\": 30,\\n   \\\"max_visit_lateness\\\": 15,\\n   \\\"polylines\\\": true\\n}\",\n      \"language\": \"json\"\n    }\n  ],\n  \"sidebar\": true\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"PROPERTY\",\n    \"h-1\": \"VALUE\",\n    \"h-2\": \"\",\n    \"0-0\": \"traffic\",\n    \"0-1\": \"String (faster(default), fast, normal, slow, very slow)\",\n    \"1-0\": \"min_visits_per_vehicle\",\n    \"1-1\": \"Number\",\n    \"2-0\": \"balance\",\n    \"2-1\": \"Boolean (beta)\",\n    \"4-0\": \"min_vehicles\",\n    \"4-1\": \"Boolean (defaults false)\",\n    \"5-0\": \"shortest_distance\",\n    \"5-1\": \"Boolean (defaults false)\",\n    \"6-0\": \"squash_durations\",\n    \"6-1\": \"Number\",\n    \"7-0\": \"max_vehicle_overtime\",\n    \"7-1\": \"Number\",\n    \"8-0\": \"max_visit_lateness\",\n    \"8-1\": \"Number\",\n    \"9-0\": \"polylines\",\n    \"9-1\": \"Boolean (defaults false)\",\n    \"3-0\": \"visit_balance_coefficient\",\n    \"3-1\": \"Number\"\n  },\n  \"cols\": 2,\n  \"rows\": 10\n}\n[/block]\n`traffic`: It's usually a good idea to simulate slower traffic to ensure you will never be late for a delivery. Estimated driving times tend to be more optimistic than in reality, and using this parameter will slow down driving speed. The default value is **faster**. Each step slows down the speed by 25%, so **fast** would be 25% slower from default, while **very slow** would be twice as slow.\n\n`min_visits_per_vehicle`: Routific will optimize your routes by finding the minimum total travel time. This may lead to some vehicles being assigned only a few visits or not being assigned at all. This may not always be desired because some businesses prefer to spread out visits/orders across all drivers. This parameter allows you to specify a minimum number of visits for each vehicle. Note that we expect an integer value greater than 0.\n\n`balance` (beta): If assigning equal number of orders across your vehicles is not enough and you want them to also have balanced driving shifts across your fleet, you can use this parameter. It *should* only be used in conjunction with `min_visits_per_vehicle`. This parameter will instruct the algorithm to keep the variance across driver shift times as small as possible.\n\n`visit_balance_coefficient`: Use this parameter (a number between 0.0 and 1.0) to adjust relative balance levels so that you have control over how balance is traded off with routing efficiency. 0.0 gives you a route solution that minimizes overall driving time while 1.0 gives you a completely balanced route at the expense of routing efficiency. This parameter cannot be used together with the `balance` and `min_visits_per_vehicle` parameters and will throw a `400: ERR_BALANCE_AND_MIN_VISITS_PER_VEHICLE_INCOMPATIBLE` error if this happens. Only available in v1.9 and up of `/vrp-long`.\n\n`min_vehicles`: Use this parameter if you are interested to minimize the number of vehicles you'd like to use to get all the jobs done. This allows you to figure out how many drivers you should call in. When using this parameter, make sure you provide ample vehicles in the input, so all the orders can be served. The idle vehicles will be empty in the solution.\n\n`shortest_distance`: By default we optimize by minimizing the total driving time and working hours. In some cases – due to time-windows – your drivers might have idle-time as it waits for the next time-window. By default we take this into account, which potentially could result in more miles driven, as we'd send the drive to another location first and coming back later. If you'd rather optimize purely on shortest distance, set this parameter to true.\n\n`squash_durations`: Useful when you have many stops at the same location, which could be an apartment complex. Normally, each stop has a duration value of let's say 10 minutes, which accounts for parking and finding the entrance. If you had 6 stops assigned to a driver at the same time, it doesn't take an hour in total! Use this parameter to squash the durations of each subsequent delivery at the same address. If you set it to 1, it will squash it to 1 minute, so the total duration for the above 6 stops would be 15 minutes.\n\n`polylines`: When setting this option to true Routific will respond with an encoded polyline representing each vehicle's route.  For more information on decoding the polylines refer to this [help article](https://academy.routific.com/api/display-route-results-on-your-own-map).\n\nUnless explicitly stated, all the options parameters listed here are supported on both the /vrp-long and /pdp-long endpoints.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Allow lateness and overtime\",\n  \"body\": \"Sometimes you want to be a little flexible with your time-window constraints. Normally, when you set time-window constraints, the Routific algorithm will consider them as hard requirements. Even if Routific thinks you'll be 1 minute late, it will return it in the `unserved` object. \\n\\nIf you need to schedule all your stops, and cannot afford any unserved – even if it means being late or working your drivers overtime – then you can use these two options parameters:\\n\\n`max_vehicle_overtime`: This sets the maximum number of minutes a driver is allowed to work overtime. Note that if all stops can be served within a normal shift, that will always be preferred.\\n\\n`max_visit_lateness`: This sets the maximum number of minutes you can be late for any of your stops. We only schedule something late if it is going to be unserved otherwise. Also note that the algorithm will minimize and spread out lateness as much as possible; the algorithm favors 5 orders being late by 2 minutes over 1 order being late by 10 minutes.\\n\\nWhen you use these options, the output in the response will include new fields:\\n\\n```\\n{\\n  ...,\\n  \\\"total_visit_lateness\\\": <minutes>,\\n  \\\"num_late_visits\\\": <number>,\\n  \\\"total_overtime\\\": <minutes>,\\n  \\\"vehicle_overtime\\\": {\\n    \\\"vehicle1\\\": <minutes>,\\n    \\\"vehicle2\\\": <minutes>\\n  },\\n  \\\"solution\\\": {\\n    \\\"vehicle1\\\": [\\n      ...\\n      {\\n        \\\"location_id\\\": \\\"visit1\\\",\\n        \\\"too_late\\\": true,\\n        \\\"late_by\\\": <minutes>\\n      },\\n      ...,\\n      }\\n    ]\\n  }\\n}\\n```\\n\\nThere are 4 new fields in the response: \\n\\n- `total_visit_lateness` indicates the actual total number of minutes the solution is violating the time-windows\\n- `num_late_visits` is the count of visits that have been scheduled late\\n- `total_overtime` is the total number of minutes your drivers are working overtime\\n- `vehicle_overtime` is an object that shows a break-down of the number of minutes each driver is working overtime\\n- In the actual solution object, on the stops that are late, we'll return the number of minutes it was `late_by`.\"\n}\n[/block]","excerpt":"Tweak the engine","slug":"options","type":"basic","title":"Options","__v":0,"childrenPages":[]}

Options

Tweak the engine

The options object belongs in the main request body and allows you to tweak how the Routing Engine runs. [block:code] { "codes": [ { "code": "\"options\": {\n \"traffic\": \"slow\",\n \"min_visits_per_vehicle\": 5,\n \"balance\": true,\n \"min_vehicles\": true,\n \"shortest_distance\": true,\n \"squash_durations\": 1,\n \"max_vehicle_overtime\": 30,\n \"max_visit_lateness\": 15,\n \"polylines\": true\n}", "language": "json" } ], "sidebar": true } [/block] [block:parameters] { "data": { "h-0": "PROPERTY", "h-1": "VALUE", "h-2": "", "0-0": "traffic", "0-1": "String (faster(default), fast, normal, slow, very slow)", "1-0": "min_visits_per_vehicle", "1-1": "Number", "2-0": "balance", "2-1": "Boolean (beta)", "4-0": "min_vehicles", "4-1": "Boolean (defaults false)", "5-0": "shortest_distance", "5-1": "Boolean (defaults false)", "6-0": "squash_durations", "6-1": "Number", "7-0": "max_vehicle_overtime", "7-1": "Number", "8-0": "max_visit_lateness", "8-1": "Number", "9-0": "polylines", "9-1": "Boolean (defaults false)", "3-0": "visit_balance_coefficient", "3-1": "Number" }, "cols": 2, "rows": 10 } [/block] `traffic`: It's usually a good idea to simulate slower traffic to ensure you will never be late for a delivery. Estimated driving times tend to be more optimistic than in reality, and using this parameter will slow down driving speed. The default value is **faster**. Each step slows down the speed by 25%, so **fast** would be 25% slower from default, while **very slow** would be twice as slow. `min_visits_per_vehicle`: Routific will optimize your routes by finding the minimum total travel time. This may lead to some vehicles being assigned only a few visits or not being assigned at all. This may not always be desired because some businesses prefer to spread out visits/orders across all drivers. This parameter allows you to specify a minimum number of visits for each vehicle. Note that we expect an integer value greater than 0. `balance` (beta): If assigning equal number of orders across your vehicles is not enough and you want them to also have balanced driving shifts across your fleet, you can use this parameter. It *should* only be used in conjunction with `min_visits_per_vehicle`. This parameter will instruct the algorithm to keep the variance across driver shift times as small as possible. `visit_balance_coefficient`: Use this parameter (a number between 0.0 and 1.0) to adjust relative balance levels so that you have control over how balance is traded off with routing efficiency. 0.0 gives you a route solution that minimizes overall driving time while 1.0 gives you a completely balanced route at the expense of routing efficiency. This parameter cannot be used together with the `balance` and `min_visits_per_vehicle` parameters and will throw a `400: ERR_BALANCE_AND_MIN_VISITS_PER_VEHICLE_INCOMPATIBLE` error if this happens. Only available in v1.9 and up of `/vrp-long`. `min_vehicles`: Use this parameter if you are interested to minimize the number of vehicles you'd like to use to get all the jobs done. This allows you to figure out how many drivers you should call in. When using this parameter, make sure you provide ample vehicles in the input, so all the orders can be served. The idle vehicles will be empty in the solution. `shortest_distance`: By default we optimize by minimizing the total driving time and working hours. In some cases – due to time-windows – your drivers might have idle-time as it waits for the next time-window. By default we take this into account, which potentially could result in more miles driven, as we'd send the drive to another location first and coming back later. If you'd rather optimize purely on shortest distance, set this parameter to true. `squash_durations`: Useful when you have many stops at the same location, which could be an apartment complex. Normally, each stop has a duration value of let's say 10 minutes, which accounts for parking and finding the entrance. If you had 6 stops assigned to a driver at the same time, it doesn't take an hour in total! Use this parameter to squash the durations of each subsequent delivery at the same address. If you set it to 1, it will squash it to 1 minute, so the total duration for the above 6 stops would be 15 minutes. `polylines`: When setting this option to true Routific will respond with an encoded polyline representing each vehicle's route. For more information on decoding the polylines refer to this [help article](https://academy.routific.com/api/display-route-results-on-your-own-map). Unless explicitly stated, all the options parameters listed here are supported on both the /vrp-long and /pdp-long endpoints. [block:callout] { "type": "info", "title": "Allow lateness and overtime", "body": "Sometimes you want to be a little flexible with your time-window constraints. Normally, when you set time-window constraints, the Routific algorithm will consider them as hard requirements. Even if Routific thinks you'll be 1 minute late, it will return it in the `unserved` object. \n\nIf you need to schedule all your stops, and cannot afford any unserved – even if it means being late or working your drivers overtime – then you can use these two options parameters:\n\n`max_vehicle_overtime`: This sets the maximum number of minutes a driver is allowed to work overtime. Note that if all stops can be served within a normal shift, that will always be preferred.\n\n`max_visit_lateness`: This sets the maximum number of minutes you can be late for any of your stops. We only schedule something late if it is going to be unserved otherwise. Also note that the algorithm will minimize and spread out lateness as much as possible; the algorithm favors 5 orders being late by 2 minutes over 1 order being late by 10 minutes.\n\nWhen you use these options, the output in the response will include new fields:\n\n```\n{\n ...,\n \"total_visit_lateness\": <minutes>,\n \"num_late_visits\": <number>,\n \"total_overtime\": <minutes>,\n \"vehicle_overtime\": {\n \"vehicle1\": <minutes>,\n \"vehicle2\": <minutes>\n },\n \"solution\": {\n \"vehicle1\": [\n ...\n {\n \"location_id\": \"visit1\",\n \"too_late\": true,\n \"late_by\": <minutes>\n },\n ...,\n }\n ]\n }\n}\n```\n\nThere are 4 new fields in the response: \n\n- `total_visit_lateness` indicates the actual total number of minutes the solution is violating the time-windows\n- `num_late_visits` is the count of visits that have been scheduled late\n- `total_overtime` is the total number of minutes your drivers are working overtime\n- `vehicle_overtime` is an object that shows a break-down of the number of minutes each driver is working overtime\n- In the actual solution object, on the stops that are late, we'll return the number of minutes it was `late_by`." } [/block]
The options object belongs in the main request body and allows you to tweak how the Routing Engine runs. [block:code] { "codes": [ { "code": "\"options\": {\n \"traffic\": \"slow\",\n \"min_visits_per_vehicle\": 5,\n \"balance\": true,\n \"min_vehicles\": true,\n \"shortest_distance\": true,\n \"squash_durations\": 1,\n \"max_vehicle_overtime\": 30,\n \"max_visit_lateness\": 15,\n \"polylines\": true\n}", "language": "json" } ], "sidebar": true } [/block] [block:parameters] { "data": { "h-0": "PROPERTY", "h-1": "VALUE", "h-2": "", "0-0": "traffic", "0-1": "String (faster(default), fast, normal, slow, very slow)", "1-0": "min_visits_per_vehicle", "1-1": "Number", "2-0": "balance", "2-1": "Boolean (beta)", "4-0": "min_vehicles", "4-1": "Boolean (defaults false)", "5-0": "shortest_distance", "5-1": "Boolean (defaults false)", "6-0": "squash_durations", "6-1": "Number", "7-0": "max_vehicle_overtime", "7-1": "Number", "8-0": "max_visit_lateness", "8-1": "Number", "9-0": "polylines", "9-1": "Boolean (defaults false)", "3-0": "visit_balance_coefficient", "3-1": "Number" }, "cols": 2, "rows": 10 } [/block] `traffic`: It's usually a good idea to simulate slower traffic to ensure you will never be late for a delivery. Estimated driving times tend to be more optimistic than in reality, and using this parameter will slow down driving speed. The default value is **faster**. Each step slows down the speed by 25%, so **fast** would be 25% slower from default, while **very slow** would be twice as slow. `min_visits_per_vehicle`: Routific will optimize your routes by finding the minimum total travel time. This may lead to some vehicles being assigned only a few visits or not being assigned at all. This may not always be desired because some businesses prefer to spread out visits/orders across all drivers. This parameter allows you to specify a minimum number of visits for each vehicle. Note that we expect an integer value greater than 0. `balance` (beta): If assigning equal number of orders across your vehicles is not enough and you want them to also have balanced driving shifts across your fleet, you can use this parameter. It *should* only be used in conjunction with `min_visits_per_vehicle`. This parameter will instruct the algorithm to keep the variance across driver shift times as small as possible. `visit_balance_coefficient`: Use this parameter (a number between 0.0 and 1.0) to adjust relative balance levels so that you have control over how balance is traded off with routing efficiency. 0.0 gives you a route solution that minimizes overall driving time while 1.0 gives you a completely balanced route at the expense of routing efficiency. This parameter cannot be used together with the `balance` and `min_visits_per_vehicle` parameters and will throw a `400: ERR_BALANCE_AND_MIN_VISITS_PER_VEHICLE_INCOMPATIBLE` error if this happens. Only available in v1.9 and up of `/vrp-long`. `min_vehicles`: Use this parameter if you are interested to minimize the number of vehicles you'd like to use to get all the jobs done. This allows you to figure out how many drivers you should call in. When using this parameter, make sure you provide ample vehicles in the input, so all the orders can be served. The idle vehicles will be empty in the solution. `shortest_distance`: By default we optimize by minimizing the total driving time and working hours. In some cases – due to time-windows – your drivers might have idle-time as it waits for the next time-window. By default we take this into account, which potentially could result in more miles driven, as we'd send the drive to another location first and coming back later. If you'd rather optimize purely on shortest distance, set this parameter to true. `squash_durations`: Useful when you have many stops at the same location, which could be an apartment complex. Normally, each stop has a duration value of let's say 10 minutes, which accounts for parking and finding the entrance. If you had 6 stops assigned to a driver at the same time, it doesn't take an hour in total! Use this parameter to squash the durations of each subsequent delivery at the same address. If you set it to 1, it will squash it to 1 minute, so the total duration for the above 6 stops would be 15 minutes. `polylines`: When setting this option to true Routific will respond with an encoded polyline representing each vehicle's route. For more information on decoding the polylines refer to this [help article](https://academy.routific.com/api/display-route-results-on-your-own-map). Unless explicitly stated, all the options parameters listed here are supported on both the /vrp-long and /pdp-long endpoints. [block:callout] { "type": "info", "title": "Allow lateness and overtime", "body": "Sometimes you want to be a little flexible with your time-window constraints. Normally, when you set time-window constraints, the Routific algorithm will consider them as hard requirements. Even if Routific thinks you'll be 1 minute late, it will return it in the `unserved` object. \n\nIf you need to schedule all your stops, and cannot afford any unserved – even if it means being late or working your drivers overtime – then you can use these two options parameters:\n\n`max_vehicle_overtime`: This sets the maximum number of minutes a driver is allowed to work overtime. Note that if all stops can be served within a normal shift, that will always be preferred.\n\n`max_visit_lateness`: This sets the maximum number of minutes you can be late for any of your stops. We only schedule something late if it is going to be unserved otherwise. Also note that the algorithm will minimize and spread out lateness as much as possible; the algorithm favors 5 orders being late by 2 minutes over 1 order being late by 10 minutes.\n\nWhen you use these options, the output in the response will include new fields:\n\n```\n{\n ...,\n \"total_visit_lateness\": <minutes>,\n \"num_late_visits\": <number>,\n \"total_overtime\": <minutes>,\n \"vehicle_overtime\": {\n \"vehicle1\": <minutes>,\n \"vehicle2\": <minutes>\n },\n \"solution\": {\n \"vehicle1\": [\n ...\n {\n \"location_id\": \"visit1\",\n \"too_late\": true,\n \"late_by\": <minutes>\n },\n ...,\n }\n ]\n }\n}\n```\n\nThere are 4 new fields in the response: \n\n- `total_visit_lateness` indicates the actual total number of minutes the solution is violating the time-windows\n- `num_late_visits` is the count of visits that have been scheduled late\n- `total_overtime` is the total number of minutes your drivers are working overtime\n- `vehicle_overtime` is an object that shows a break-down of the number of minutes each driver is working overtime\n- In the actual solution object, on the stops that are late, we'll return the number of minutes it was `late_by`." } [/block]
{"_id":"5b2c2fa8f4eae600035b717a","category":"5b2c2fa8f4eae600035b7169","project":"546559525871e90800f503c0","user":"5465590bf42a472000b0c6b7","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":[],"next":{"pages":[],"description":""},"createdAt":"2014-11-28T20:38:58.637Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"never","params":[],"url":""},"isReference":false,"order":0,"body":"The output is a schedule, where each of the visits are optimally allocated across the available vehicles. Estimated arrival and finishing times are given for each location. Note that the arrival time at the first location basically means the departure time from the depot.\n\nAn example response can be found in the side bar.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  \\\"status\\\": \\\"success\\\",\\n  \\\"total_travel_time\\\": 31.983334,\\n  \\\"total_idle_time\\\": 0,\\n  \\\"num_unserved\\\": 0,\\n  \\\"unserved\\\": null,\\n  \\\"solution\\\": {\\n    \\\"vehicle_1\\\": [\\n      {\\n        \\\"location_id\\\": \\\"depot\\\",\\n        \\\"location_name\\\": \\\"800 Kingsway\\\",\\n        \\\"arrival_time\\\": \\\"08:00\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_3\\\",\\n        \\\"location_name\\\": \\\"800 Robson\\\",\\n        \\\"arrival_time\\\": \\\"08:10\\\",\\n        \\\"finish_time\\\": \\\"08:20\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_2\\\",\\n        \\\"location_name\\\": \\\"3780 Arbutus\\\",\\n        \\\"arrival_time\\\": \\\"08:29\\\",\\n        \\\"finish_time\\\": \\\"09:10\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_1\\\",\\n        \\\"location_name\\\": \\\"6800 Cambie\\\",\\n        \\\"arrival_time\\\": \\\"09:19\\\",\\n        \\\"finish_time\\\": \\\"09:29\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"depot\\\",\\n        \\\"location_name\\\": \\\"800 Kingsway\\\",\\n        \\\"arrival_time\\\": \\\"09:39\\\"\\n      }\\n    ]\\n  }\\n}\",\n      \"language\": \"json\"\n    }\n  ],\n  \"sidebar\": true\n}\n[/block]\nWhen there are too many visits — or the time windows are too tight — and the fleet cannot possibly visit all locations, some visits will be `unserved`. In other cases, a location could have been incorrectly geocoded and out of your region. Geocoding mistakes are common, since an address can be quite ambiguous at times. We will intelligently deduce your intended region based on your inputs, and return outliers as unserved.\n\nWe will return both those location IDs in `unserved` as follows in the API response:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n \\\"num_unserved\\\": 2,\\n \\\"unserved\\\": {\\n   \\\"order_1\\\": \\\"lat/lng coordinate is out of your region\\\",\\n   \\\"order_2\\\": \\\"cannot be visited within the constraints\\\"\\n }\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"PROPERTY\",\n    \"h-1\": \"TYPE\",\n    \"h-2\": \"NOTES\",\n    \"0-0\": \"status\",\n    \"0-1\": \"String\",\n    \"0-2\": \"A sanity check, will always be \\\"success\\\" when the HTTP code is 200.\",\n    \"1-0\": \"total_travel_time\",\n    \"2-0\": \"total_idle_time\",\n    \"3-0\": \"num_unserved\",\n    \"4-0\": \"unserved\",\n    \"5-0\": \"solution\",\n    \"1-1\": \"Number (minutes)\",\n    \"2-1\": \"Number (minutes)\",\n    \"3-1\": \"Number\",\n    \"4-1\": \"Object\",\n    \"5-1\": \"Object\",\n    \"1-2\": \"Total travel time of the entire fleet in minutes.\",\n    \"2-2\": \"Total number of minutes that the entire fleet in waiting idle.\",\n    \"3-2\": \"Number of visits that could not be scheduled.\",\n    \"4-2\": \"Visits that could not be scheduled, with their reasons.\",\n    \"5-2\": \"The optimized schedule, where the keys reference the vehicle IDs and the values are ordered arrays of visits (and estimated arrival and finish times).\"\n  },\n  \"cols\": 3,\n  \"rows\": 6\n}\n[/block]","excerpt":"","slug":"output","type":"basic","title":"API response","__v":0,"childrenPages":[]}

API response


The output is a schedule, where each of the visits are optimally allocated across the available vehicles. Estimated arrival and finishing times are given for each location. Note that the arrival time at the first location basically means the departure time from the depot. An example response can be found in the side bar. [block:code] { "codes": [ { "code": "{\n \"status\": \"success\",\n \"total_travel_time\": 31.983334,\n \"total_idle_time\": 0,\n \"num_unserved\": 0,\n \"unserved\": null,\n \"solution\": {\n \"vehicle_1\": [\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\",\n \"arrival_time\": \"08:00\"\n },\n {\n \"location_id\": \"order_3\",\n \"location_name\": \"800 Robson\",\n \"arrival_time\": \"08:10\",\n \"finish_time\": \"08:20\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"3780 Arbutus\",\n \"arrival_time\": \"08:29\",\n \"finish_time\": \"09:10\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"6800 Cambie\",\n \"arrival_time\": \"09:19\",\n \"finish_time\": \"09:29\"\n },\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\",\n \"arrival_time\": \"09:39\"\n }\n ]\n }\n}", "language": "json" } ], "sidebar": true } [/block] When there are too many visits — or the time windows are too tight — and the fleet cannot possibly visit all locations, some visits will be `unserved`. In other cases, a location could have been incorrectly geocoded and out of your region. Geocoding mistakes are common, since an address can be quite ambiguous at times. We will intelligently deduce your intended region based on your inputs, and return outliers as unserved. We will return both those location IDs in `unserved` as follows in the API response: [block:code] { "codes": [ { "code": "{\n \"num_unserved\": 2,\n \"unserved\": {\n \"order_1\": \"lat/lng coordinate is out of your region\",\n \"order_2\": \"cannot be visited within the constraints\"\n }\n}", "language": "json" } ] } [/block] [block:parameters] { "data": { "h-0": "PROPERTY", "h-1": "TYPE", "h-2": "NOTES", "0-0": "status", "0-1": "String", "0-2": "A sanity check, will always be \"success\" when the HTTP code is 200.", "1-0": "total_travel_time", "2-0": "total_idle_time", "3-0": "num_unserved", "4-0": "unserved", "5-0": "solution", "1-1": "Number (minutes)", "2-1": "Number (minutes)", "3-1": "Number", "4-1": "Object", "5-1": "Object", "1-2": "Total travel time of the entire fleet in minutes.", "2-2": "Total number of minutes that the entire fleet in waiting idle.", "3-2": "Number of visits that could not be scheduled.", "4-2": "Visits that could not be scheduled, with their reasons.", "5-2": "The optimized schedule, where the keys reference the vehicle IDs and the values are ordered arrays of visits (and estimated arrival and finish times)." }, "cols": 3, "rows": 6 } [/block]
The output is a schedule, where each of the visits are optimally allocated across the available vehicles. Estimated arrival and finishing times are given for each location. Note that the arrival time at the first location basically means the departure time from the depot. An example response can be found in the side bar. [block:code] { "codes": [ { "code": "{\n \"status\": \"success\",\n \"total_travel_time\": 31.983334,\n \"total_idle_time\": 0,\n \"num_unserved\": 0,\n \"unserved\": null,\n \"solution\": {\n \"vehicle_1\": [\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\",\n \"arrival_time\": \"08:00\"\n },\n {\n \"location_id\": \"order_3\",\n \"location_name\": \"800 Robson\",\n \"arrival_time\": \"08:10\",\n \"finish_time\": \"08:20\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"3780 Arbutus\",\n \"arrival_time\": \"08:29\",\n \"finish_time\": \"09:10\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"6800 Cambie\",\n \"arrival_time\": \"09:19\",\n \"finish_time\": \"09:29\"\n },\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\",\n \"arrival_time\": \"09:39\"\n }\n ]\n }\n}", "language": "json" } ], "sidebar": true } [/block] When there are too many visits — or the time windows are too tight — and the fleet cannot possibly visit all locations, some visits will be `unserved`. In other cases, a location could have been incorrectly geocoded and out of your region. Geocoding mistakes are common, since an address can be quite ambiguous at times. We will intelligently deduce your intended region based on your inputs, and return outliers as unserved. We will return both those location IDs in `unserved` as follows in the API response: [block:code] { "codes": [ { "code": "{\n \"num_unserved\": 2,\n \"unserved\": {\n \"order_1\": \"lat/lng coordinate is out of your region\",\n \"order_2\": \"cannot be visited within the constraints\"\n }\n}", "language": "json" } ] } [/block] [block:parameters] { "data": { "h-0": "PROPERTY", "h-1": "TYPE", "h-2": "NOTES", "0-0": "status", "0-1": "String", "0-2": "A sanity check, will always be \"success\" when the HTTP code is 200.", "1-0": "total_travel_time", "2-0": "total_idle_time", "3-0": "num_unserved", "4-0": "unserved", "5-0": "solution", "1-1": "Number (minutes)", "2-1": "Number (minutes)", "3-1": "Number", "4-1": "Object", "5-1": "Object", "1-2": "Total travel time of the entire fleet in minutes.", "2-2": "Total number of minutes that the entire fleet in waiting idle.", "3-2": "Number of visits that could not be scheduled.", "4-2": "Visits that could not be scheduled, with their reasons.", "5-2": "The optimized schedule, where the keys reference the vehicle IDs and the values are ordered arrays of visits (and estimated arrival and finish times)." }, "cols": 3, "rows": 6 } [/block]
{"_id":"5b2c2fa8f4eae600035b717b","category":"5b2c2fa8f4eae600035b7169","user":"5465590bf42a472000b0c6b7","project":"546559525871e90800f503c0","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":[],"next":{"pages":[],"description":""},"createdAt":"2014-11-28T20:39:28.338Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"settings":"","results":{"codes":[{"code":"{}","name":"","status":200,"language":"json"},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"never","params":[],"url":""},"isReference":false,"order":1,"body":"Successful requests return HTTP code `200`. In other cases, we will return an error code with a helpful message.\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"200\",\n    \"0-1\": \"Successful request\",\n    \"1-0\": \"400\",\n    \"1-1\": \"Input error, see the error message for details\",\n    \"2-0\": \"401\",\n    \"2-1\": \"Are you sending your API token in the request header?\",\n    \"4-0\": \"412\",\n    \"4-1\": \"No solution could be found. Please check your input? Usually due to incorrect time-windows.\",\n    \"5-0\": \"429\",\n    \"5-1\": \"Exceeding API usage? Is your problem size larger than your limit? You can increase your limits from your [dashboard](https://routific.com/developers/#/dashboard)\",\n    \"6-0\": \"500\",\n    \"6-1\": \"Sorry, our bad. Let us know what happened! We're at <a href=\\\"mailto:support@routific.com\\\">support@routific.com</a>\",\n    \"3-0\": \"408\",\n    \"3-1\": \"Request timeout. Your request was too large. Consider using [Long-running tasks](doc:vrp-long).\"\n  },\n  \"cols\": 2,\n  \"rows\": 7\n}\n[/block]","excerpt":"Something went wrong?","slug":"error-codes","type":"basic","title":"Error codes","__v":0,"childrenPages":[]}

Error codes

Something went wrong?

Successful requests return HTTP code `200`. In other cases, we will return an error code with a helpful message. [block:parameters] { "data": { "0-0": "200", "0-1": "Successful request", "1-0": "400", "1-1": "Input error, see the error message for details", "2-0": "401", "2-1": "Are you sending your API token in the request header?", "4-0": "412", "4-1": "No solution could be found. Please check your input? Usually due to incorrect time-windows.", "5-0": "429", "5-1": "Exceeding API usage? Is your problem size larger than your limit? You can increase your limits from your [dashboard](https://routific.com/developers/#/dashboard)", "6-0": "500", "6-1": "Sorry, our bad. Let us know what happened! We're at <a href=\"mailto:support@routific.com\">support@routific.com</a>", "3-0": "408", "3-1": "Request timeout. Your request was too large. Consider using [Long-running tasks](doc:vrp-long)." }, "cols": 2, "rows": 7 } [/block]
Successful requests return HTTP code `200`. In other cases, we will return an error code with a helpful message. [block:parameters] { "data": { "0-0": "200", "0-1": "Successful request", "1-0": "400", "1-1": "Input error, see the error message for details", "2-0": "401", "2-1": "Are you sending your API token in the request header?", "4-0": "412", "4-1": "No solution could be found. Please check your input? Usually due to incorrect time-windows.", "5-0": "429", "5-1": "Exceeding API usage? Is your problem size larger than your limit? You can increase your limits from your [dashboard](https://routific.com/developers/#/dashboard)", "6-0": "500", "6-1": "Sorry, our bad. Let us know what happened! We're at <a href=\"mailto:support@routific.com\">support@routific.com</a>", "3-0": "408", "3-1": "Request timeout. Your request was too large. Consider using [Long-running tasks](doc:vrp-long)." }, "cols": 2, "rows": 7 } [/block]
{"_id":"5b2c2fa8f4eae600035b717c","category":"5b2c2fa8f4eae600035b7169","project":"546559525871e90800f503c0","user":"5465590bf42a472000b0c6b7","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-08-08T21:47:31.927Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":2,"body":"There are two main reasons a visit may end up unserved: either it just can't fit (i.e. the problem might have too many constraints to accommodate every visit), or it's an input error (i.e. a visit may be incompatible in with every vehicle in the fleet). \n\nIn the first case, the reason will be returned as `cannot be visited within the constraints`. It basically means that we just couldn't fit it in. You can typically resolve this by either adding more vehicles, or extending the shift times, or increasing the capacities. It really depends on the situation; you might want to inspect the inputs of the visit that was unserved, and find out why it couldn't fit.\n\nIn the second case, where there is a clear reason why, we can be more helpful. As this is often due to a user input error, we provide special messages to assist the user in quickly identifying the unserved reason:\n\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Unserved reasons\",\n    \"h-1\": \"\",\n    \"0-0\": \"**The types do not match with any vehicle.** \",\n    \"0-1\": \"\",\n    \"1-0\": \"A visit may be of a type that none of the vehicles in the fleet can serve. This is often due to a misspelling. Can you make sure the type tags are exactly the same?\",\n    \"1-1\": \"\",\n    \"3-0\": \"A visit may have a load greater than the capacity of any vehicle in the fleet. It simply can't fit anywhere! You might need to buy a bigger truck. Or cut the load in pieces :)\",\n    \"3-1\": \"\",\n    \"4-0\": \"**No vehicle available during the specified time windows.** \",\n    \"4-1\": \"\",\n    \"5-0\": \"A visit may have a time window constraint that prevents any vehicle from being able to serve it. Note that we also take the duration into account. The overlap between the time window of the visit and the driver shift times (excluding breaks) should be at least as large as the duration – or else it won't fit.\\n\\nYou can avoid this situation by increasing the time windows. Note that using the *max_visit_lateness* and *max_vehicle_overtime* parameters in [Options](doc:options) might help as well.\",\n    \"5-1\": \"\",\n    \"9-0\": \"If all of your visits are incompatible, due to any of the reasons above, we will throw a 400 error instead. We already know that nothing is compatible, so we won't even try to run the routes. When you're using /vrp-long or /pdp-long this means that the job won't even get created.\",\n    \"8-0\": \"**Sorry, none of the stops can be scheduled. Please check your inputs and constraints.** \",\n    \"7-0\": \"What the message says. Check if your lat/lng coordinates make sense? Usually due to geocoding errors, which can be prevented if you clean up your addresses before geocoding.\",\n    \"6-0\": \"**The lat/lng is too far from the rest of the visits; likely a geocoding error?** \",\n    \"2-0\": \"**The load is too large for any vehicle.** \"\n  },\n  \"cols\": 1,\n  \"rows\": 10\n}\n[/block]","excerpt":"When things don't fit...","slug":"unserved-reasons","type":"basic","title":"Unserved reasons","__v":0,"childrenPages":[]}

Unserved reasons

When things don't fit...

There are two main reasons a visit may end up unserved: either it just can't fit (i.e. the problem might have too many constraints to accommodate every visit), or it's an input error (i.e. a visit may be incompatible in with every vehicle in the fleet). In the first case, the reason will be returned as `cannot be visited within the constraints`. It basically means that we just couldn't fit it in. You can typically resolve this by either adding more vehicles, or extending the shift times, or increasing the capacities. It really depends on the situation; you might want to inspect the inputs of the visit that was unserved, and find out why it couldn't fit. In the second case, where there is a clear reason why, we can be more helpful. As this is often due to a user input error, we provide special messages to assist the user in quickly identifying the unserved reason: [block:parameters] { "data": { "h-0": "Unserved reasons", "h-1": "", "0-0": "**The types do not match with any vehicle.** ", "0-1": "", "1-0": "A visit may be of a type that none of the vehicles in the fleet can serve. This is often due to a misspelling. Can you make sure the type tags are exactly the same?", "1-1": "", "3-0": "A visit may have a load greater than the capacity of any vehicle in the fleet. It simply can't fit anywhere! You might need to buy a bigger truck. Or cut the load in pieces :)", "3-1": "", "4-0": "**No vehicle available during the specified time windows.** ", "4-1": "", "5-0": "A visit may have a time window constraint that prevents any vehicle from being able to serve it. Note that we also take the duration into account. The overlap between the time window of the visit and the driver shift times (excluding breaks) should be at least as large as the duration – or else it won't fit.\n\nYou can avoid this situation by increasing the time windows. Note that using the *max_visit_lateness* and *max_vehicle_overtime* parameters in [Options](doc:options) might help as well.", "5-1": "", "9-0": "If all of your visits are incompatible, due to any of the reasons above, we will throw a 400 error instead. We already know that nothing is compatible, so we won't even try to run the routes. When you're using /vrp-long or /pdp-long this means that the job won't even get created.", "8-0": "**Sorry, none of the stops can be scheduled. Please check your inputs and constraints.** ", "7-0": "What the message says. Check if your lat/lng coordinates make sense? Usually due to geocoding errors, which can be prevented if you clean up your addresses before geocoding.", "6-0": "**The lat/lng is too far from the rest of the visits; likely a geocoding error?** ", "2-0": "**The load is too large for any vehicle.** " }, "cols": 1, "rows": 10 } [/block]
There are two main reasons a visit may end up unserved: either it just can't fit (i.e. the problem might have too many constraints to accommodate every visit), or it's an input error (i.e. a visit may be incompatible in with every vehicle in the fleet). In the first case, the reason will be returned as `cannot be visited within the constraints`. It basically means that we just couldn't fit it in. You can typically resolve this by either adding more vehicles, or extending the shift times, or increasing the capacities. It really depends on the situation; you might want to inspect the inputs of the visit that was unserved, and find out why it couldn't fit. In the second case, where there is a clear reason why, we can be more helpful. As this is often due to a user input error, we provide special messages to assist the user in quickly identifying the unserved reason: [block:parameters] { "data": { "h-0": "Unserved reasons", "h-1": "", "0-0": "**The types do not match with any vehicle.** ", "0-1": "", "1-0": "A visit may be of a type that none of the vehicles in the fleet can serve. This is often due to a misspelling. Can you make sure the type tags are exactly the same?", "1-1": "", "3-0": "A visit may have a load greater than the capacity of any vehicle in the fleet. It simply can't fit anywhere! You might need to buy a bigger truck. Or cut the load in pieces :)", "3-1": "", "4-0": "**No vehicle available during the specified time windows.** ", "4-1": "", "5-0": "A visit may have a time window constraint that prevents any vehicle from being able to serve it. Note that we also take the duration into account. The overlap between the time window of the visit and the driver shift times (excluding breaks) should be at least as large as the duration – or else it won't fit.\n\nYou can avoid this situation by increasing the time windows. Note that using the *max_visit_lateness* and *max_vehicle_overtime* parameters in [Options](doc:options) might help as well.", "5-1": "", "9-0": "If all of your visits are incompatible, due to any of the reasons above, we will throw a 400 error instead. We already know that nothing is compatible, so we won't even try to run the routes. When you're using /vrp-long or /pdp-long this means that the job won't even get created.", "8-0": "**Sorry, none of the stops can be scheduled. Please check your inputs and constraints.** ", "7-0": "What the message says. Check if your lat/lng coordinates make sense? Usually due to geocoding errors, which can be prevented if you clean up your addresses before geocoding.", "6-0": "**The lat/lng is too far from the rest of the visits; likely a geocoding error?** ", "2-0": "**The load is too large for any vehicle.** " }, "cols": 1, "rows": 10 } [/block]
{"_id":"5b2c2fa8f4eae600035b7176","category":"5b2c2fa8f4eae600035b716a","user":"5465590bf42a472000b0c6b7","project":"546559525871e90800f503c0","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":[],"next":{"pages":[],"description":""},"createdAt":"2014-11-26T01:55:38.306Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"never","params":[],"url":""},"isReference":false,"order":0,"body":"Time-windows and durations are optional. If you are only interested in the optimal route without considering time, you can just omit the parameters. On large-scale problems, this will result in tremendous performance improvements! Keep in mind that the response will not include ETA values.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  \\\"visits\\\": {\\n    \\\"order_1\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"6800 Cambie\\\",\\n        \\\"lat\\\": 49.227107,\\n        \\\"lng\\\": -123.1163085\\n      }\\n    },\\n    \\\"order_2\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"3780 Arbutus\\\",\\n        \\\"lat\\\": 49.2474624,\\n        \\\"lng\\\": -123.1532338\\n      }\\n    },\\n    \\\"order_3\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"800 Robson\\\",\\n        \\\"lat\\\": 49.2819229,\\n        \\\"lng\\\": -123.1211844\\n      }\\n    }\\n  },\\n  \\\"fleet\\\": {\\n    \\\"vehicle_1\\\": {\\n      \\\"start_location\\\": {\\n        \\\"id\\\": \\\"depot\\\",\\n        \\\"name\\\": \\\"800 Kingsway\\\",\\n        \\\"lat\\\": 49.2553636,\\n        \\\"lng\\\": -123.0873365\\n      },\\n      \\\"end_location\\\": {\\n        \\\"id\\\": \\\"depot\\\",\\n        \\\"name\\\": \\\"800 Kingsway\\\",\\n        \\\"lat\\\": 49.2553636,\\n        \\\"lng\\\": -123.0873365\\n      }\\n    }\\n  }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Input\"\n    },\n    {\n      \"code\": \"{\\n  \\\"status\\\": \\\"success\\\",\\n  \\\"total_travel_time\\\": 31.983334,\\n  \\\"total_idle_time\\\": 0,\\n  \\\"num_unserved\\\": 0,\\n  \\\"unserved\\\": null,\\n  \\\"solution\\\": {\\n    \\\"vehicle_1\\\": [\\n      {\\n        \\\"location_id\\\": \\\"depot\\\",\\n        \\\"location_name\\\": \\\"800 Kingsway\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_3\\\",\\n        \\\"location_name\\\": \\\"800 Robson\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_2\\\",\\n        \\\"location_name\\\": \\\"3780 Arbutus\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_1\\\",\\n        \\\"location_name\\\": \\\"6800 Cambie\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"depot\\\",\\n        \\\"location_name\\\": \\\"800 Kingsway\\\"\\n      }\\n    ]\\n  }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Output\"\n    }\n  ],\n  \"sidebar\": true\n}\n[/block]","excerpt":"The simplest form of route optimization","slug":"routing-without-time-windows","type":"basic","title":"Without time-windows","__v":0,"childrenPages":[]}

Without time-windows

The simplest form of route optimization

Time-windows and durations are optional. If you are only interested in the optimal route without considering time, you can just omit the parameters. On large-scale problems, this will result in tremendous performance improvements! Keep in mind that the response will not include ETA values. [block:code] { "codes": [ { "code": "{\n \"visits\": {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n }\n },\n \"order_2\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n }\n },\n \"order_3\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n }\n }\n },\n \"fleet\": {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"end_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n }\n }\n }\n}", "language": "json", "name": "Input" }, { "code": "{\n \"status\": \"success\",\n \"total_travel_time\": 31.983334,\n \"total_idle_time\": 0,\n \"num_unserved\": 0,\n \"unserved\": null,\n \"solution\": {\n \"vehicle_1\": [\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\"\n },\n {\n \"location_id\": \"order_3\",\n \"location_name\": \"800 Robson\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"3780 Arbutus\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"6800 Cambie\"\n },\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\"\n }\n ]\n }\n}", "language": "json", "name": "Output" } ], "sidebar": true } [/block]
Time-windows and durations are optional. If you are only interested in the optimal route without considering time, you can just omit the parameters. On large-scale problems, this will result in tremendous performance improvements! Keep in mind that the response will not include ETA values. [block:code] { "codes": [ { "code": "{\n \"visits\": {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n }\n },\n \"order_2\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n }\n },\n \"order_3\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n }\n }\n },\n \"fleet\": {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"end_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n }\n }\n }\n}", "language": "json", "name": "Input" }, { "code": "{\n \"status\": \"success\",\n \"total_travel_time\": 31.983334,\n \"total_idle_time\": 0,\n \"num_unserved\": 0,\n \"unserved\": null,\n \"solution\": {\n \"vehicle_1\": [\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\"\n },\n {\n \"location_id\": \"order_3\",\n \"location_name\": \"800 Robson\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"3780 Arbutus\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"6800 Cambie\"\n },\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\"\n }\n ]\n }\n}", "language": "json", "name": "Output" } ], "sidebar": true } [/block]
{"_id":"5b2c2fa8f4eae600035b7177","category":"5b2c2fa8f4eae600035b716a","project":"546559525871e90800f503c0","user":"5465590bf42a472000b0c6b7","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":[],"next":{"pages":[],"description":""},"createdAt":"2014-11-28T20:41:46.276Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"never","params":[],"url":""},"isReference":false,"order":1,"body":"The end-location on a vehicle is optional and can be omitted to generate open-ended routes.\n\nIf you are generating the routes for the entire day, and you want to make sure that the driver reaches the end location at the end of the shift, you can provide an end-location. If the driver needs to return to a depot, the algorithm can utilize this final leg back to make a few visits along the way.\n\nHowever, if you are only interested in getting all your deliveries done as soon as possible without considering where driver might be at the end of his/her shift, you may opt to leave the route open-ended.\n\nOn-demand businesses that need real-time routing is another great use-case where you would keep the routes open-ended. As new orders come in dynamically throughout the day, you may call the API with the real-time locations of your drivers and keep re-optimizing throughout the day, without returning home.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  \\\"visits\\\": {\\n    \\\"order_1\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"6800 Cambie\\\",\\n        \\\"lat\\\": 49.227107,\\n        \\\"lng\\\": -123.1163085\\n      }\\n    },\\n    \\\"order_2\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"3780 Arbutus\\\",\\n        \\\"lat\\\": 49.2474624,\\n        \\\"lng\\\": -123.1532338\\n      }\\n    },\\n    \\\"order_3\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"800 Robson\\\",\\n        \\\"lat\\\": 49.2819229,\\n        \\\"lng\\\": -123.1211844\\n      }\\n    }\\n  },\\n  \\\"fleet\\\": {\\n    \\\"vehicle_1\\\": {\\n      \\\"start_location\\\": {\\n        \\\"id\\\": \\\"depot\\\",\\n        \\\"name\\\": \\\"800 Kingsway\\\",\\n        \\\"lat\\\": 49.2553636,\\n        \\\"lng\\\": -123.0873365\\n      }\\n    }\\n  }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Input\"\n    },\n    {\n      \"code\": \"{\\n  \\\"status\\\": \\\"success\\\",\\n  \\\"total_travel_time\\\": 31.983334,\\n  \\\"total_idle_time\\\": 0,\\n  \\\"num_unserved\\\": 0,\\n  \\\"unserved\\\": null,\\n  \\\"solution\\\": {\\n    \\\"vehicle_1\\\": [\\n      {\\n        \\\"location_id\\\": \\\"depot\\\",\\n        \\\"location_name\\\": \\\"800 Kingsway\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_3\\\",\\n        \\\"location_name\\\": \\\"800 Robson\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_2\\\",\\n        \\\"location_name\\\": \\\"3780 Arbutus\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_1\\\",\\n        \\\"location_name\\\": \\\"6800 Cambie\\\"\\n      }\\n    ]\\n  }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Output\"\n    }\n  ],\n  \"sidebar\": true\n}\n[/block]","excerpt":"Dynamic re-routing and maximum delivery speed","slug":"without-returning-to-depot","type":"basic","title":"Open-ended routes","__v":0,"childrenPages":[]}

Open-ended routes

Dynamic re-routing and maximum delivery speed

The end-location on a vehicle is optional and can be omitted to generate open-ended routes. If you are generating the routes for the entire day, and you want to make sure that the driver reaches the end location at the end of the shift, you can provide an end-location. If the driver needs to return to a depot, the algorithm can utilize this final leg back to make a few visits along the way. However, if you are only interested in getting all your deliveries done as soon as possible without considering where driver might be at the end of his/her shift, you may opt to leave the route open-ended. On-demand businesses that need real-time routing is another great use-case where you would keep the routes open-ended. As new orders come in dynamically throughout the day, you may call the API with the real-time locations of your drivers and keep re-optimizing throughout the day, without returning home. [block:code] { "codes": [ { "code": "{\n \"visits\": {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n }\n },\n \"order_2\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n }\n },\n \"order_3\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n }\n }\n },\n \"fleet\": {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n }\n }\n }\n}", "language": "json", "name": "Input" }, { "code": "{\n \"status\": \"success\",\n \"total_travel_time\": 31.983334,\n \"total_idle_time\": 0,\n \"num_unserved\": 0,\n \"unserved\": null,\n \"solution\": {\n \"vehicle_1\": [\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\"\n },\n {\n \"location_id\": \"order_3\",\n \"location_name\": \"800 Robson\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"3780 Arbutus\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"6800 Cambie\"\n }\n ]\n }\n}", "language": "json", "name": "Output" } ], "sidebar": true } [/block]
The end-location on a vehicle is optional and can be omitted to generate open-ended routes. If you are generating the routes for the entire day, and you want to make sure that the driver reaches the end location at the end of the shift, you can provide an end-location. If the driver needs to return to a depot, the algorithm can utilize this final leg back to make a few visits along the way. However, if you are only interested in getting all your deliveries done as soon as possible without considering where driver might be at the end of his/her shift, you may opt to leave the route open-ended. On-demand businesses that need real-time routing is another great use-case where you would keep the routes open-ended. As new orders come in dynamically throughout the day, you may call the API with the real-time locations of your drivers and keep re-optimizing throughout the day, without returning home. [block:code] { "codes": [ { "code": "{\n \"visits\": {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n }\n },\n \"order_2\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n }\n },\n \"order_3\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n }\n }\n },\n \"fleet\": {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n }\n }\n }\n}", "language": "json", "name": "Input" }, { "code": "{\n \"status\": \"success\",\n \"total_travel_time\": 31.983334,\n \"total_idle_time\": 0,\n \"num_unserved\": 0,\n \"unserved\": null,\n \"solution\": {\n \"vehicle_1\": [\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\"\n },\n {\n \"location_id\": \"order_3\",\n \"location_name\": \"800 Robson\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"3780 Arbutus\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"6800 Cambie\"\n }\n ]\n }\n}", "language": "json", "name": "Output" } ], "sidebar": true } [/block]
{"_id":"5b2c2fa8f4eae600035b7178","category":"5b2c2fa8f4eae600035b716a","project":"546559525871e90800f503c0","user":"5465590bf42a472000b0c6b7","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":[],"next":{"pages":[],"description":""},"createdAt":"2014-11-28T20:36:09.706Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"language":"json","code":"{}","name":"","status":200},{"name":"","status":400,"language":"json","code":"{}"}]},"settings":"","auth":"never","params":[],"url":""},"isReference":false,"order":2,"body":"When you are delivering larger items, it is imperative that you consider capacity constraints of your vehicles. Otherwise, the optimized routes may assign more deliveries to a vehicle than it can handle in reality.\n\nTo enable capacity constraints, each visit must set the `load` parameter to a numeric value. Also, each vehicle should have a value for its `capacity` parameter. The values for these parameters are unit-agnostic, so they can denote whatever unit makes sense for your business operations. \n\nFor example, if you deliver small, medium, and large packages, you can specify each delivery in the smallest common denominator – in this case a small package. A medium package could be the size of 4 small packages, etc. Now you can set the maximum capacity of a vehicle to the total amount of small packages that can fit in a vehicle.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"If you need to do same-day pickup and delivery – i.e. one order has a pickup location and a dropoff location – please have a look at the [Pickup and Delivery API](/docs/overview).\",\n  \"title\": \"Pickups and dropoffs\"\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  \\\"visits\\\": {\\n    \\\"order_1\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"6800 Cambie\\\",\\n        \\\"lat\\\": 49.227107,\\n        \\\"lng\\\": -123.1163085\\n      },\\n      \\\"load\\\": 5\\n    },\\n    \\\"order_2\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"3780 Arbutus\\\",\\n        \\\"lat\\\": 49.2474624,\\n        \\\"lng\\\": -123.1532338\\n      },\\n      \\\"load\\\": 2\\n    },\\n    \\\"order_3\\\": {\\n      \\\"location\\\": {\\n        \\\"name\\\": \\\"800 Robson\\\",\\n        \\\"lat\\\": 49.2819229,\\n        \\\"lng\\\": -123.1211844\\n      },\\n      \\\"load\\\": 10\\n    }\\n  },\\n  \\\"fleet\\\": {\\n    \\\"vehicle_1\\\": {\\n      \\\"start_location\\\": {\\n        \\\"id\\\": \\\"depot\\\",\\n        \\\"name\\\": \\\"800 Kingsway\\\",\\n        \\\"lat\\\": 49.2553636,\\n        \\\"lng\\\": -123.0873365\\n      },\\n      \\\"capacity\\\": 8\\n    }\\n  }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Input\"\n    },\n    {\n      \"code\": \"{\\n  \\\"status\\\": \\\"success\\\",\\n  \\\"total_travel_time\\\": 16.816668,\\n  \\\"total_idle_time\\\": 0,\\n  \\\"num_unserved\\\": 1,\\n  \\\"unserved\\\": { order_3: 'cannot be visited with the current fleet' },\\n  \\\"solution\\\": {\\n    \\\"vehicle_1\\\": [\\n      {\\n        \\\"location_id\\\": \\\"depot\\\",\\n        \\\"location_name\\\": \\\"800 Kingsway\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_1\\\",\\n        \\\"location_name\\\": \\\"6800 Cambie\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_2\\\",\\n        \\\"location_name\\\": \\\"3780 Arbutus\\\"\\n      }\\n    ]\\n  }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Output\"\n    }\n  ]\n}\n[/block]","excerpt":"Avoid overloading your trucks","slug":"capacity-constraints","type":"basic","title":"Capacity constraints","__v":0,"childrenPages":[]}

Capacity constraints

Avoid overloading your trucks

When you are delivering larger items, it is imperative that you consider capacity constraints of your vehicles. Otherwise, the optimized routes may assign more deliveries to a vehicle than it can handle in reality. To enable capacity constraints, each visit must set the `load` parameter to a numeric value. Also, each vehicle should have a value for its `capacity` parameter. The values for these parameters are unit-agnostic, so they can denote whatever unit makes sense for your business operations. For example, if you deliver small, medium, and large packages, you can specify each delivery in the smallest common denominator – in this case a small package. A medium package could be the size of 4 small packages, etc. Now you can set the maximum capacity of a vehicle to the total amount of small packages that can fit in a vehicle. [block:callout] { "type": "info", "body": "If you need to do same-day pickup and delivery – i.e. one order has a pickup location and a dropoff location – please have a look at the [Pickup and Delivery API](/docs/overview).", "title": "Pickups and dropoffs" } [/block] [block:code] { "codes": [ { "code": "{\n \"visits\": {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n },\n \"load\": 5\n },\n \"order_2\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n },\n \"load\": 2\n },\n \"order_3\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n },\n \"load\": 10\n }\n },\n \"fleet\": {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"capacity\": 8\n }\n }\n}", "language": "json", "name": "Input" }, { "code": "{\n \"status\": \"success\",\n \"total_travel_time\": 16.816668,\n \"total_idle_time\": 0,\n \"num_unserved\": 1,\n \"unserved\": { order_3: 'cannot be visited with the current fleet' },\n \"solution\": {\n \"vehicle_1\": [\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"6800 Cambie\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"3780 Arbutus\"\n }\n ]\n }\n}", "language": "json", "name": "Output" } ] } [/block]
When you are delivering larger items, it is imperative that you consider capacity constraints of your vehicles. Otherwise, the optimized routes may assign more deliveries to a vehicle than it can handle in reality. To enable capacity constraints, each visit must set the `load` parameter to a numeric value. Also, each vehicle should have a value for its `capacity` parameter. The values for these parameters are unit-agnostic, so they can denote whatever unit makes sense for your business operations. For example, if you deliver small, medium, and large packages, you can specify each delivery in the smallest common denominator – in this case a small package. A medium package could be the size of 4 small packages, etc. Now you can set the maximum capacity of a vehicle to the total amount of small packages that can fit in a vehicle. [block:callout] { "type": "info", "body": "If you need to do same-day pickup and delivery – i.e. one order has a pickup location and a dropoff location – please have a look at the [Pickup and Delivery API](/docs/overview).", "title": "Pickups and dropoffs" } [/block] [block:code] { "codes": [ { "code": "{\n \"visits\": {\n \"order_1\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n },\n \"load\": 5\n },\n \"order_2\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n },\n \"load\": 2\n },\n \"order_3\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n },\n \"load\": 10\n }\n },\n \"fleet\": {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"capacity\": 8\n }\n }\n}", "language": "json", "name": "Input" }, { "code": "{\n \"status\": \"success\",\n \"total_travel_time\": 16.816668,\n \"total_idle_time\": 0,\n \"num_unserved\": 1,\n \"unserved\": { order_3: 'cannot be visited with the current fleet' },\n \"solution\": {\n \"vehicle_1\": [\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"6800 Cambie\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"3780 Arbutus\"\n }\n ]\n }\n}", "language": "json", "name": "Output" } ] } [/block]
{"_id":"5b2c2fa8f4eae600035b7170","category":"5b2c2fa8f4eae600035b716b","project":"546559525871e90800f503c0","user":"5465590bf42a472000b0c6b7","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-05-29T20:38:40.915Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"language":"json","code":"{}","name":"","status":200},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":0,"body":"[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"https://api.routific.com/v1/pdp\",\n      \"language\": \"curl\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"For requests with more than 60 visits (i.e. 30 orders), it is necessary to use the asynchronous endpoint `/pdp-long` for [long-running tasks](/docs/vrp-long) to avoid timeouts. We recommend that you to use this endpoint even for smaller requests.\"\n}\n[/block]\nMost real-world routing situations can be covered with the routing endpoint described above. There is one case that requires special attention: Same-day Pickup and Delivery. Each order has a pickup location and a drop-off location that are mutually dependent. An item can only be dropped off after it has been picked up by the same driver.\n\nThe algorithm will find the optimal routes to do all your orders, so it may often occur that you pick up multiple orders before you drop them off. If you specify capacity constraints, it will ensure that your vehicles won't try to carry more than they can hold.\n\nSome example use-cases:\n\n- same-day courier\n- taxi services\n- moving companies\n- transportation services\n- third-party restaurant delivery\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Note that if you do pickups and deliveries, but they are not same-day, then you can use the normal Vehicle Routing endpoint, because there are no direct dependencies between the visits in the route you are solving. \\n\\nWhen using the `capacity` and `load` parameters, you can use a negative load to indicate a drop-off, which would clear up space in your vehicle.\",\n  \"title\": \"Next-day pickup and delivery\"\n}\n[/block]","excerpt":"","slug":"overview","type":"basic","title":"Pickup and Delivery Overview","__v":0,"childrenPages":[]}

Pickup and Delivery Overview


[block:code] { "codes": [ { "code": "https://api.routific.com/v1/pdp", "language": "curl" } ] } [/block] [block:callout] { "type": "info", "body": "For requests with more than 60 visits (i.e. 30 orders), it is necessary to use the asynchronous endpoint `/pdp-long` for [long-running tasks](/docs/vrp-long) to avoid timeouts. We recommend that you to use this endpoint even for smaller requests." } [/block] Most real-world routing situations can be covered with the routing endpoint described above. There is one case that requires special attention: Same-day Pickup and Delivery. Each order has a pickup location and a drop-off location that are mutually dependent. An item can only be dropped off after it has been picked up by the same driver. The algorithm will find the optimal routes to do all your orders, so it may often occur that you pick up multiple orders before you drop them off. If you specify capacity constraints, it will ensure that your vehicles won't try to carry more than they can hold. Some example use-cases: - same-day courier - taxi services - moving companies - transportation services - third-party restaurant delivery [block:callout] { "type": "info", "body": "Note that if you do pickups and deliveries, but they are not same-day, then you can use the normal Vehicle Routing endpoint, because there are no direct dependencies between the visits in the route you are solving. \n\nWhen using the `capacity` and `load` parameters, you can use a negative load to indicate a drop-off, which would clear up space in your vehicle.", "title": "Next-day pickup and delivery" } [/block]
[block:code] { "codes": [ { "code": "https://api.routific.com/v1/pdp", "language": "curl" } ] } [/block] [block:callout] { "type": "info", "body": "For requests with more than 60 visits (i.e. 30 orders), it is necessary to use the asynchronous endpoint `/pdp-long` for [long-running tasks](/docs/vrp-long) to avoid timeouts. We recommend that you to use this endpoint even for smaller requests." } [/block] Most real-world routing situations can be covered with the routing endpoint described above. There is one case that requires special attention: Same-day Pickup and Delivery. Each order has a pickup location and a drop-off location that are mutually dependent. An item can only be dropped off after it has been picked up by the same driver. The algorithm will find the optimal routes to do all your orders, so it may often occur that you pick up multiple orders before you drop them off. If you specify capacity constraints, it will ensure that your vehicles won't try to carry more than they can hold. Some example use-cases: - same-day courier - taxi services - moving companies - transportation services - third-party restaurant delivery [block:callout] { "type": "info", "body": "Note that if you do pickups and deliveries, but they are not same-day, then you can use the normal Vehicle Routing endpoint, because there are no direct dependencies between the visits in the route you are solving. \n\nWhen using the `capacity` and `load` parameters, you can use a negative load to indicate a drop-off, which would clear up space in your vehicle.", "title": "Next-day pickup and delivery" } [/block]
{"_id":"5b2c2fa8f4eae600035b7171","category":"5b2c2fa8f4eae600035b716b","user":"5465590bf42a472000b0c6b7","project":"546559525871e90800f503c0","parentDoc":null,"version":"5b2c2fa8f4eae600035b717d","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-05-29T20:51:18.245Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":1,"body":"Usage of Pickup and Delivery API is mostly identical with the normal Vehicle Routing API, with only one difference: the way we define pickup and delivery orders in the `visits` object.\n\nIn this case, visits is a hash of order objects where the key represents the `ID` of the order. Each order has a `pickup` and `dropoff` object. Both the `pickup` and `dropoff` objects require a location object, and optionally can have independent time-window and duration parameters.\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"PROPERTY\",\n    \"h-1\": \"TYPE\",\n    \"h-2\": \"REQUIRED\",\n    \"0-0\": \"pickup\",\n    \"1-0\": \"dropoff\",\n    \"0-1\": \"Visit object\",\n    \"0-2\": \"required\",\n    \"1-1\": \"Visit object\",\n    \"1-2\": \"required\",\n    \"2-0\": \"load\",\n    \"2-1\": \"Number (any unit)\",\n    \"2-2\": \"optional\",\n    \"3-0\": \"type\",\n    \"3-1\": \"String or Array\",\n    \"3-2\": \"optional\"\n  },\n  \"cols\": 3,\n  \"rows\": 4\n}\n[/block]\nThe `pickup` and `dropoff` parameters must be defined and are just like regular **visit objects**:\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"PROPERTY\",\n    \"h-1\": \"TYPE\",\n    \"h-2\": \"REQUIRED\",\n    \"0-0\": \"location\",\n    \"0-1\": \"Location object\",\n    \"0-2\": \"required\",\n    \"1-0\": \"start\",\n    \"1-1\": \"String (\\\"hh:mm\\\")\",\n    \"1-2\": \"optional\",\n    \"2-0\": \"end\",\n    \"2-1\": \"String (\\\"hh:mm\\\")\",\n    \"2-2\": \"optional\",\n    \"3-0\": \"duration\",\n    \"3-1\": \"Number (minutes)\",\n    \"3-2\": \"optional\"\n  },\n  \"cols\": 3,\n  \"rows\": 4\n}\n[/block]\n\n\nEach order can also have an optional `load` parameter. This is used when you want to account for the maximum capacity of your vehicles. This capacity must be defined on your fleet as well, otherwise this parameter will be ignored.\n\n`type` is an optional parameter if you want to restrict a visit to be served by a particular type of vehicle. The value of this parameter can be a String or an Array of Strings for multiple types. For example, if a visit has the type `[\"A\",\"B\"]` it can be served by a vehicle of type `\"A\"` or `\"B\"`. If none of the vehicles match the type, it will be unserved. Visits without any type parameters can be served by any vehicle.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Note that the `load` and `type` parameters are defined on the order object and not on the individual pick up and drop off objects\"\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"visits\\\": {\\n        \\\"order_1\\\": {\\n            \\\"load\\\": 1,\\n            \\\"pickup\\\": {\\n                \\\"location\\\": {\\n                    \\\"name\\\": \\\"3780 Arbutus\\\",\\n                    \\\"lat\\\": 49.2474624,\\n                    \\\"lng\\\": -123.1532338\\n                },\\n                \\\"start\\\": \\\"9:00\\\",\\n                \\\"end\\\": \\\"12:00\\\",\\n                \\\"duration\\\": 10\\n            },\\n            \\\"dropoff\\\": {\\n                \\\"location\\\": {\\n                    \\\"name\\\": \\\"6800 Cambie\\\",\\n                    \\\"lat\\\": 49.227107,\\n                    \\\"lng\\\": -123.1163085\\n                },\\n                \\\"start\\\": \\\"9:00\\\",\\n                \\\"end\\\": \\\"12:00\\\",\\n                \\\"duration\\\": 10\\n            }\\n        },\\n        \\\"order_2\\\": {\\n            \\\"load\\\": 1,\\n            \\\"pickup\\\": {\\n                \\\"location\\\": {\\n                    \\\"name\\\": \\\"3780 Arbutus\\\",\\n                    \\\"lat\\\": 49.2474624,\\n                    \\\"lng\\\": -123.1532338\\n                },\\n                \\\"start\\\": \\\"9:00\\\",\\n                \\\"end\\\": \\\"12:00\\\",\\n                \\\"duration\\\": 10\\n            },\\n            \\\"dropoff\\\": {\\n                \\\"location\\\": {\\n                    \\\"name\\\": \\\"800 Robson\\\",\\n                    \\\"lat\\\": 49.2819229,\\n                    \\\"lng\\\": -123.1211844\\n                },\\n                \\\"start\\\": \\\"9:00\\\",\\n                \\\"end\\\": \\\"12:00\\\",\\n                \\\"duration\\\": 10\\n            }\\n        }\\n    },\\n    \\\"fleet\\\": {\\n        \\\"vehicle_1\\\": {\\n            \\\"start_location\\\": {\\n                \\\"id\\\": \\\"depot\\\",\\n                \\\"name\\\": \\\"800 Kingsway\\\",\\n                \\\"lat\\\": 49.2553636,\\n                \\\"lng\\\": -123.0873365\\n            },\\n            \\\"end_location\\\": {\\n                \\\"id\\\": \\\"depot\\\",\\n                \\\"name\\\": \\\"800 Kingsway\\\",\\n                \\\"lat\\\": 49.2553636,\\n                \\\"lng\\\": -123.0873365\\n            },\\n            \\\"shift_start\\\": \\\"8:00\\\",\\n            \\\"shift_end\\\": \\\"12:00\\\",\\n            \\\"capacity\\\": 2\\n        },\\n        \\\"vehicle_2\\\": {\\n            \\\"start_location\\\": {\\n                \\\"id\\\": \\\"depot 2\\\",\\n                \\\"name\\\": \\\"800 Robson\\\",\\n                \\\"lat\\\": 49.2819229,\\n                \\\"lng\\\": -123.1211844\\n            },\\n            \\\"end_location\\\": {\\n                \\\"id\\\": \\\"depot\\\",\\n                \\\"name\\\": \\\"800 Kingsway\\\",\\n                \\\"lat\\\": 49.2553636,\\n                \\\"lng\\\": -123.0873365\\n            },\\n            \\\"shift_start\\\": \\\"8:00\\\",\\n            \\\"shift_end\\\": \\\"12:00\\\",\\n            \\\"capacity\\\": 1\\n        }\\n    }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Input\"\n    },\n    {\n      \"code\": \"{\\n  \\\"status\\\": \\\"success\\\",\\n  \\\"total_travel_time\\\": 31.283333,\\n  \\\"total_idle_time\\\": 0,\\n  \\\"num_unserved\\\": 0,\\n  \\\"unserved\\\": null,\\n  \\\"solution\\\": {\\n    \\\"vehicle_1\\\": [\\n      {\\n        \\\"location_id\\\": \\\"depot\\\",\\n        \\\"location_name\\\": \\\"800 Kingsway\\\",\\n        \\\"arrival_time\\\": \\\"08:50\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_2\\\",\\n        \\\"location_name\\\": \\\"3780 Arbutus\\\",\\n        \\\"arrival_time\\\": \\\"09:00\\\",\\n        \\\"finish_time\\\": \\\"09:10\\\",\\n        \\\"type\\\": \\\"pickup\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_1\\\",\\n        \\\"location_name\\\": \\\"3780 Arbutus\\\",\\n        \\\"arrival_time\\\": \\\"09:10\\\",\\n        \\\"finish_time\\\": \\\"09:20\\\",\\n        \\\"type\\\": \\\"pickup\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_1\\\",\\n        \\\"location_name\\\": \\\"6800 Cambie\\\",\\n        \\\"arrival_time\\\": \\\"09:26\\\",\\n        \\\"finish_time\\\": \\\"09:36\\\",\\n        \\\"type\\\": \\\"dropoff\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"order_2\\\",\\n        \\\"location_name\\\": \\\"800 Robson\\\",\\n        \\\"arrival_time\\\": \\\"09:45\\\",\\n        \\\"finish_time\\\": \\\"09:55\\\",\\n        \\\"type\\\": \\\"dropoff\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"depot\\\",\\n        \\\"location_name\\\": \\\"800 Kingsway\\\",\\n        \\\"arrival_time\\\": \\\"10:02\\\"\\n      }\\n    ],\\n    \\\"vehicle_2\\\": [\\n      {\\n        \\\"location_id\\\": \\\"depot 2\\\",\\n        \\\"location_name\\\": \\\"800 Robson\\\",\\n        \\\"arrival_time\\\": \\\"08:00\\\"\\n      },\\n      {\\n        \\\"location_id\\\": \\\"depot\\\",\\n        \\\"location_name\\\": \\\"800 Kingsway\\\",\\n        \\\"arrival_time\\\": \\\"08:06\\\"\\n      }\\n    ]\\n  }\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Output\"\n    }\n  ],\n  \"sidebar\": true\n}\n[/block]\nAnother thing to note in the example on the right: in the output, each visit contains a `type` to indicate if it is a pick up or a drop off.","excerpt":"With a pickup location and a drop-off location","slug":"defining-orders","type":"basic","title":"Defining orders","__v":0,"childrenPages":[]}

Defining orders

With a pickup location and a drop-off location

Usage of Pickup and Delivery API is mostly identical with the normal Vehicle Routing API, with only one difference: the way we define pickup and delivery orders in the `visits` object. In this case, visits is a hash of order objects where the key represents the `ID` of the order. Each order has a `pickup` and `dropoff` object. Both the `pickup` and `dropoff` objects require a location object, and optionally can have independent time-window and duration parameters. [block:parameters] { "data": { "h-0": "PROPERTY", "h-1": "TYPE", "h-2": "REQUIRED", "0-0": "pickup", "1-0": "dropoff", "0-1": "Visit object", "0-2": "required", "1-1": "Visit object", "1-2": "required", "2-0": "load", "2-1": "Number (any unit)", "2-2": "optional", "3-0": "type", "3-1": "String or Array", "3-2": "optional" }, "cols": 3, "rows": 4 } [/block] The `pickup` and `dropoff` parameters must be defined and are just like regular **visit objects**: [block:parameters] { "data": { "h-0": "PROPERTY", "h-1": "TYPE", "h-2": "REQUIRED", "0-0": "location", "0-1": "Location object", "0-2": "required", "1-0": "start", "1-1": "String (\"hh:mm\")", "1-2": "optional", "2-0": "end", "2-1": "String (\"hh:mm\")", "2-2": "optional", "3-0": "duration", "3-1": "Number (minutes)", "3-2": "optional" }, "cols": 3, "rows": 4 } [/block] Each order can also have an optional `load` parameter. This is used when you want to account for the maximum capacity of your vehicles. This capacity must be defined on your fleet as well, otherwise this parameter will be ignored. `type` is an optional parameter if you want to restrict a visit to be served by a particular type of vehicle. The value of this parameter can be a String or an Array of Strings for multiple types. For example, if a visit has the type `["A","B"]` it can be served by a vehicle of type `"A"` or `"B"`. If none of the vehicles match the type, it will be unserved. Visits without any type parameters can be served by any vehicle. [block:callout] { "type": "info", "body": "Note that the `load` and `type` parameters are defined on the order object and not on the individual pick up and drop off objects" } [/block] [block:code] { "codes": [ { "code": "{\n \"visits\": {\n \"order_1\": {\n \"load\": 1,\n \"pickup\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n },\n \"start\": \"9:00\",\n \"end\": \"12:00\",\n \"duration\": 10\n },\n \"dropoff\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n },\n \"start\": \"9:00\",\n \"end\": \"12:00\",\n \"duration\": 10\n }\n },\n \"order_2\": {\n \"load\": 1,\n \"pickup\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n },\n \"start\": \"9:00\",\n \"end\": \"12:00\",\n \"duration\": 10\n },\n \"dropoff\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n },\n \"start\": \"9:00\",\n \"end\": \"12:00\",\n \"duration\": 10\n }\n }\n },\n \"fleet\": {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"end_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"shift_start\": \"8:00\",\n \"shift_end\": \"12:00\",\n \"capacity\": 2\n },\n \"vehicle_2\": {\n \"start_location\": {\n \"id\": \"depot 2\",\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n },\n \"end_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"shift_start\": \"8:00\",\n \"shift_end\": \"12:00\",\n \"capacity\": 1\n }\n }\n}", "language": "json", "name": "Input" }, { "code": "{\n \"status\": \"success\",\n \"total_travel_time\": 31.283333,\n \"total_idle_time\": 0,\n \"num_unserved\": 0,\n \"unserved\": null,\n \"solution\": {\n \"vehicle_1\": [\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\",\n \"arrival_time\": \"08:50\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"3780 Arbutus\",\n \"arrival_time\": \"09:00\",\n \"finish_time\": \"09:10\",\n \"type\": \"pickup\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"3780 Arbutus\",\n \"arrival_time\": \"09:10\",\n \"finish_time\": \"09:20\",\n \"type\": \"pickup\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"6800 Cambie\",\n \"arrival_time\": \"09:26\",\n \"finish_time\": \"09:36\",\n \"type\": \"dropoff\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"800 Robson\",\n \"arrival_time\": \"09:45\",\n \"finish_time\": \"09:55\",\n \"type\": \"dropoff\"\n },\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\",\n \"arrival_time\": \"10:02\"\n }\n ],\n \"vehicle_2\": [\n {\n \"location_id\": \"depot 2\",\n \"location_name\": \"800 Robson\",\n \"arrival_time\": \"08:00\"\n },\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\",\n \"arrival_time\": \"08:06\"\n }\n ]\n }\n}", "language": "json", "name": "Output" } ], "sidebar": true } [/block] Another thing to note in the example on the right: in the output, each visit contains a `type` to indicate if it is a pick up or a drop off.
Usage of Pickup and Delivery API is mostly identical with the normal Vehicle Routing API, with only one difference: the way we define pickup and delivery orders in the `visits` object. In this case, visits is a hash of order objects where the key represents the `ID` of the order. Each order has a `pickup` and `dropoff` object. Both the `pickup` and `dropoff` objects require a location object, and optionally can have independent time-window and duration parameters. [block:parameters] { "data": { "h-0": "PROPERTY", "h-1": "TYPE", "h-2": "REQUIRED", "0-0": "pickup", "1-0": "dropoff", "0-1": "Visit object", "0-2": "required", "1-1": "Visit object", "1-2": "required", "2-0": "load", "2-1": "Number (any unit)", "2-2": "optional", "3-0": "type", "3-1": "String or Array", "3-2": "optional" }, "cols": 3, "rows": 4 } [/block] The `pickup` and `dropoff` parameters must be defined and are just like regular **visit objects**: [block:parameters] { "data": { "h-0": "PROPERTY", "h-1": "TYPE", "h-2": "REQUIRED", "0-0": "location", "0-1": "Location object", "0-2": "required", "1-0": "start", "1-1": "String (\"hh:mm\")", "1-2": "optional", "2-0": "end", "2-1": "String (\"hh:mm\")", "2-2": "optional", "3-0": "duration", "3-1": "Number (minutes)", "3-2": "optional" }, "cols": 3, "rows": 4 } [/block] Each order can also have an optional `load` parameter. This is used when you want to account for the maximum capacity of your vehicles. This capacity must be defined on your fleet as well, otherwise this parameter will be ignored. `type` is an optional parameter if you want to restrict a visit to be served by a particular type of vehicle. The value of this parameter can be a String or an Array of Strings for multiple types. For example, if a visit has the type `["A","B"]` it can be served by a vehicle of type `"A"` or `"B"`. If none of the vehicles match the type, it will be unserved. Visits without any type parameters can be served by any vehicle. [block:callout] { "type": "info", "body": "Note that the `load` and `type` parameters are defined on the order object and not on the individual pick up and drop off objects" } [/block] [block:code] { "codes": [ { "code": "{\n \"visits\": {\n \"order_1\": {\n \"load\": 1,\n \"pickup\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n },\n \"start\": \"9:00\",\n \"end\": \"12:00\",\n \"duration\": 10\n },\n \"dropoff\": {\n \"location\": {\n \"name\": \"6800 Cambie\",\n \"lat\": 49.227107,\n \"lng\": -123.1163085\n },\n \"start\": \"9:00\",\n \"end\": \"12:00\",\n \"duration\": 10\n }\n },\n \"order_2\": {\n \"load\": 1,\n \"pickup\": {\n \"location\": {\n \"name\": \"3780 Arbutus\",\n \"lat\": 49.2474624,\n \"lng\": -123.1532338\n },\n \"start\": \"9:00\",\n \"end\": \"12:00\",\n \"duration\": 10\n },\n \"dropoff\": {\n \"location\": {\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n },\n \"start\": \"9:00\",\n \"end\": \"12:00\",\n \"duration\": 10\n }\n }\n },\n \"fleet\": {\n \"vehicle_1\": {\n \"start_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"end_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"shift_start\": \"8:00\",\n \"shift_end\": \"12:00\",\n \"capacity\": 2\n },\n \"vehicle_2\": {\n \"start_location\": {\n \"id\": \"depot 2\",\n \"name\": \"800 Robson\",\n \"lat\": 49.2819229,\n \"lng\": -123.1211844\n },\n \"end_location\": {\n \"id\": \"depot\",\n \"name\": \"800 Kingsway\",\n \"lat\": 49.2553636,\n \"lng\": -123.0873365\n },\n \"shift_start\": \"8:00\",\n \"shift_end\": \"12:00\",\n \"capacity\": 1\n }\n }\n}", "language": "json", "name": "Input" }, { "code": "{\n \"status\": \"success\",\n \"total_travel_time\": 31.283333,\n \"total_idle_time\": 0,\n \"num_unserved\": 0,\n \"unserved\": null,\n \"solution\": {\n \"vehicle_1\": [\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\",\n \"arrival_time\": \"08:50\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"3780 Arbutus\",\n \"arrival_time\": \"09:00\",\n \"finish_time\": \"09:10\",\n \"type\": \"pickup\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"3780 Arbutus\",\n \"arrival_time\": \"09:10\",\n \"finish_time\": \"09:20\",\n \"type\": \"pickup\"\n },\n {\n \"location_id\": \"order_1\",\n \"location_name\": \"6800 Cambie\",\n \"arrival_time\": \"09:26\",\n \"finish_time\": \"09:36\",\n \"type\": \"dropoff\"\n },\n {\n \"location_id\": \"order_2\",\n \"location_name\": \"800 Robson\",\n \"arrival_time\": \"09:45\",\n \"finish_time\": \"09:55\",\n \"type\": \"dropoff\"\n },\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\",\n \"arrival_time\": \"10:02\"\n }\n ],\n \"vehicle_2\": [\n {\n \"location_id\": \"depot 2\",\n \"location_name\": \"800 Robson\",\n \"arrival_time\": \"08:00\"\n },\n {\n \"location_id\": \"depot\",\n \"location_name\": \"800 Kingsway\",\n \"arrival_time\": \"08:06\"\n }\n ]\n }\n}", "language": "json", "name": "Output" } ], "sidebar": true } [/block] Another thing to note in the example on the right: in the output, each visit contains a `type` to indicate if it is a pick up or a drop off.