curl --request POST \
--url https://api.neoagent.io/public-api/skills/{skill_id}/test-runs \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data @- <<EOF
{
"agent_id": 23433,
"args": [
"--month",
"2026-08"
],
"entry_path": "scripts/reconcile.py",
"files": [
{
"content": "print('reconcile v2')\n",
"path": "scripts/reconcile.py"
}
]
}
EOFimport requests
url = "https://api.neoagent.io/public-api/skills/{skill_id}/test-runs"
payload = {
"agent_id": 23433,
"args": ["--month", "2026-08"],
"entry_path": "scripts/reconcile.py",
"files": [
{
"content": "print('reconcile v2')
",
"path": "scripts/reconcile.py"
}
]
}
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({
agent_id: 23433,
args: ['--month', '2026-08'],
entry_path: 'scripts/reconcile.py',
files: [{content: 'print(\'reconcile v2\')\n', path: 'scripts/reconcile.py'}]
})
};
fetch('https://api.neoagent.io/public-api/skills/{skill_id}/test-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.neoagent.io/public-api/skills/{skill_id}/test-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([
'agent_id' => 23433,
'args' => [
'--month',
'2026-08'
],
'entry_path' => 'scripts/reconcile.py',
'files' => [
[
'content' => 'print(\'reconcile v2\')
',
'path' => 'scripts/reconcile.py'
]
]
]),
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.neoagent.io/public-api/skills/{skill_id}/test-runs"
payload := strings.NewReader("{\n \"agent_id\": 23433,\n \"args\": [\n \"--month\",\n \"2026-08\"\n ],\n \"entry_path\": \"scripts/reconcile.py\",\n \"files\": [\n {\n \"content\": \"print('reconcile v2')\\n\",\n \"path\": \"scripts/reconcile.py\"\n }\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.neoagent.io/public-api/skills/{skill_id}/test-runs")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"agent_id\": 23433,\n \"args\": [\n \"--month\",\n \"2026-08\"\n ],\n \"entry_path\": \"scripts/reconcile.py\",\n \"files\": [\n {\n \"content\": \"print('reconcile v2')\\n\",\n \"path\": \"scripts/reconcile.py\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.neoagent.io/public-api/skills/{skill_id}/test-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 \"agent_id\": 23433,\n \"args\": [\n \"--month\",\n \"2026-08\"\n ],\n \"entry_path\": \"scripts/reconcile.py\",\n \"files\": [\n {\n \"content\": \"print('reconcile v2')\\n\",\n \"path\": \"scripts/reconcile.py\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": "<unknown>",
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timings_ms": {},
"pagination": {
"has_more": true,
"next_cursor": "<string>"
},
"warnings": [
"<string>"
]
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}Run a skill script in the sandbox (SSE)
Run one script of the skill in the tenant’s code sandbox and stream its output. The run borrows the integration permissions of agent_id in read-only mode: every write to a connected system is refused by the sandbox proxy, and no technician approval is involved. Send unsaved drafts in files to run them instead of the saved files; the saved skill is never changed by a run.
Response is text/event-stream — stream it, don’t buffer. Events: status {phase}, output {stream, data} as the script prints, and a final done {run_id, outcome, exit_code, failure_reason, duration_ms}. Closing the stream stops the script. A run is limited to 120 seconds and 500 KB of output, and to 30 runs per hour per user. Read the recorded run back with GET …/test-runs/.
curl --request POST \
--url https://api.neoagent.io/public-api/skills/{skill_id}/test-runs \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data @- <<EOF
{
"agent_id": 23433,
"args": [
"--month",
"2026-08"
],
"entry_path": "scripts/reconcile.py",
"files": [
{
"content": "print('reconcile v2')\n",
"path": "scripts/reconcile.py"
}
]
}
EOFimport requests
url = "https://api.neoagent.io/public-api/skills/{skill_id}/test-runs"
payload = {
"agent_id": 23433,
"args": ["--month", "2026-08"],
"entry_path": "scripts/reconcile.py",
"files": [
{
"content": "print('reconcile v2')
",
"path": "scripts/reconcile.py"
}
]
}
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({
agent_id: 23433,
args: ['--month', '2026-08'],
entry_path: 'scripts/reconcile.py',
files: [{content: 'print(\'reconcile v2\')\n', path: 'scripts/reconcile.py'}]
})
};
fetch('https://api.neoagent.io/public-api/skills/{skill_id}/test-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.neoagent.io/public-api/skills/{skill_id}/test-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([
'agent_id' => 23433,
'args' => [
'--month',
'2026-08'
],
'entry_path' => 'scripts/reconcile.py',
'files' => [
[
'content' => 'print(\'reconcile v2\')
',
'path' => 'scripts/reconcile.py'
]
]
]),
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.neoagent.io/public-api/skills/{skill_id}/test-runs"
payload := strings.NewReader("{\n \"agent_id\": 23433,\n \"args\": [\n \"--month\",\n \"2026-08\"\n ],\n \"entry_path\": \"scripts/reconcile.py\",\n \"files\": [\n {\n \"content\": \"print('reconcile v2')\\n\",\n \"path\": \"scripts/reconcile.py\"\n }\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.neoagent.io/public-api/skills/{skill_id}/test-runs")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"agent_id\": 23433,\n \"args\": [\n \"--month\",\n \"2026-08\"\n ],\n \"entry_path\": \"scripts/reconcile.py\",\n \"files\": [\n {\n \"content\": \"print('reconcile v2')\\n\",\n \"path\": \"scripts/reconcile.py\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.neoagent.io/public-api/skills/{skill_id}/test-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 \"agent_id\": 23433,\n \"args\": [\n \"--month\",\n \"2026-08\"\n ],\n \"entry_path\": \"scripts/reconcile.py\",\n \"files\": [\n {\n \"content\": \"print('reconcile v2')\\n\",\n \"path\": \"scripts/reconcile.py\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": "<unknown>",
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timings_ms": {},
"pagination": {
"has_more": true,
"next_cursor": "<string>"
},
"warnings": [
"<string>"
]
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": {}
},
"meta": {
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}Authorizations
Authorization: Bearer <token> where <token> is either a neo_sk_<env>_<secret> API key (service account) or a Microsoft Entra ID access token (dashboard user).
Path Parameters
Body
POST /skills/{id}/test-runs — run one script of the skill in the tenant sandbox.
The agent whose integration permissions the run borrows. Every proxied call (PSA, Microsoft 365, RMM, ...) is authorised as this agent, in read-only mode. Must be an agent of your own tenant that you may edit; Neo-managed and end-user agents are refused.
The script to run, as a path inside the skill, e.g. scripts/run.py.
Command-line arguments passed to the script.
Unsaved drafts to run instead of the saved files at the same paths. The saved skill is not changed. Omit to run the saved skill as it is.
Show child attributes
Show child attributes
