Agent
#Create an agent session
/v1/agent/sessionsStart a new agent session and stream results over Server-Sent Events.
Request body
attachmentsobject[]Optionalmedia_idstringRequiredlocal_authoringbooleanOptionalLocalAuthoring signals that the caller (an interactive MCP-driven LLM) can author motion-clip userCode itself for free. When set, create_motion_clip pauses with a motion_clip_authoring interrupt instead of generating (and charging) server-side, and shows 0 cost in the plan review. Only sent by interactive headless sessions; normal in-editor usage omits it.
messagestringRequiredplanner_onlybooleanOptionalPlannerOnly forces the planner runner and bypasses the semantic session router. Set by non-interactive callers (the MCP bridge) that always want the full planning flow and can't recover from a direct-edit misroute. Omitted for normal in-editor usage, which keeps semantic routing.
project_idstringRequiredthread_idstringRequiredunattendedbooleanOptionalUnattended signals that NOBODY can answer a question mid-run — the caller fires the job and polls for the result (the REST /v1/agent path). The clarify tool then answers itself inline ("proceed with the most reasonable assumption") instead of pausing for input that would never arrive. Only sent by non-interactive headless sessions; a human editor or an interactive MCP-driven LLM can both answer, so they omit it.
Response codes
200OK
400Bad Request
401Unauthorized
curl -X POST "https://api.rendley.com/v1/agent/sessions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "<message>",
"project_id": "<project_id>",
"thread_id": "<thread_id>"
}'const res = await fetch("https://api.rendley.com/v1/agent/sessions", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"message": "<message>",
"project_id": "<project_id>",
"thread_id": "<thread_id>"
}),
});
const { data } = await res.json();import requests
res = requests.post(
"https://api.rendley.com/v1/agent/sessions",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"message": "<message>",
"project_id": "<project_id>",
"thread_id": "<thread_id>"
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/agent/sessions");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["message" => "<message>", "project_id" => "<project_id>", "thread_id" => "<thread_id>"]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
"bytes"
)
func main() {
body := bytes.NewBufferString(`{
"message": "<message>",
"project_id": "<project_id>",
"thread_id": "<thread_id>"
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/agent/sessions", body)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/agent/sessions")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { message: "<message>", project_id: "<project_id>", thread_id: "<thread_id>" }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]attachmentsLocalAuthoring signals that the caller (an interactive MCP-driven LLM) can author motion-clip userCode itself for free. When set, create_motion_clip pauses with a motion_clip_authoring interrupt instead of generating (and charging) server-side, and shows 0 cost in the plan review. Only sent by interactive headless sessions; normal in-editor usage omits it.
PlannerOnly forces the planner runner and bypasses the semantic session router. Set by non-interactive callers (the MCP bridge) that always want the full planning flow and can't recover from a direct-edit misroute. Omitted for normal in-editor usage, which keeps semantic routing.
Unattended signals that NOBODY can answer a question mid-run — the caller fires the job and polls for the result (the REST /v1/agent path). The clarify tool then answers itself inline ("proceed with the most reasonable assumption") instead of pausing for input that would never arrive. Only sent by non-interactive headless sessions; a human editor or an interactive MCP-driven LLM can both answer, so they omit it.
#Resume an agent session
/v1/agent/sessions/resumeResume an interrupted agent session and stream results over Server-Sent Events.
Request body
interrupt_idstringOptionalinterrupt_type"plan_review" | "request_upgrade" | "tool_review" | "context_request" | "command_execution" | "file_upload" | "edit_feedback" | "motion_clip_authoring" | "clarify"OptionalresponsestringRequiredthread_idstringRequiredResponse codes
200OK
400Bad Request
401Unauthorized
curl -X POST "https://api.rendley.com/v1/agent/sessions/resume" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"response": "<response>",
"thread_id": "<thread_id>"
}'const res = await fetch("https://api.rendley.com/v1/agent/sessions/resume", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"response": "<response>",
"thread_id": "<thread_id>"
}),
});
const { data } = await res.json();import requests
res = requests.post(
"https://api.rendley.com/v1/agent/sessions/resume",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"response": "<response>",
"thread_id": "<thread_id>"
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/agent/sessions/resume");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["response" => "<response>", "thread_id" => "<thread_id>"]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
"bytes"
)
func main() {
body := bytes.NewBufferString(`{
"response": "<response>",
"thread_id": "<thread_id>"
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/agent/sessions/resume", body)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/agent/sessions/resume")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { response: "<response>", thread_id: "<thread_id>" }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]#Create an agent thread
/v1/agent/threadsCreate a new agent thread for a project.
Request body
project_idstringRequiredResponse codes
200OK
400Bad Request
401Unauthorized
curl -X POST "https://api.rendley.com/v1/agent/threads" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_id": "<project_id>"
}'const res = await fetch("https://api.rendley.com/v1/agent/threads", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"project_id": "<project_id>"
}),
});
const { data } = await res.json();import requests
res = requests.post(
"https://api.rendley.com/v1/agent/threads",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"project_id": "<project_id>"
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/agent/threads");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["project_id" => "<project_id>"]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
"bytes"
)
func main() {
body := bytes.NewBufferString(`{
"project_id": "<project_id>"
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/agent/threads", body)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/agent/threads")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { project_id: "<project_id>" }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]#Get the thread's pending interrupt
/v1/agent/threads/{threadID}/pending-interruptReturn the last sent-but-unanswered interrupt for a thread so a client whose SSE stream died can replay it and resume the run.
Path parameters
threadIDstringThread ID
Response codes
200OK
400Bad Request
401Unauthorized
curl "https://api.rendley.com/v1/agent/threads/THREAD_ID/pending-interrupt" \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://api.rendley.com/v1/agent/threads/THREAD_ID/pending-interrupt", {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();import requests
res = requests.get(
"https://api.rendley.com/v1/agent/threads/THREAD_ID/pending-interrupt",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/agent/threads/THREAD_ID/pending-interrupt");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY"]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.rendley.com/v1/agent/threads/THREAD_ID/pending-interrupt", nil)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/agent/threads/THREAD_ID/pending-interrupt")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]#Get the last agent thread
/v1/agent/threads/lastGet the most recent agent thread for a project.
Query parameters
project_idstringRequiredProject ID
Response codes
200OK
400Bad Request
401Unauthorized
curl "https://api.rendley.com/v1/agent/threads/last?project_id=PROJECT_ID" \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://api.rendley.com/v1/agent/threads/last?project_id=PROJECT_ID", {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();import requests
res = requests.get(
"https://api.rendley.com/v1/agent/threads/last?project_id=PROJECT_ID",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/agent/threads/last?project_id=PROJECT_ID");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY"]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true)["data"];package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.rendley.com/v1/agent/threads/last?project_id=PROJECT_ID", nil)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b))
}require "net/http"
require "json"
uri = URI("https://api.rendley.com/v1/agent/threads/last?project_id=PROJECT_ID")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]