NAV Navbar
Examples

Introduction

Welcome to the Solvice API! You can use our API to access Solvice API endpoints, which can get information on your solved jobs, their statuses and of course post new solve jobs.

Authentication

# With shell, you can just pass the correct header with each request
curl "https://api.solvice.io/"
  -H "Authorization Basic: key"

Make sure to replace key with your API key.

Currently Basic Auth is used for authenticating users. Classically you can add a HTTP header:

"Authorization Basic" + btoa(USERNAME + ":" + PASSWORD)

Getting started

Test our API in just one command

curl https://demo:[email protected]/demo/vrp | \
curl https://demo:[email protected]/v1/solve  \
     -X POST -H "Content-Type: application/json" -d @-

You can copy and paste the above in your terminal for a working example. The example uses a randomly generated VRP problem.

The Solvice API is super simple! Basically, it holds one /solve endpoint for sending an asynchronous solve request to for a certain optimization problem and it holds one /jobs/:job_id/solution endpoint for retrieving the solved job asynchronous. That's it! The only thing you have to manage is the actual payload for the solve request.

Solvice API

Common usage of the Solvice API follows this flow:

  1. Post solve request for x seconds with HTTP param ?seconds=x
  2. Wait x seconds
  3. Fetch status of job
  4. Fetch solution if status=SOLVED in solution endpoint
  5. Fetch statistics if !score.feasible in statistics endpoint

Solve endpoint

Response example

{
  "id": "job_id",
  "solver": "VRP",
  "solve_duration": 100,
  "status": "QUEUED"
}

Solving a new job is as simple as making a POST request to the solve endpoint. This is an asynchronous action and will return the status of the job.

HTTP request

POST https://api.solvice.io/v1/solve

The payload of the request is the structure defined in the next chapter.

Jobs endpoint

Response example

{
  "id": "job_id",
  "solver": "VRP",
  "solve_duration": 100,
  "status": "QUEUED"
}

When posting a new solve request, this job can be checked again under this endpoint. In fact, it should be the entire request posted as-is.

HTTP request

GET https://api.solvice.io/v1/jobs/{job_id}

Job attributes:

Parameter Description
id The id of the job
solver Type of the solver used for this job
solve_duration How long will the solver take to solve it (in minutes)
status Status of the job

Status endpoint

Response example

{
  "id": "job_id",
  "solver": "VRP",
  "solve_duration": 100,
  "status": "SOLVING"
}

After a specified solve duration set the HTTP param seconds in the solve endpoint (e.g.: api.solvice.io/solve?seconds-=25), it is time to check the status of the job. Recurrent polling of the status should be done on this endpoint.

HTTP request

GET https://api.solvice.io/v1/jobs/{job_id}/status

Hooks

Alternatively, you can use hooks in order to be notified when the solve is done. It is required to have an open endpoint on a web-service that receives payloads in the form of the status. Simply integrate hooks by adding a property "hooks": "http://your-web-service/hook-receive" that will receive HTTP POST requests with status updates. After this request is received, you know that for a certain job, the solution is calculated.

Solution endpoint

Response example

{
  "id": "job_id",
  "solver": "VRP",
  "solve_duration": 100,
  "status": "SOLVED",
  "solution": {...}
}

Once the status is SOLVED, you can get the resulting solution in the Solution endpoint.

HTTP request

GET https://api.solvice.io/v1/jobs/{job_id}/solution

Statistics endpoint

Response example

{
  "id": "job_id",
  "goals": [
    {

    },
    ...

  ]
}

Want to know how it is optimised? This endpoint lets you know what rules have been overruled.

HTTP request

GET https://api.solvice.io/v1/stats/{job_id}

Vehicle Routing

Locations

Extract of VRP solve request - locations details:

{
  "locations": [
    {
      "name" : "Brussels, Belgium",
      "latitude": 51.057,
      "longitude": 4.185
    },
    ...
  ],
  ...
}

Each node in the network is defined by the latitude and longitude at least (WGS84). The name property is required, and will be returned in the response. The name is also necessary when referencing this location in the orders section.

Parameter Type Description Required
name String The unique name of the location yes
latitude Integer Latitude yes
longitude Integer Longitude yes

Fleet

Extract of VRP solve request - fleet details:

{
  "fleet": [
    {
      "name" : "Driver John",
      "startLocation": "Brussels, Belgium",
      "endlocation": "Brussels, Belgium",
      "shiftstart": 690,
      "shiftend": 1020,
      "capacity": 18,
      "category": "TRUCK",
      "overtime": false,
      "workingDays": [
        "MONDAY",
        "TUESDAY",
        "WEDNESDAY",
        "THURSDAY",
        "FRIDAY"
      ],
      "unavailable": [
        "2018-01-05",
        "2018-01-07"
      ],
      "type" : [
        "Technician"
      ]
    },
    ...
  ],
  ...
}

The fleet consists of your vehicles, that you want to allocate the orders to. Each vehicle is defined by a starting and ending location (referencing a location on the network), and the shift start and end times.

Parameter Type Description Required
name String The unique name of the vehicle yes
startlocation String The name of the location where the vehicle starts yes
endlocation String The name of the location where the vehicle ends
shiftstart Number Starting time of the shift in minutes
shiftend Number End time of the shift in minutes
capacity Number Capacity type 1
capacity2 Number Capacity type 2
breaks Array See Break structure
type Array of Strings Type restrictions
category String see Category
overtime Boolean If vehicle can do overtime or not
workingDays Array of days of week Plannable days
unavailable Array of dates Non plannable dates

The end location is optional and may be omitted. This may be useful in cases when you care less about total distance traveled, and instead would like to prioritize your visits closeby to be done as soon as possible. The reason why this works is because Solvice OnRoute minimizes total travel time, and may leave closeby visits for on the way back.

Optionally, you may define the capacity of the vehicle (using the same unit as the "weight" for your orders). The algorithm will make sure that this capacity will not be exceeded. You can define 2 types of capacity: e.g. one for weight (in pounds, kilos, tons) and one for volume (square meters, cube meters)

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 is an array of strings for multiple types. Vehicles without any type will still be able to serve the visits that have no type restrictions. Examples of type restrictions: "Technician", "Maintenance", ...

If a vehicle can do overtime, then the shift end constraint is not seen as hard and then it is possible that some orders are scheduled after shift end. overtime_end determines the maximum of overtime.

Breaks

A break can be scheduled between a certain break interval (breakstart and breakend) and can take a pre-defined amount of time (breakduration).

Break payload

{
  "breaks": [
    {
      "breakstart": 780,
      "breakend": 860,
      "breakduration": 30
    }
  ]
}
Parameter Type Description Required
breakstart Number Earliest starting time of break yes
breakend Number Latest ending time of break yes
breakduration Number Duration of break (should be less than or equal to end - start)

In the solution, breaks will return as orders and visits of the fleet. Introducing breaks will require more computation time, as they are seen as orders.

Category

Category Restrictions
CAR car access
BIKE bike access
SMALL_TRUCK height=2.7m, width=2+0.4m, length=5.5m, weight=2080+1400 kg
TRUCK height=3.7m, width=2.6+0.5m, length=12m, weight=13000 + 13000 kg, hgv=yes, 3 Axes
BUS height=3.54m, width=2.55+0.5m, length=10.34m, weight=9600 + 6000 kg

Orders

Extract of VRP solve request - orders details:

{
  "orders": [
    {
      "name" : "order 1",
      "location": "Brussels, Belgium",
      "demand": 10,
      "demand2": 50,
      "duration": 30,
      "windows": [
        {
         ...
        }
      ],
      "type" : [
        "Technician"
      ],
      "openingDays" : [
        "MONDAY",
        "TUESDAY",
        "WEDNESDAY",
        "THURSDAY",
        "FRIDAY"
      ],

    },
    ...
  ],
  ...
}

Orders reference the location ID that was defined in the network above. Each order can have a time-window constraint, defined by starttime and endtime. Time windows are optional; when not provided, it implies that any time will do.

Parameter Type Description Required
name String The unique name of the vehicle yes
location String The name of the location where the vehicle starts yes
duration Number Duration of the service (in minutes)
type String or Array Type restriction
demand Number demand for capacity type 1
demand2 Number demand for capacity type 2
windows Array See Time Window structure
openingDays Array of String Plannable days
dateWindows Array See Date Window structure
allowedVehicles Array List of vehicle id's
disallowedVehicles Array List of vehicle id's
durationSquash Number Duration of visits at the same location

duration specifies how many minutes the order at the customer takes. If a delivery takes 30 minutes and given a time-window of 12:00-13:00 (720 - 780), the algorithm will make sure that you arrive at 12:30 at the latest. Multiple time windows are allowed.

activity reflects the type of activity done for that order or at that customer. 3 different types are defined: DELIVERY, PICKUP or EXECUTION.

demand is the number of a certain item that gets delivered or picked up. (This can be weight, volume or a number)

demand2 is the number of a certain item that gets delivered or picked up. (This can be weight, volume or a number)

location refers to the exact name defined in the section of locations.

type refers to the type attributed to the vehicle. Only when the type matches by string, this order can be assigned to that vehicle. Example: if you want an order only to be assigned to a subset of vehicles, then define the same type definitions for both orders and vehicles.

openingDays define the actual days in the week in the week that the order is plannable. By default the midweek from Monday until Friday is used.

dateWindows defines a list of periods (start and end dates) between this order is plannable.

allowedVehicles defines a list of vehicles to which this order can be assigned to.

disallowedVehicles defines a list of vehicles to which this order cannot be assigned to.

durationSquash is 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.

Time window

Time window structure

{
  "windows": [
    {
      "starttime": 680,
      "endtime": 720,
      "hard": false
    }
  ]
}

A time window consists of a starttime and an endtime. The order cannot be processed before the starttime and should start being processed before endtime. If the time window is hard, then it should always be fulfilled. E.g. a driver would prefer to drive 3 hours longer than not be on time wrt that time window for that order. So hard time window constraints are pretty extreme!

Date window

Date window structure

{
  "dateWindows": [
    {
      "start": "2019-01-21",
      "end": "2019-01-24"
    }
  ]
}

A date window consists of a start date and an end date. The order cannot be planned before the start and should be planned before end date.

Options

Specific options can be added to guide the solving process.

{
  "options" : {
    "traffic": 1.2,
    "overconstrained": false,
    "vehicle_setup_cost": 100,
    "minimize_driver_wait_time": false,
    "minimize_vehicle_use": false,
    "allow_overtime": false
  }
}
Parameter Type Description
traffic Double Traffic modifier
overconstrained Boolean Indicates to not plan all orders, but only feasible ones
minimize_driver_wait_time Boolean Wait time should be minimized
minimize_vehicle_use Boolean The least number of vehicles should be used
vehicle_setup_cost Number Cost incurred when using an extra vehicle

Solution

Solution structure of visits

{
  "solution ": {
    "driver1": [
      {
        "location ": "loc0 ",
        "order ": null,
        "arrival ": 510,
        "finish ": 510,
        "wait ": 0,
        "drive ": 0,
        "distance ": 0
      },
      {
        "location ": "loc1 ",
        "order ": "order1 ",
        "arrival ": 504,
        "finish ": 534,
        "wait ": 0,
        "drive ": 24,
        "distance ": 24
      }
    ]
  }
}

The output will contain a section on the quality of the solution score. When a solution would not be feasible, this is the place to look.

Score structure

"score":{"hardScore":0,"softScore":-59,"feasible":true}

The output will contain the input where in each vehicle section of the fleet, the sequence of visits will create the route. A sequence of visits will look like this:

A visit refers to the order and the location and also depicts the arrival time, the finish time, the wait time, the drive time and the distance in km to that location.

Initial solution

Initial scheduled visits (pre-defined)

{
  "name": "truck2",
  "visits": [
    {
      "order": "order1",
      "arrival": 750,
    },
    {
      "order": "order3",
      "arrival": 782,
    }
  ]
}

When you want to start from an initial solution (perhaps your current route that is calculated manually) then you can also enter this information as visits for every truck. The structure is similar to the result you obtain after the solution is found.

Pickup and Delivery

A special case of the classical Vehicle Routing Problem is the Pickup and Delivery Problem. 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 Solvice solver 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:

Pickup

 {
     "name": "pickup in Ghent",
     "location": "Ghent, Centre",
     "activity": "PICKUP",
     "duration": 10,
     "ride": "order0"
 }

Delivery

 {
     "name": "Delivery in Brussels",
     "location": "Brussels, Centre",
     "activity": "DROPOFF",
     "duration": 10,
     "ride": "order0"
 }

First off, but most importantly, you should define that the problem is a PDP, by setting the solver property to "PDP" in the payload.

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. If an item has to reach a certain location, you have to pick it up first (i.e. create a pickup order with activity : "pickup") and then drop it of in another location (i.e. create a dropoff order with activity : "dropoff").

In the example on the right, you can see one order (order0) which has a pickup requirement in the centre of Ghent and a delivery requirement (see the next tab) in the city of Antwerp. It takes 10 minutes to pickup and 10 minutes to deliver and it accounts for 3 units of the load in a vehicle. Mind that the property ride alerts the solver that its about the same ride!

An entire solution can be seen in the third tab.

Periodic Vehicle Routing Problem

Another special case of the classical Vehicle Routing Problem is the Periodic VRP. When planning for multiple days, the optimisation gets even more complicated.

First off, but most importantly, you should define that the problem is a PVRP, by setting the solver property to "PVRP" in the payload.

Planning period

An extra property explaining the period for which we can solve the problem should be used.

Parameter Type Description
start String Start date of planning period
end String End date of planning period

Planning period

{
  "period": {
      "start": "2018-01-01",
      "end": "2018-01-31"
  },
  // ...
}

Precedence constraints

In PVRP, a time dependency (or precedence constraint) can be modelled for two orders.

Parameter Type Description
order1 String The name of the left order (must be executed first), referenced by the name provided in orders
order2 String The name of the right order (must be executed after order 1)
min Integer The minimum time between order2 and order1
max Integer The maximum time between order2 and order1

Extract of PVRP solve request - precedence constraints:

{
  "precedence_constraints": [
    {
      "order1" : "A",
      "order2": "B",
      "min": 1,
      "max": 5
    },
    ...
  ],
  ...
}

Try out the demo resource at https://api.solvice.io/demo/pvrp with your credentials.

Errors

Message structure

For debugging purposes, we identify two types of errors that can occur when sending bad requests. This will help the developer integrating the Solvice API to determine whether

JSON error:

Property Description
errorCode The exact code of the error
explanation Description of the error
line Line number of the error
column Column number of the error

Validation error:

Property Description
errorCode The exact code of the error
explanation Description of the error
propertyPath Path of the property that has a validation error

Codes

The Solvice API uses the following error codes:

Error Code Error Name Description
400 Bad Request Your request is wrong. Check specific reasons.
401 Unauthorized Your API key is wrong.
403 Forbidden The request is for administrators only.
404 Not Found The specified resource could not be found.
405 Method Not Allowed You tried to access a resource with an invalid method.
406 Not Acceptable You requested a format that isn't JSON.
429 Too Many Requests You're requesting too many solve requests! Slow down!
500 Internal Server Error We had a problem with our server. Try again later.
503 Service Unavailable We're temporarily offline for maintenance. Please try again later.