curl --request POST \
--url https://api.kiteml.com/v1/training_runs \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"dataset": {
"uri": "<string>"
},
"policies": [
"<string>"
],
"hardware_tier": "gcp_gpu_t4",
"robot": "<string>",
"config": {
"steps": 500000,
"batch_size": 512,
"save_freq": 2,
"eval_enabled": false
},
"cameras": {
"rename": {}
},
"output": {
"push_to_hub": false,
"hf_repo_id": "<string>"
},
"webhook_metadata": {}
}
'import requests
url = "https://api.kiteml.com/v1/training_runs"
payload = {
"dataset": { "uri": "<string>" },
"policies": ["<string>"],
"hardware_tier": "gcp_gpu_t4",
"robot": "<string>",
"config": {
"steps": 500000,
"batch_size": 512,
"save_freq": 2,
"eval_enabled": False
},
"cameras": { "rename": {} },
"output": {
"push_to_hub": False,
"hf_repo_id": "<string>"
},
"webhook_metadata": {}
}
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({
dataset: {uri: '<string>'},
policies: ['<string>'],
hardware_tier: 'gcp_gpu_t4',
robot: '<string>',
config: {steps: 500000, batch_size: 512, save_freq: 2, eval_enabled: false},
cameras: {rename: {}},
output: {push_to_hub: false, hf_repo_id: '<string>'},
webhook_metadata: {}
})
};
fetch('https://api.kiteml.com/v1/training_runs', 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://api.kiteml.com/v1/training_runs",
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([
'dataset' => [
'uri' => '<string>'
],
'policies' => [
'<string>'
],
'hardware_tier' => 'gcp_gpu_t4',
'robot' => '<string>',
'config' => [
'steps' => 500000,
'batch_size' => 512,
'save_freq' => 2,
'eval_enabled' => false
],
'cameras' => [
'rename' => [
]
],
'output' => [
'push_to_hub' => false,
'hf_repo_id' => '<string>'
],
'webhook_metadata' => [
]
]),
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://api.kiteml.com/v1/training_runs"
payload := strings.NewReader("{\n \"dataset\": {\n \"uri\": \"<string>\"\n },\n \"policies\": [\n \"<string>\"\n ],\n \"hardware_tier\": \"gcp_gpu_t4\",\n \"robot\": \"<string>\",\n \"config\": {\n \"steps\": 500000,\n \"batch_size\": 512,\n \"save_freq\": 2,\n \"eval_enabled\": false\n },\n \"cameras\": {\n \"rename\": {}\n },\n \"output\": {\n \"push_to_hub\": false,\n \"hf_repo_id\": \"<string>\"\n },\n \"webhook_metadata\": {}\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://api.kiteml.com/v1/training_runs")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"dataset\": {\n \"uri\": \"<string>\"\n },\n \"policies\": [\n \"<string>\"\n ],\n \"hardware_tier\": \"gcp_gpu_t4\",\n \"robot\": \"<string>\",\n \"config\": {\n \"steps\": 500000,\n \"batch_size\": 512,\n \"save_freq\": 2,\n \"eval_enabled\": false\n },\n \"cameras\": {\n \"rename\": {}\n },\n \"output\": {\n \"push_to_hub\": false,\n \"hf_repo_id\": \"<string>\"\n },\n \"webhook_metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kiteml.com/v1/training_runs")
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 \"dataset\": {\n \"uri\": \"<string>\"\n },\n \"policies\": [\n \"<string>\"\n ],\n \"hardware_tier\": \"gcp_gpu_t4\",\n \"robot\": \"<string>\",\n \"config\": {\n \"steps\": 500000,\n \"batch_size\": 512,\n \"save_freq\": 2,\n \"eval_enabled\": false\n },\n \"cameras\": {\n \"rename\": {}\n },\n \"output\": {\n \"push_to_hub\": false,\n \"hf_repo_id\": \"<string>\"\n },\n \"webhook_metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"object": "list",
"data": [
{
"cameras": {},
"completed_at": "2026-09-27T15:41:52.664301+00:00",
"config": {
"batch_size": 8,
"eval_enabled": false,
"save_freq": 1000,
"steps": 30000
},
"created_at": "2026-09-27T14:02:11.482913+00:00",
"dataset": {
"uri": "lerobot/svla_so101_pickplace"
},
"eval": {},
"group_id": "5f0c2e9a7b1d4c3e8f6a2b9d0c1e7f35",
"hardware_tier": "gcp_gpu_t4",
"id": "trn_01K65Z3N8Q4W2H7R9T6Y1B3C5D",
"metrics": {
"loss": 0.043,
"max_steps": 30000,
"step": 30000
},
"object": "training_run",
"output": {
"checkpoint_count": 30,
"hf_push_status": "ok",
"hf_repo_id": "your-hf-user/act-pickplace",
"hf_url": "https://huggingface.co/your-hf-user/act-pickplace",
"latest_checkpoint": {
"artifact_uri": "gs://example-bucket/jobs/7c1e9f0a2b3d4e5f8a9b0c1d2e3f4a5b/artifacts/lerobot/checkpoints/030000/pretrained_model/",
"created_at": "2026-09-27T15:38:40.120394+00:00",
"download_url": "/v1/training_runs/trn_01K65Z3N8Q4W2H7R9T6Y1B3C5D/checkpoints/30000/download",
"object": "training_checkpoint",
"step": 30000
}
},
"phase": "completed",
"policy": "act",
"progress": 1,
"robot": "so101_follower",
"started_at": "2026-09-27T14:02:13.107554+00:00",
"status": "succeeded",
"status_message": "Completed",
"tokens": {
"charged": 500,
"refunded": 0
},
"webhook_metadata": {
"ref": "nightly-42"
}
}
],
"has_more": true,
"next_cursor": "<string>"
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}Create Training Runs
Launch one run per policy. Returns a list of resources, one per policy.
Everything is validated across the whole batch before anything launches, so a request either starts all of its runs or none of them.
curl --request POST \
--url https://api.kiteml.com/v1/training_runs \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"dataset": {
"uri": "<string>"
},
"policies": [
"<string>"
],
"hardware_tier": "gcp_gpu_t4",
"robot": "<string>",
"config": {
"steps": 500000,
"batch_size": 512,
"save_freq": 2,
"eval_enabled": false
},
"cameras": {
"rename": {}
},
"output": {
"push_to_hub": false,
"hf_repo_id": "<string>"
},
"webhook_metadata": {}
}
'import requests
url = "https://api.kiteml.com/v1/training_runs"
payload = {
"dataset": { "uri": "<string>" },
"policies": ["<string>"],
"hardware_tier": "gcp_gpu_t4",
"robot": "<string>",
"config": {
"steps": 500000,
"batch_size": 512,
"save_freq": 2,
"eval_enabled": False
},
"cameras": { "rename": {} },
"output": {
"push_to_hub": False,
"hf_repo_id": "<string>"
},
"webhook_metadata": {}
}
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({
dataset: {uri: '<string>'},
policies: ['<string>'],
hardware_tier: 'gcp_gpu_t4',
robot: '<string>',
config: {steps: 500000, batch_size: 512, save_freq: 2, eval_enabled: false},
cameras: {rename: {}},
output: {push_to_hub: false, hf_repo_id: '<string>'},
webhook_metadata: {}
})
};
fetch('https://api.kiteml.com/v1/training_runs', 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://api.kiteml.com/v1/training_runs",
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([
'dataset' => [
'uri' => '<string>'
],
'policies' => [
'<string>'
],
'hardware_tier' => 'gcp_gpu_t4',
'robot' => '<string>',
'config' => [
'steps' => 500000,
'batch_size' => 512,
'save_freq' => 2,
'eval_enabled' => false
],
'cameras' => [
'rename' => [
]
],
'output' => [
'push_to_hub' => false,
'hf_repo_id' => '<string>'
],
'webhook_metadata' => [
]
]),
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://api.kiteml.com/v1/training_runs"
payload := strings.NewReader("{\n \"dataset\": {\n \"uri\": \"<string>\"\n },\n \"policies\": [\n \"<string>\"\n ],\n \"hardware_tier\": \"gcp_gpu_t4\",\n \"robot\": \"<string>\",\n \"config\": {\n \"steps\": 500000,\n \"batch_size\": 512,\n \"save_freq\": 2,\n \"eval_enabled\": false\n },\n \"cameras\": {\n \"rename\": {}\n },\n \"output\": {\n \"push_to_hub\": false,\n \"hf_repo_id\": \"<string>\"\n },\n \"webhook_metadata\": {}\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://api.kiteml.com/v1/training_runs")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"dataset\": {\n \"uri\": \"<string>\"\n },\n \"policies\": [\n \"<string>\"\n ],\n \"hardware_tier\": \"gcp_gpu_t4\",\n \"robot\": \"<string>\",\n \"config\": {\n \"steps\": 500000,\n \"batch_size\": 512,\n \"save_freq\": 2,\n \"eval_enabled\": false\n },\n \"cameras\": {\n \"rename\": {}\n },\n \"output\": {\n \"push_to_hub\": false,\n \"hf_repo_id\": \"<string>\"\n },\n \"webhook_metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kiteml.com/v1/training_runs")
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 \"dataset\": {\n \"uri\": \"<string>\"\n },\n \"policies\": [\n \"<string>\"\n ],\n \"hardware_tier\": \"gcp_gpu_t4\",\n \"robot\": \"<string>\",\n \"config\": {\n \"steps\": 500000,\n \"batch_size\": 512,\n \"save_freq\": 2,\n \"eval_enabled\": false\n },\n \"cameras\": {\n \"rename\": {}\n },\n \"output\": {\n \"push_to_hub\": false,\n \"hf_repo_id\": \"<string>\"\n },\n \"webhook_metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"object": "list",
"data": [
{
"cameras": {},
"completed_at": "2026-09-27T15:41:52.664301+00:00",
"config": {
"batch_size": 8,
"eval_enabled": false,
"save_freq": 1000,
"steps": 30000
},
"created_at": "2026-09-27T14:02:11.482913+00:00",
"dataset": {
"uri": "lerobot/svla_so101_pickplace"
},
"eval": {},
"group_id": "5f0c2e9a7b1d4c3e8f6a2b9d0c1e7f35",
"hardware_tier": "gcp_gpu_t4",
"id": "trn_01K65Z3N8Q4W2H7R9T6Y1B3C5D",
"metrics": {
"loss": 0.043,
"max_steps": 30000,
"step": 30000
},
"object": "training_run",
"output": {
"checkpoint_count": 30,
"hf_push_status": "ok",
"hf_repo_id": "your-hf-user/act-pickplace",
"hf_url": "https://huggingface.co/your-hf-user/act-pickplace",
"latest_checkpoint": {
"artifact_uri": "gs://example-bucket/jobs/7c1e9f0a2b3d4e5f8a9b0c1d2e3f4a5b/artifacts/lerobot/checkpoints/030000/pretrained_model/",
"created_at": "2026-09-27T15:38:40.120394+00:00",
"download_url": "/v1/training_runs/trn_01K65Z3N8Q4W2H7R9T6Y1B3C5D/checkpoints/30000/download",
"object": "training_checkpoint",
"step": 30000
}
},
"phase": "completed",
"policy": "act",
"progress": 1,
"robot": "so101_follower",
"started_at": "2026-09-27T14:02:13.107554+00:00",
"status": "succeeded",
"status_message": "Completed",
"tokens": {
"charged": 500,
"refunded": 0
},
"webhook_metadata": {
"ref": "nightly-42"
}
}
],
"has_more": true,
"next_cursor": "<string>"
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}Authorizations
A Kite API key (kite_...), from Platform API → Keys in the dashboard.
Headers
255The dated contract your code was written against. Without it you get 2026-09-27; every response says which version served it.
2026-09-27 Body
Show child attributes
Show child attributes
LeRobot policy types to train; one run per policy. See GET /v1/training_policies. Note: all runs count against your account's in-flight concurrency limit, so a batch larger than that limit is rejected upfront.
1 - 8 elementsSee GET /v1/hardware_tiers
64LeRobot robot tag (label only)
64Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Opaque metadata echoed on the resource and its webhook events
Response
One run per policy, in the order given: processing, or failed with submission_failed when its GPU job could not start