curl --request POST \
--url https://app.kardinal.ai/api/v2/plans \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"resources": [
{
"id": "resource1",
"vehicleProfile": {
"type": "fly",
"kmph": 20
},
"workingTimeWindow": {
"begin": "2026-03-21T08:00:00Z",
"end": "2026-03-21T23:00:00Z"
}
}
],
"orders": [
{
"id": "order-1",
"stops": [
{
"type": "single",
"id": "Balard",
"position": {
"lon": 2.279424,
"lat": 48.835749
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
},
{
"id": "order-2",
"stops": [
{
"type": "single",
"id": "Dauphine",
"position": {
"lon": 2.274264,
"lat": 48.870087
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
},
{
"id": "order-3",
"stops": [
{
"type": "single",
"id": "Station-f",
"position": {
"lon": 2.370564,
"lat": 48.83476
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
}
],
"maxOptimizationDuration": "PT1M"
}
'import requests
url = "https://app.kardinal.ai/api/v2/plans"
payload = {
"resources": [
{
"id": "resource1",
"vehicleProfile": {
"type": "fly",
"kmph": 20
},
"workingTimeWindow": {
"begin": "2026-03-21T08:00:00Z",
"end": "2026-03-21T23:00:00Z"
}
}
],
"orders": [
{
"id": "order-1",
"stops": [
{
"type": "single",
"id": "Balard",
"position": {
"lon": 2.279424,
"lat": 48.835749
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
},
{
"id": "order-2",
"stops": [
{
"type": "single",
"id": "Dauphine",
"position": {
"lon": 2.274264,
"lat": 48.870087
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
},
{
"id": "order-3",
"stops": [
{
"type": "single",
"id": "Station-f",
"position": {
"lon": 2.370564,
"lat": 48.83476
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
}
],
"maxOptimizationDuration": "PT1M"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
resources: [
{
id: 'resource1',
vehicleProfile: {type: 'fly', kmph: 20},
workingTimeWindow: {begin: '2026-03-21T08:00:00Z', end: '2026-03-21T23:00:00Z'}
}
],
orders: [
{
id: 'order-1',
stops: [
{
type: 'single',
id: 'Balard',
position: {lon: 2.279424, lat: 48.835749},
kind: 'pickup',
operationDuration: 'PT5M30S'
}
]
},
{
id: 'order-2',
stops: [
{
type: 'single',
id: 'Dauphine',
position: {lon: 2.274264, lat: 48.870087},
kind: 'pickup',
operationDuration: 'PT5M30S'
}
]
},
{
id: 'order-3',
stops: [
{
type: 'single',
id: 'Station-f',
position: {lon: 2.370564, lat: 48.83476},
kind: 'pickup',
operationDuration: 'PT5M30S'
}
]
}
],
maxOptimizationDuration: 'PT1M'
})
};
fetch('https://app.kardinal.ai/api/v2/plans', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.kardinal.ai/api/v2/plans",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'resources' => [
[
'id' => 'resource1',
'vehicleProfile' => [
'type' => 'fly',
'kmph' => 20
],
'workingTimeWindow' => [
'begin' => '2026-03-21T08:00:00Z',
'end' => '2026-03-21T23:00:00Z'
]
]
],
'orders' => [
[
'id' => 'order-1',
'stops' => [
[
'type' => 'single',
'id' => 'Balard',
'position' => [
'lon' => 2.279424,
'lat' => 48.835749
],
'kind' => 'pickup',
'operationDuration' => 'PT5M30S'
]
]
],
[
'id' => 'order-2',
'stops' => [
[
'type' => 'single',
'id' => 'Dauphine',
'position' => [
'lon' => 2.274264,
'lat' => 48.870087
],
'kind' => 'pickup',
'operationDuration' => 'PT5M30S'
]
]
],
[
'id' => 'order-3',
'stops' => [
[
'type' => 'single',
'id' => 'Station-f',
'position' => [
'lon' => 2.370564,
'lat' => 48.83476
],
'kind' => 'pickup',
'operationDuration' => 'PT5M30S'
]
]
]
],
'maxOptimizationDuration' => 'PT1M'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.kardinal.ai/api/v2/plans"
payload := strings.NewReader("{\n \"resources\": [\n {\n \"id\": \"resource1\",\n \"vehicleProfile\": {\n \"type\": \"fly\",\n \"kmph\": 20\n },\n \"workingTimeWindow\": {\n \"begin\": \"2026-03-21T08:00:00Z\",\n \"end\": \"2026-03-21T23:00:00Z\"\n }\n }\n ],\n \"orders\": [\n {\n \"id\": \"order-1\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Balard\",\n \"position\": {\n \"lon\": 2.279424,\n \"lat\": 48.835749\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n },\n {\n \"id\": \"order-2\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Dauphine\",\n \"position\": {\n \"lon\": 2.274264,\n \"lat\": 48.870087\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n },\n {\n \"id\": \"order-3\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Station-f\",\n \"position\": {\n \"lon\": 2.370564,\n \"lat\": 48.83476\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n }\n ],\n \"maxOptimizationDuration\": \"PT1M\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.kardinal.ai/api/v2/plans")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"resources\": [\n {\n \"id\": \"resource1\",\n \"vehicleProfile\": {\n \"type\": \"fly\",\n \"kmph\": 20\n },\n \"workingTimeWindow\": {\n \"begin\": \"2026-03-21T08:00:00Z\",\n \"end\": \"2026-03-21T23:00:00Z\"\n }\n }\n ],\n \"orders\": [\n {\n \"id\": \"order-1\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Balard\",\n \"position\": {\n \"lon\": 2.279424,\n \"lat\": 48.835749\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n },\n {\n \"id\": \"order-2\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Dauphine\",\n \"position\": {\n \"lon\": 2.274264,\n \"lat\": 48.870087\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n },\n {\n \"id\": \"order-3\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Station-f\",\n \"position\": {\n \"lon\": 2.370564,\n \"lat\": 48.83476\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n }\n ],\n \"maxOptimizationDuration\": \"PT1M\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.kardinal.ai/api/v2/plans")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"resources\": [\n {\n \"id\": \"resource1\",\n \"vehicleProfile\": {\n \"type\": \"fly\",\n \"kmph\": 20\n },\n \"workingTimeWindow\": {\n \"begin\": \"2026-03-21T08:00:00Z\",\n \"end\": \"2026-03-21T23:00:00Z\"\n }\n }\n ],\n \"orders\": [\n {\n \"id\": \"order-1\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Balard\",\n \"position\": {\n \"lon\": 2.279424,\n \"lat\": 48.835749\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n },\n {\n \"id\": \"order-2\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Dauphine\",\n \"position\": {\n \"lon\": 2.274264,\n \"lat\": 48.870087\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n },\n {\n \"id\": \"order-3\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Station-f\",\n \"position\": {\n \"lon\": 2.370564,\n \"lat\": 48.83476\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n }\n ],\n \"maxOptimizationDuration\": \"PT1M\"\n}"
response = http.request(request)
puts response.read_body{
"item": {
"id": "4cbd0ab8-282c-4b30-b981-29e1ed8a2016",
"agencyId": "BLD1234567_production",
"version": 1,
"status": {
"waitingRoom": {
"waitingVersion": 1,
"runningVersion": 1
},
"creation": {
"waitingVersion": 1,
"runningVersion": 1
},
"optimization": {
"waitingVersion": 1,
"runningVersion": 1
}
},
"resources": [
{
"id": "resource1",
"vehicleProfile": {
"type": "fly",
"kmph": 20
},
"workingTimeWindow": {
"begin": "2026-03-21T08:00:00Z",
"end": "2026-03-21T23:00:00Z"
}
}
],
"orders": [
{
"id": "order-1",
"stops": [
{
"type": "single",
"id": "Balard",
"position": {
"lon": 2.279424,
"lat": 48.835749
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
},
{
"id": "order-2",
"stops": [
{
"type": "single",
"id": "Dauphine",
"position": {
"lon": 2.274264,
"lat": 48.870087
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
},
{
"id": "order-3",
"stops": [
{
"type": "single",
"id": "Station-f",
"position": {
"lon": 2.370564,
"lat": 48.83476
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
}
]
},
"agencyId": "BLD1234567_production",
"planId": "4cbd0ab8-282c-4b30-b981-29e1ed8a2016",
"planVersion": 1
}Create a plan
The plan id is generated by the service: an id sent in the payload is ignored and replaced by a generated one. Use the id returned in the response to address the plan on the other endpoints.
This operation consumes credits — see Pricing and credits.
curl --request POST \
--url https://app.kardinal.ai/api/v2/plans \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"resources": [
{
"id": "resource1",
"vehicleProfile": {
"type": "fly",
"kmph": 20
},
"workingTimeWindow": {
"begin": "2026-03-21T08:00:00Z",
"end": "2026-03-21T23:00:00Z"
}
}
],
"orders": [
{
"id": "order-1",
"stops": [
{
"type": "single",
"id": "Balard",
"position": {
"lon": 2.279424,
"lat": 48.835749
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
},
{
"id": "order-2",
"stops": [
{
"type": "single",
"id": "Dauphine",
"position": {
"lon": 2.274264,
"lat": 48.870087
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
},
{
"id": "order-3",
"stops": [
{
"type": "single",
"id": "Station-f",
"position": {
"lon": 2.370564,
"lat": 48.83476
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
}
],
"maxOptimizationDuration": "PT1M"
}
'import requests
url = "https://app.kardinal.ai/api/v2/plans"
payload = {
"resources": [
{
"id": "resource1",
"vehicleProfile": {
"type": "fly",
"kmph": 20
},
"workingTimeWindow": {
"begin": "2026-03-21T08:00:00Z",
"end": "2026-03-21T23:00:00Z"
}
}
],
"orders": [
{
"id": "order-1",
"stops": [
{
"type": "single",
"id": "Balard",
"position": {
"lon": 2.279424,
"lat": 48.835749
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
},
{
"id": "order-2",
"stops": [
{
"type": "single",
"id": "Dauphine",
"position": {
"lon": 2.274264,
"lat": 48.870087
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
},
{
"id": "order-3",
"stops": [
{
"type": "single",
"id": "Station-f",
"position": {
"lon": 2.370564,
"lat": 48.83476
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
}
],
"maxOptimizationDuration": "PT1M"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
resources: [
{
id: 'resource1',
vehicleProfile: {type: 'fly', kmph: 20},
workingTimeWindow: {begin: '2026-03-21T08:00:00Z', end: '2026-03-21T23:00:00Z'}
}
],
orders: [
{
id: 'order-1',
stops: [
{
type: 'single',
id: 'Balard',
position: {lon: 2.279424, lat: 48.835749},
kind: 'pickup',
operationDuration: 'PT5M30S'
}
]
},
{
id: 'order-2',
stops: [
{
type: 'single',
id: 'Dauphine',
position: {lon: 2.274264, lat: 48.870087},
kind: 'pickup',
operationDuration: 'PT5M30S'
}
]
},
{
id: 'order-3',
stops: [
{
type: 'single',
id: 'Station-f',
position: {lon: 2.370564, lat: 48.83476},
kind: 'pickup',
operationDuration: 'PT5M30S'
}
]
}
],
maxOptimizationDuration: 'PT1M'
})
};
fetch('https://app.kardinal.ai/api/v2/plans', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.kardinal.ai/api/v2/plans",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'resources' => [
[
'id' => 'resource1',
'vehicleProfile' => [
'type' => 'fly',
'kmph' => 20
],
'workingTimeWindow' => [
'begin' => '2026-03-21T08:00:00Z',
'end' => '2026-03-21T23:00:00Z'
]
]
],
'orders' => [
[
'id' => 'order-1',
'stops' => [
[
'type' => 'single',
'id' => 'Balard',
'position' => [
'lon' => 2.279424,
'lat' => 48.835749
],
'kind' => 'pickup',
'operationDuration' => 'PT5M30S'
]
]
],
[
'id' => 'order-2',
'stops' => [
[
'type' => 'single',
'id' => 'Dauphine',
'position' => [
'lon' => 2.274264,
'lat' => 48.870087
],
'kind' => 'pickup',
'operationDuration' => 'PT5M30S'
]
]
],
[
'id' => 'order-3',
'stops' => [
[
'type' => 'single',
'id' => 'Station-f',
'position' => [
'lon' => 2.370564,
'lat' => 48.83476
],
'kind' => 'pickup',
'operationDuration' => 'PT5M30S'
]
]
]
],
'maxOptimizationDuration' => 'PT1M'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.kardinal.ai/api/v2/plans"
payload := strings.NewReader("{\n \"resources\": [\n {\n \"id\": \"resource1\",\n \"vehicleProfile\": {\n \"type\": \"fly\",\n \"kmph\": 20\n },\n \"workingTimeWindow\": {\n \"begin\": \"2026-03-21T08:00:00Z\",\n \"end\": \"2026-03-21T23:00:00Z\"\n }\n }\n ],\n \"orders\": [\n {\n \"id\": \"order-1\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Balard\",\n \"position\": {\n \"lon\": 2.279424,\n \"lat\": 48.835749\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n },\n {\n \"id\": \"order-2\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Dauphine\",\n \"position\": {\n \"lon\": 2.274264,\n \"lat\": 48.870087\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n },\n {\n \"id\": \"order-3\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Station-f\",\n \"position\": {\n \"lon\": 2.370564,\n \"lat\": 48.83476\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n }\n ],\n \"maxOptimizationDuration\": \"PT1M\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.kardinal.ai/api/v2/plans")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"resources\": [\n {\n \"id\": \"resource1\",\n \"vehicleProfile\": {\n \"type\": \"fly\",\n \"kmph\": 20\n },\n \"workingTimeWindow\": {\n \"begin\": \"2026-03-21T08:00:00Z\",\n \"end\": \"2026-03-21T23:00:00Z\"\n }\n }\n ],\n \"orders\": [\n {\n \"id\": \"order-1\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Balard\",\n \"position\": {\n \"lon\": 2.279424,\n \"lat\": 48.835749\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n },\n {\n \"id\": \"order-2\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Dauphine\",\n \"position\": {\n \"lon\": 2.274264,\n \"lat\": 48.870087\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n },\n {\n \"id\": \"order-3\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Station-f\",\n \"position\": {\n \"lon\": 2.370564,\n \"lat\": 48.83476\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n }\n ],\n \"maxOptimizationDuration\": \"PT1M\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.kardinal.ai/api/v2/plans")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"resources\": [\n {\n \"id\": \"resource1\",\n \"vehicleProfile\": {\n \"type\": \"fly\",\n \"kmph\": 20\n },\n \"workingTimeWindow\": {\n \"begin\": \"2026-03-21T08:00:00Z\",\n \"end\": \"2026-03-21T23:00:00Z\"\n }\n }\n ],\n \"orders\": [\n {\n \"id\": \"order-1\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Balard\",\n \"position\": {\n \"lon\": 2.279424,\n \"lat\": 48.835749\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n },\n {\n \"id\": \"order-2\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Dauphine\",\n \"position\": {\n \"lon\": 2.274264,\n \"lat\": 48.870087\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n },\n {\n \"id\": \"order-3\",\n \"stops\": [\n {\n \"type\": \"single\",\n \"id\": \"Station-f\",\n \"position\": {\n \"lon\": 2.370564,\n \"lat\": 48.83476\n },\n \"kind\": \"pickup\",\n \"operationDuration\": \"PT5M30S\"\n }\n ]\n }\n ],\n \"maxOptimizationDuration\": \"PT1M\"\n}"
response = http.request(request)
puts response.read_body{
"item": {
"id": "4cbd0ab8-282c-4b30-b981-29e1ed8a2016",
"agencyId": "BLD1234567_production",
"version": 1,
"status": {
"waitingRoom": {
"waitingVersion": 1,
"runningVersion": 1
},
"creation": {
"waitingVersion": 1,
"runningVersion": 1
},
"optimization": {
"waitingVersion": 1,
"runningVersion": 1
}
},
"resources": [
{
"id": "resource1",
"vehicleProfile": {
"type": "fly",
"kmph": 20
},
"workingTimeWindow": {
"begin": "2026-03-21T08:00:00Z",
"end": "2026-03-21T23:00:00Z"
}
}
],
"orders": [
{
"id": "order-1",
"stops": [
{
"type": "single",
"id": "Balard",
"position": {
"lon": 2.279424,
"lat": 48.835749
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
},
{
"id": "order-2",
"stops": [
{
"type": "single",
"id": "Dauphine",
"position": {
"lon": 2.274264,
"lat": 48.870087
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
},
{
"id": "order-3",
"stops": [
{
"type": "single",
"id": "Station-f",
"position": {
"lon": 2.370564,
"lat": 48.83476
},
"kind": "pickup",
"operationDuration": "PT5M30S"
}
]
}
]
},
"agencyId": "BLD1234567_production",
"planId": "4cbd0ab8-282c-4b30-b981-29e1ed8a2016",
"planVersion": 1
}Authorizations
JWT bearer token, sent as Authorization: Bearer <token>. Two kinds of token are accepted:
- A session token (1 hour), obtained through the interactive Console login flow. Used to sign in to the Console; not meant to be used against this API.
- A long-term API token (366 days), obtained once via the Console and meant to be stored by your integration. It is the credential recommended for backend use, since it does not depend on repeating the interactive login flow.
Body
The plan to create.
A full plan for a date and agency, with its associated resources, orders, constraints, and so on.
Resources (vehicles, drivers, or vehicle-and-driver pairs) available to serve this plan's orders.
Default. Capped at 250 entries per plan — see Limits and quotas.
Show child attributes
Show child attributes
Free-form metadata map (string to string), with no effect on optimization. Returned unchanged on the object and in the solution. Typical uses: a driver's name, a vehicle's plate, a customer name or address, a client reference.
Show child attributes
Show child attributes
{
"plate": "AB-123-CD",
"driverName": "Jane Doe"
}
Orders (individual stops or groups of stops) to be served by this plan.
Default. Capped at 3,000 entries per plan — see Limits and quotas.
Show child attributes
Show child attributes
Additional operation time for a resource and a stop, according to tags (pairs of tags must be unique).
Show child attributes
Show child attributes
Policies to remove the operation durations, by resource tag.
Show child attributes
Show child attributes
{
"trailer": [
{
"policy": "withoutFirstOperationDuration",
"stopTags": ["access:parking33"]
}
]
}
Extra constraints layered on top of resources' and orders' own fields, such as forbidden assignments or capacity ceilings shared across a group of stops.
additionalConstraints scope. At every stop of the tour, at least one of the listed capacities must be at or below its given threshold — an OR across the listed capacities, checked at each stop, not a requirement that they all hold together.
When to use. For sequencing stop types or validating multi-compartment configurations. If the tour has not, at each stop, one of its capacities lower than or equal to the given limit, the tour is invalid.
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
- Option 6
- Option 7
Show child attributes
Show child attributes
List of global constraints to be satisfied by the returned solution.
Show child attributes
Show child attributes
Fixed extra duration charged once, before the first of a group of consecutive stops sharing a tag, in ISO 8601 duration format.
When to use. For a cost paid once per visit to a tagged location, such as a 30-minute dock access time. For a cost paid on every stop regardless of what came before it, use a stop's own
operationDurationinstead.
Show child attributes
Show child attributes
{ "access:parking33": "PT5M" }
Target maximum number of resources physically present at the same time at stops sharing a tag.
When to use. To model a shared bottleneck resource such as a depot with a limited number of loading docks, or a cross-dock with limited simultaneous capacity, for example limiting a two-dock depot to 2 resources at once.
Modelling pitfall. A soft limit, not a hard cap: overruns are minimized by the
minimizeOverOverlappingCapacitiesOnStopsobjective, so how firmly the engine keeps to the limit depends on that objective's position inobjectives, and it has no effect if that objective is left out.
Show child attributes
Show child attributes
{ "capa:bat22": 3 }
Sequence-dependent changeover times to add whenever a resource travels directly between two stops carrying a matching pair of tags.
Show child attributes
Show child attributes
Objectives the engine optimizes for this plan; see PlanObjectives for how priority order drives trade-offs.
Name of a built-in objective, used as an entry in PlanObjectives.
- maximizeMandatoryStops: Maximizes the number of non-optional stops actually planned.
- minimizeDelay: Minimizes the sum of delays against stops'
preferredTimeWindows; only lateness counts, never earliness. - minimizeCosts: Minimizes the plan's total cost, as defined by each resource's
cost. - minimizeResources: Favours using fewer resources over spreading stops across more of them.
- minimizeOverOverlappingCapacitiesOnStops: Minimizes how far the limits set in
Plan.overlappingCapacitiesByStopTagare exceeded, in resources simultaneously present beyond the limit. - maximizeOptionalStops: Maximizes the number of optional stops planned in addition to mandatory ones.
- maximizePreferredStops: Maximizes stops matched to a resource's
preferredStopTags. - minimizeLargestTourDuration: Minimizes the working duration of the single longest tour across the fleet (travel, service, and waiting time), balancing workload between resources.
- minimizeWorkingDuration: Minimizes the total working duration summed across every tour, waiting time included.
- minimizeDistance: Minimizes the total distance travelled summed across every tour.
- minimizeEarlyLoadings: Minimizes early loadings; pairs with a resource's
avoidEarlyLoadingsdeclarations.
maximizeMandatoryStops, minimizeDelay, minimizeCosts, minimizeResources, minimizeOverOverlappingCapacitiesOnStops, maximizeOptionalStops, maximizePreferredStops, minimizeLargestTourDuration, minimizeWorkingDuration, minimizeDistance, minimizeEarlyLoadings Maximum time the engine is allowed to search, in ISO 8601 duration format. The engine stops early on its own once it stops finding improvements, so an overly generous value costs only a longer worst case, never a worse solution.
Default. If omitted, 5 seconds for the sandbox agency and 15 minutes for the production agency. A value exceeding the agency's maximum (5 seconds for the sandbox, 6 hours for production by default) is clamped to it, with a warning in the response; see Limits and quotas.
Modelling pitfall. A good solution typically takes about
PT10Sfor 1 resource and 15 stops,PT2Mfor 5 resources and 100 stops,PT10Mfor 30 resources and 800 stops, andPT30Mfor 45 resources and 3,000 stops. These values are indicative, not a guarantee: a plan can converge faster or slower depending on its constraints, and past about 800 stops the 15-minute production default is too short. Size this value against your own data (see Handling large volumes).
^P(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$"PT1H"
Time zone this plan's resources and stops are scheduled in.
"Europe/Paris"
Allows resources to depart later than the earliest feasible moment in their workingTimeWindow, when doing so does not hurt the objectives.
Default.
false: resources always leave as early as possible.
Pools a capacity key across all of a resource's assigned stops for the whole tour, instead of only within a single order.
When to use. For several different orders assigned to the same resource that draw down and top back up the same running balance, such as a limited stock of reusable equipment. Pair it with an
atLeastOneValidCapacityadditional constraint whenever the rule is stronger than "never exceed the ceiling at any single point".
Default.
false: capacities only interact within a single order.
Thresholds for capacities below which a resource is considered "empty" for empty distance calculation, grouped by resource tag. A resource is "empty" (kilometres travelled count as empty distance) when all capacities are at or below their threshold. The wildcard tag "*" matches all resources.
Show child attributes
Show child attributes
{
"heavy": { "weight": 150, "volume": 75 },
"*": { "weight": 50 }
}
Early loading declarations grouped by resource tag. The wildcard tag "*" matches all resources. Each entry identifies a stop tag and optional capacities used to compute the minimizeEarlyLoadings objective.
Show child attributes
Show child attributes
{
"*": [
{
"stopTag": "depot1",
"capacities": ["weight", "volume"]
}
],
"heavy": [{ "stopTag": "warehouse" }]
}
Optional CO2 emission calculation parameters grouped by resource tag. Each value is a Cost-shaped object. Applies to every resource carrying the corresponding tag. When set, the resulting emissions are reported on tours as CO2Emission and aggregated on the solution as CO2Emission. If a resource matches multiple tags, only its first declared matching tag is used. Overridden by the resource-level declaration.
Show child attributes
Show child attributes
{
"resTag2": {
"km": { "costCoeff": 0.55 },
"costPerCapacityPerTravelledKm": { "weight": { "costCoeff": 0.2 } }
}
}
Response
Plan response created.
A single plan wrapped with its identifying metadata, as returned by the plan-retrieval endpoints.
The plan itself.
Show child attributes
Show child attributes
Identifier of the Kardinal tenant/account the plan is scoped to, derived automatically from the access token used to make the request.
Modelling pitfall. Not a physical-depot or site partition key. A single fleet based at several physical depots is still one
Plan; do not split it into severalPlanobjects just because resources have differentdeparture/arrivalpositions.
^BLD[0-9]{7}_[a-zA-Z0-9-._~:@!$,]+$"BLD1234567_production"
The plan id.
^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"4cbd0ab8-282c-4b30-b981-29e1ed8a2016"
The plan version.
x >= 142
Amendments applied while processing this request, if any.
Show child attributes
Show child attributes
Was this page helpful?

