This document describes the usage of the XTL API to calculate static TSPs, PDPs and VRPs.
The base URL for all API requests is https://example.xtl-gmbh.de
. The API currently supports HTTP 1.0 and HTTP 1.1. Data send in POST
and PUT
requests needs to be encoded in JSON. Responses are always encoded in JSON.
The creation of a secure HTTPS connection is required for all requests. Only TLS 1.2 and a set of secure ciphers which offer forward secrecy are allowed:
ECDHE-RSA-AES256-GCM-SHA384, ECDHE-RSA-AES128-GCM-SHA256, DHE-RSA-AES256-GCM-SHA384, DHE-RSA-AES128-GCM-SHA256, ECDHE-RSA-AES256-SHA384, ECDHE-RSA-AES128-SHA256, ECDHE-RSA-AES256-SHA, ECDHE-RSA-AES128-SHA, DHE-RSA-AES256-SHA256, DHE-RSA-AES128-SHA256, DHE-RSA-AES256-SHA, DHE-RSA-AES128-SHA, ECDHE-RSA-DES-CBC3-SHA, EDH-RSA-DES-CBC3-SHA, AES256-GCM-SHA384, AES128-GCM-SHA256, AES256-SHA256, AES128-SHA256, AES256-SHA, AES128-SHA, DES-CBC3-SHA
Each API request needs to include authentication information (your API Key) in the HTTP Header field X-Api-Key.
The following API endpoint can be used to calculate small to medium static TSPs, PDPs and VRPs.
POST /planning/static
X-Api-Key: 0123456789ABCDEF
The endpoint works synchronously, i.e. the request is blocked until the calculation is completed. Depending on the volume of data (number of orders and couriers/vehicles) and the complexity of the scenario, the calculation may take some time. It is therefore important not to use a timeout that is too short so that the request is not aborted too early.
In order to keep the response time as short as possible, do not calculate very large and complex scenarios with this endpoint.
The distinction between TSP, PDP and VRP is made implicitly by the data you send (orders and couriers/vehicles).
The body of the HTTP request consists of a JSON object with the following properties:
Field | Type | Description |
---|---|---|
couriers | Courier[] | List of couriers |
orders | Order[] | List of orders |
{
"couriers": [...],
"orders": [...]
}
Some entities like orders and couriers contain addresses which consist of descriptive properties street
, number
, postalcode
and city
and geo coordinates locationLat
and locationLon
. Only descriptive parts or the geo coordinates needs to be complete. Other information will be completed by geocoding or reverse geocoding automatically according to the configured geocoding-provider-hierarchy.
No geocoding or reverse geocoding will be made, if the descriptive properties and geo coordinates are provided.
Field | Type | Description |
---|---|---|
name | String | Name of recipient/sender |
street | String | Street without house number |
number | String | House number |
postalcode | Integer | Postalcode |
city | String | City |
locationLat | Number | Latitude |
locationLon | Number | Longitude |
Since all properties are provided, no geocoding or reverse geocoding will be made for this address:
{
"name": "XTL",
"street": "Fahrenheitstraße",
"number": "1",
"postalcode": 28359,
"city": "Bremen",
"locationLat": 53.10837,
"locationLon": 8.848045
}
The following address will be geocoded to complete the geo coordinates
{
"name": "XTL",
"street": "Fahrenheitstraße",
"number": "1",
"postalcode": 28359,
"city": "Bremen"
}
The descriptive parts of the following address will be completed by reverse geocoding:
{
"name": "XTL",
"locationLat": 53.10837,
"locationLon": 8.848045
}
Incomplete descriptive parts (street missing):
"name": "XTL",
"number": "1",
"postalcode": 28359,
"city": "Bremen"
Mixed descriptive parts and geo coordinates, but both incomplete:
{
"name": "XTL",
"locationLat": 53.10837,
"city": "Bremen"
}
All dates in the request body need to be specified as IETF-compliant RFC 2822 time stamp e.g. 2016-01-15T17:45:00.000Z
or milliseconds since 1. January 1970 00:00:00 UTC.
Returned dates (e.g. in plans and stops) are always specified as IETF-compliant RFC 2822 time stamp in UTC.
One or more couriers with their vehicle are required to create route plans. Each courier object contains a vehicle which is used by the courier.
Couriers always need a working time window, a vehicle and a start address:
Field | Type | Description |
---|---|---|
workingTimeFrom | String/Date | Courier working time start |
workingTimeUntil | String/Date | Courier working time end |
startAddress | Address | Courier/Vehicle start address |
vehicle | Vehicle | Vehicle object - see below |
Field | Type | Description | Default value |
---|---|---|---|
endAddress | Address | Courier/Vehicle end address at which the vehicle must finish its tour (e.g a depot). | null |
tourDescription | String | Tour description. Can be used to identify a specific courier/plan | <Empty string> |
firstName | String | Courier first name. Can be used to identify a specific courier/plan | <Empty string> |
lastName | String | Courier last name. Can be used to identify a specific courier/plan | <Empty string> |
skills | String[] | List of skills. Courier can serve orders with matching skills | [] |
costPerHour | Number | Cost per hour | 12.50 € |
serviceTimeFunction | String/ENUM | Service time function for this courier. Only preconfigured Values can be used | DEFAULT |
breakNeededAfterMinutes | Integer | Setting driving and rest periods. After how many minutes of driving time must a break be taken? | 0 (no break needed) |
breakDurationMinutes | Integer | How many minutes does a break last? | 0 (no break needed) |
The type defines the infrastructure the vhicle is driving on as well as the driving times on the infrastructure.
Field | Type | Description |
---|---|---|
type | String/ENUM | Allowed values: "CAR" , "TRUCK" , "BIKE" |
Field | Type | Description | Default value |
---|---|---|---|
capacity | Integer | Vehicle capacity | 0 (unlimited) |
maxNoOfStoringPlaces | Number | Available storing places in the vehicle | 0 (unlimited) |
costPerKM | Number | Cost per kilometer in Euro | 0.20 € |
costPerDay | Number | Cost per day in Euro | 20.00 € |
size | Object | Size of vehicle. Object with properties width , height , length (Number) |
{ "width": 0, "height": 0, "length": 0 } (unlimited) |
licensePlate | String | Vehicle license plate. Can be used to identify a specific vehicle | <Empty string> |
{
"workingTimeFrom": "2018-01-01T09:00:00.000Z",
"workingTimeUntil": "2018-01-01T17:00:00.000Z",
"startAddress": {
"street": "Fahrenheitstraße",
"number": "1",
"postalcode": 28359,
"city": "Bremen",
"locationLat": 53.10837,
"locationLon": 8.848045,
"name": "XTL"
},
"endAddress": {
"street": "Fahrenheitstraße",
"number": "1",
"postalcode": 28359,
"city": "Bremen",
"locationLat": 53.10837,
"locationLon": 8.848045,
"name": "XTL"
},
"vehicle": {
"type": "CAR"
}
}
Field | Type | Description |
---|---|---|
pickupTimeFrom | String/Date | Earliest pickup time |
pickupTimeUntil | String/Date | Latest pickup time |
pickupAddress | Address | Pickup address |
deliveryTimeFrom | String/Date | Earliest delivery time |
deliveryTimeUntil | String/Date | Latest delivery time |
deliveryAddress | Address | Delivery address |
You can leave out all pickup related fields for delivery only orders.
{
"pickupTimeFrom": "2018-01-01T10:00:00.000Z",
"pickupTimeUntil": "2018-01-01T16:00:00.000Z",
"deliveryTimeFrom": "2018-01-01T10:00:00.000Z",
"deliveryTimeUntil": "2018-01-01T16:00:00.000Z",
"pickupAddress": {
"street": "Fahrenheitstraße",
"number": "1",
"postalcode": 28359,
"city": "Bremen",
"locationLat": 53.10837,
"locationLon": 8.848045,
"name": "XTL"
},
"deliveryAddress": {
"street": "Wiener Straße",
"number": "13",
"postalcode": 28359,
"city": "Bremen",
"locationLat": 53.110527,
"locationLon": 8.848950,
"name": "Max Mustermann"
}
}
{
"deliveryTimeFrom": "2018-01-01T10:00:00.000Z",
"deliveryTimeUntil": "2018-01-01T16:00:00.000Z",
"deliveryAddress": {
"street": "Wiener Straße",
"number": "13",
"postalcode": 28359,
"city": "Bremen",
"locationLat": 53.110527,
"locationLon": 8.848950,
"name": "Max Mustermann"
}
}
Field | Type | Description | Default value |
---|---|---|---|
name | String | Descriptive order name | <Empty string> |
priority | Boolean | Should this order be processed with priority? | false |
skills | String[] | List of skills. Only couriers with corresponding skills can transport this order. | [] |
pickupHandlingTime | Number | Order specific handling time on pickup in seconds which is added to the general servcie time (servcie-time-function as well as location based service time) | 0 |
pickupSoftTimeWindow | Number | Pickup soft time window in seconds. The soft-time window is only used if orders cannot be served within the general time window | 0 |
deliveryHandlingTime | Number | Order specific handling time on delivery in seconds which is added to the general servcie time (servcie-time-function as well as location based service time) | 0 |
deliverySoftTimeWindow | Number | Delivery soft time window in seconds. The soft-time window is only used if orders cannot be served within the general time window | 0 |
note | String | Note | <Empty string> |
packingUnits | PackingUnit[] | List of packing units | See below |
Packing units represent the transported goods or colli.
Fields:
Field | Type | Description | |
---|---|---|---|
type | String | Packing unit type | |
length | Integer | Packing unit length | |
width | Integer | Packing unit width | |
height | Integer | Packing unit height | |
amount | Integer | How many packages/goods do belong to this packing unit? | |
weight | Integer | Packing unit weight | |
noOfStoringPlaces | Number | How many storing places does the packing unit require? Will be weighed against the available storing places of the vehicle | |
trackingId | String | Optional id to track this packing unit |
Note: We recommend using base units like kilogram and centimeter for the packing unit properties weight
, length
, width
and height
, although other units can be used as long as the unit matches the units used in vehicles.
Default Packing Units:
[{
"type": "NORMAL_PACKAGE",
"length": 0,
"height": 0,
"width": 0,
"amount": 0,
"weight": 0,
"noOfStoringPlaces": 0,
"trackingId": "",
}]
Field | Type | Description |
---|---|---|
scenario | Object | Should be ignored for static route planning |
plans | Plan[] | List of Plans. One route plan for each courier |
orders | Object | Object with unserved and unservable orders |
orders.unserved | Order[] | Unserved orders. See below for a detailed description |
orders.unservable | Order[] | Unservable orders. See below for a detailed description |
Each plan represents one courier/vehicle and their tour. The plan contains stops in chronological order, which in turn contain orders that have to be picked up or delivered.
Field | Type | Description |
---|---|---|
workingTime | Number | Courier working time in hours |
drivingTime | Number | Courier driving time (time on the road) in hours |
distance | Number | Distance of the route in kilometer |
cost | Number | Tour cost. Calculated from courier costPerHour and vehicle costPerKm and costPerDay |
warnings | Warning[] | Plan warnings are not relevant in static planning |
courier | Courier | The courier to whom the plan belongs to |
dailyMetaData | DailyMetaData[] | Attributes workingTime , drivingTime , distance and cost divided by days. Useful for multi day plans |
stops | Stop[] | List of stops in chronological order |
Field | Type | Description |
---|---|---|
kind | String/ENUM | Stop type. Possible values: PICKUP , DELIVERY , BREAK , DEPOT , END |
address | Address | Stop address |
eta | String/Date | Estimated time of arrival |
etd | String/Date | Estimated time of departure |
earliestArrivalTime | String/Date | Earliest arrival time according to the orders at this stop |
latestArrivalTime | String/Date | Latest arrival time according to the orders at this stop |
handlingTime | Integer | Calculated handling time for this stop |
warnings | Stop warnings are not relevant in static planning | |
pickupOrders | Order[] | Orders which must be picked up at this stop. Only filled with kind=PICKUP |
deliveryOrders | Order[] | Orders which must be delivered at this stop. Only filled with kind=DELIVERY and kind=DEPOT |
Stops of kind END
or BREAK
do not contain any orders.
The list of unserved orders contains orders that could not be assigned to any courier during the calculation but do not violate any hard constraints. If other orders would be removed, unserved orders could be transported.
The list of unservable orders contains orders that could not be assigned to a courier during the calculation due to constraint violations. Thus, they cannot be transported even if other orders would be removed. Each unservable order contains information about the constraint violation in the unservabilityReason
attribute.
The distinction between TSP, PDP and VRP is made implicitly by the data you provide (orders and couriers/vehicles).
All orders should have the same pickupAddress
to calculate a TSP. The following command can be used to calculate a TSP with orders and couriers from this tsp.json
curl -X POST \
-H "X-Api-Key: 0123456789ABCDEF" \
-H "Content-Type: application/json" \
--data @tsp.json \
https://example.xtl-gmbh.de/planning/static
Use different pickupAddress
for orders to calculate a PDP. The following command can be used to calculate a PDP with orders and couriers from this pdp.json
curl -X POST \
-H "X-Api-Key: 0123456789ABCDEF" \
-H "Content-Type: application/json" \
--data @pdp.json \
https://example.xtl-gmbh.de/planning/static
Add multiple couriers/vehicles to the request to calculate a VRP. The following command can be used to calculate a VRP with orders and couriers from this vrp.json
:
curl -X POST \
-H "X-Api-Key: 0123456789ABCDEF" \
-H "Content-Type: application/json" \
--data @vrp.json \
https://example.xtl-gmbh.de/planning/static