Create Sim Run
Preview. Usable today, but this endpoint can change before it is stable, without a new Kite-Version. Changes are announced before they ship.
Run an SDK spec on Kite. The spec is checked first (the same checks as /v1/sim_runs/validate), so a spec that
cannot run is refused here, for free. Returns 202 with a queued run; poll GET /v1/sim_runs/, or subscribe
to sim_run.succeeded / sim_run.failed / sim_run.canceled. Send an Idempotency-Key to make retries safe: a retry
with the same key and body returns the same run, even while the first request is still in flight.
curl --request POST \
--url https://api.kiteml.com/v1/sim_runs \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"files": {
"../evals": {
"kind": "directory",
"shipped": "evals"
}
},
"spec_path": "specs/smoke.yaml",
"spec_yaml": "kite_spec_version: \"2\"\nname: smoke\npolicy: {kind: scripted_pick, ref: scripted_pick}\n..."
}
'import requests
url = "https://api.kiteml.com/v1/sim_runs"
payload = {
"files": { "../evals": {
"kind": "directory",
"shipped": "evals"
} },
"spec_path": "specs/smoke.yaml",
"spec_yaml": "kite_spec_version: \"2\"
name: smoke
policy: {kind: scripted_pick, ref: scripted_pick}
..."
}
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({
files: {'../evals': {kind: 'directory', shipped: 'evals'}},
spec_path: 'specs/smoke.yaml',
spec_yaml: 'kite_spec_version: "2"\nname: smoke\npolicy: {kind: scripted_pick, ref: scripted_pick}\n...'
})
};
fetch('https://api.kiteml.com/v1/sim_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/sim_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([
'files' => [
'../evals' => [
'kind' => 'directory',
'shipped' => 'evals'
]
],
'spec_path' => 'specs/smoke.yaml',
'spec_yaml' => 'kite_spec_version: "2"
name: smoke
policy: {kind: scripted_pick, ref: scripted_pick}
...'
]),
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/sim_runs"
payload := strings.NewReader("{\n \"files\": {\n \"../evals\": {\n \"kind\": \"directory\",\n \"shipped\": \"evals\"\n }\n },\n \"spec_path\": \"specs/smoke.yaml\",\n \"spec_yaml\": \"kite_spec_version: \\\"2\\\"\\nname: smoke\\npolicy: {kind: scripted_pick, ref: scripted_pick}\\n...\"\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/sim_runs")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"files\": {\n \"../evals\": {\n \"kind\": \"directory\",\n \"shipped\": \"evals\"\n }\n },\n \"spec_path\": \"specs/smoke.yaml\",\n \"spec_yaml\": \"kite_spec_version: \\\"2\\\"\\nname: smoke\\npolicy: {kind: scripted_pick, ref: scripted_pick}\\n...\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kiteml.com/v1/sim_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 \"files\": {\n \"../evals\": {\n \"kind\": \"directory\",\n \"shipped\": \"evals\"\n }\n },\n \"spec_path\": \"specs/smoke.yaml\",\n \"spec_yaml\": \"kite_spec_version: \\\"2\\\"\\nname: smoke\\npolicy: {kind: scripted_pick, ref: scripted_pick}\\n...\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"status": "queued",
"progress": 0.5,
"tokens": {
"charged": 123,
"refunded": 123
},
"object": "sim_run",
"phase": "<string>",
"status_message": "<string>",
"episodes": {
"done": 123,
"total": 123
},
"error": {
"code": "<string>",
"message": "<string>",
"resumable": true,
"param": "<string>",
"details": {}
},
"spec": {},
"kite_version": "<string>",
"options": {},
"label": "<string>",
"result": {
"verified": true,
"run_id": "<string>",
"manifest_hash": "<string>",
"run_hash": "<string>",
"determinism_verified": true,
"metrics": [
{
"id": "<string>",
"version": "<string>",
"value": 123,
"interval": [
123
],
"n": 123
}
]
},
"download": {
"url": "<string>",
"requires_auth": true,
"filename": "<string>",
"bytes": 123,
"sha256": "<string>",
"expires_at": "<string>"
},
"webhook_metadata": {},
"created_at": "<string>",
"started_at": "<string>",
"completed_at": "<string>",
"links": {}
}{
"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": {}
}
}{
"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
Run a spec. spec_yaml and the files it names are required; everything else has a default.
The spec file's text, as written
1 - 2000000Its path in your workspace: what errors cite
500Each path the spec names, as it names it
Show child attributes
Show child attributes
FIELD=VALUE, as kite --set
100The Kite release to run; default the latest
40Show child attributes
Show child attributes
120Opaque metadata echoed on the resource and its webhook events
Response
The run, queued
One run of an SDK spec.
srun_ + a time-ordered ULID
queued, processing, canceling, succeeded, failed, canceled 0 <= x <= 1Show child attributes
Show child attributes
sim_run "sim_run"materializing, planning, fetching, running, verifying or packaging
Show child attributes
Show child attributes
Show child attributes
Show child attributes
path and name
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
curl --request POST \
--url https://api.kiteml.com/v1/sim_runs \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"files": {
"../evals": {
"kind": "directory",
"shipped": "evals"
}
},
"spec_path": "specs/smoke.yaml",
"spec_yaml": "kite_spec_version: \"2\"\nname: smoke\npolicy: {kind: scripted_pick, ref: scripted_pick}\n..."
}
'import requests
url = "https://api.kiteml.com/v1/sim_runs"
payload = {
"files": { "../evals": {
"kind": "directory",
"shipped": "evals"
} },
"spec_path": "specs/smoke.yaml",
"spec_yaml": "kite_spec_version: \"2\"
name: smoke
policy: {kind: scripted_pick, ref: scripted_pick}
..."
}
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({
files: {'../evals': {kind: 'directory', shipped: 'evals'}},
spec_path: 'specs/smoke.yaml',
spec_yaml: 'kite_spec_version: "2"\nname: smoke\npolicy: {kind: scripted_pick, ref: scripted_pick}\n...'
})
};
fetch('https://api.kiteml.com/v1/sim_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/sim_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([
'files' => [
'../evals' => [
'kind' => 'directory',
'shipped' => 'evals'
]
],
'spec_path' => 'specs/smoke.yaml',
'spec_yaml' => 'kite_spec_version: "2"
name: smoke
policy: {kind: scripted_pick, ref: scripted_pick}
...'
]),
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/sim_runs"
payload := strings.NewReader("{\n \"files\": {\n \"../evals\": {\n \"kind\": \"directory\",\n \"shipped\": \"evals\"\n }\n },\n \"spec_path\": \"specs/smoke.yaml\",\n \"spec_yaml\": \"kite_spec_version: \\\"2\\\"\\nname: smoke\\npolicy: {kind: scripted_pick, ref: scripted_pick}\\n...\"\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/sim_runs")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"files\": {\n \"../evals\": {\n \"kind\": \"directory\",\n \"shipped\": \"evals\"\n }\n },\n \"spec_path\": \"specs/smoke.yaml\",\n \"spec_yaml\": \"kite_spec_version: \\\"2\\\"\\nname: smoke\\npolicy: {kind: scripted_pick, ref: scripted_pick}\\n...\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.kiteml.com/v1/sim_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 \"files\": {\n \"../evals\": {\n \"kind\": \"directory\",\n \"shipped\": \"evals\"\n }\n },\n \"spec_path\": \"specs/smoke.yaml\",\n \"spec_yaml\": \"kite_spec_version: \\\"2\\\"\\nname: smoke\\npolicy: {kind: scripted_pick, ref: scripted_pick}\\n...\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"status": "queued",
"progress": 0.5,
"tokens": {
"charged": 123,
"refunded": 123
},
"object": "sim_run",
"phase": "<string>",
"status_message": "<string>",
"episodes": {
"done": 123,
"total": 123
},
"error": {
"code": "<string>",
"message": "<string>",
"resumable": true,
"param": "<string>",
"details": {}
},
"spec": {},
"kite_version": "<string>",
"options": {},
"label": "<string>",
"result": {
"verified": true,
"run_id": "<string>",
"manifest_hash": "<string>",
"run_hash": "<string>",
"determinism_verified": true,
"metrics": [
{
"id": "<string>",
"version": "<string>",
"value": 123,
"interval": [
123
],
"n": 123
}
]
},
"download": {
"url": "<string>",
"requires_auth": true,
"filename": "<string>",
"bytes": 123,
"sha256": "<string>",
"expires_at": "<string>"
},
"webhook_metadata": {},
"created_at": "<string>",
"started_at": "<string>",
"completed_at": "<string>",
"links": {}
}{
"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": {}
}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>",
"details": {}
}
}