Projects
#List projects
/v1/projectsList all projects in a workspace.
Query parameters
workspace_idstringRequiredWorkspace ID
Response codes
200OK
400Bad Request
401Unauthorized
403Forbidden
curl "https://api.rendley.com/v1/projects?workspace_id=WORKSPACE_ID" \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://api.rendley.com/v1/projects?workspace_id=WORKSPACE_ID", {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();import requests
res = requests.get(
"https://api.rendley.com/v1/projects?workspace_id=WORKSPACE_ID",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects?workspace_id=WORKSPACE_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/projects?workspace_id=WORKSPACE_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/projects?workspace_id=WORKSPACE_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"]Response
{
"data": [
{
"agent_prompt": "string",
"created_at": "string",
"created_by": "string",
"deleted_at": "string",
"fit_duration": 0,
"id": "string",
"last_viewed_at": "string",
"name": "string",
"project_json": "string",
"thumbnail_url": "string",
"updated_at": "string",
"version": 0,
"workspace_id": "string"
}
]
}#Create a project
/v1/projectsCreate a new project in a workspace, optionally from a template.
Request body
agent_promptstringOptionalAgentPrompt, when set, is stored on the project and prefilled into the assistant when the editor opens (MCP draft handoff).
namestringRequiredtemplate_idstringOptionalworkspace_idstringRequiredResponse codes
200OK
400Bad Request
401Unauthorized
403Forbidden
curl -X POST "https://api.rendley.com/v1/projects" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "<name>",
"workspace_id": "<workspace_id>"
}'const res = await fetch("https://api.rendley.com/v1/projects", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"name": "<name>",
"workspace_id": "<workspace_id>"
}),
});
const { data } = await res.json();import requests
res = requests.post(
"https://api.rendley.com/v1/projects",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"name": "<name>",
"workspace_id": "<workspace_id>"
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects");
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(["name" => "<name>", "workspace_id" => "<workspace_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(`{
"name": "<name>",
"workspace_id": "<workspace_id>"
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/projects", 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/projects")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { name: "<name>", workspace_id: "<workspace_id>" }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]AgentPrompt, when set, is stored on the project and prefilled into the assistant when the editor opens (MCP draft handoff).
Response
{
"data": {
"agent_prompt": "string",
"created_at": "string",
"created_by": "string",
"deleted_at": "string",
"fit_duration": 0,
"id": "string",
"last_viewed_at": "string",
"name": "string",
"project_json": "string",
"thumbnail_url": "string",
"updated_at": "string",
"version": 0,
"workspace_id": "string"
}
}#Get a project
/v1/projects/{id}Retrieve a single project by its ID.
Path parameters
idstringProject ID
Response codes
200OK
401Unauthorized
403Forbidden
404Not Found
curl "https://api.rendley.com/v1/projects/ID" \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://api.rendley.com/v1/projects/ID", {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();import requests
res = requests.get(
"https://api.rendley.com/v1/projects/ID",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects/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/projects/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/projects/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"]Response
{
"data": {
"agent_prompt": "string",
"created_at": "string",
"created_by": "string",
"deleted_at": "string",
"fit_duration": 0,
"id": "string",
"last_viewed_at": "string",
"name": "string",
"project_json": "string",
"thumbnail_url": "string",
"updated_at": "string",
"version": 0,
"workspace_id": "string"
}
}#Update a project
/v1/projects/{id}Update a project's mutable fields. Send only the fields you want to change.
Path parameters
idstringProject ID
Request body
adopt_file_hashesstring[]OptionalAdoptFileHashes lists role=pending uploads to retag role=library in the same request, AFTER the project JSON is saved — the atomic "save project + adopt pending uploads" step of the library injection flow. Adoption is skipped when the save itself fails.
agent_promptstringOptionalAgentPrompt updates the stored handoff prompt out of band from the version-guarded document save: "" clears it (on send), non-empty sets it, nil leaves it untouched.
fit_durationnumberOptionalnamestringOptionalproject_jsonstringOptionalversionintegerOptionalResponse codes
200OK
400Bad Request
401Unauthorized
403Forbidden
curl -X PATCH "https://api.rendley.com/v1/projects/ID" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"adopt_file_hashes": [
"string"
],
"agent_prompt": "<agent_prompt>",
"fit_duration": 0
}'const res = await fetch("https://api.rendley.com/v1/projects/ID", {
method: "PATCH",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"adopt_file_hashes": [
"string"
],
"agent_prompt": "<agent_prompt>",
"fit_duration": 0
}),
});
const { data } = await res.json();import requests
res = requests.patch(
"https://api.rendley.com/v1/projects/ID",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"adopt_file_hashes": [
"string"
],
"agent_prompt": "<agent_prompt>",
"fit_duration": 0
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects/ID");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["adopt_file_hashes" => ["string"], "agent_prompt" => "<agent_prompt>", "fit_duration" => 0]));
$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(`{
"adopt_file_hashes": [
"string"
],
"agent_prompt": "<agent_prompt>",
"fit_duration": 0
}`)
req, _ := http.NewRequest("PATCH", "https://api.rendley.com/v1/projects/ID", 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/projects/ID")
req = Net::HTTP::Patch.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { adopt_file_hashes: ["string"], agent_prompt: "<agent_prompt>", fit_duration: 0 }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]AdoptFileHashes lists role=pending uploads to retag role=library in the same request, AFTER the project JSON is saved — the atomic "save project + adopt pending uploads" step of the library injection flow. Adoption is skipped when the save itself fails.
AgentPrompt updates the stored handoff prompt out of band from the version-guarded document save: "" clears it (on send), non-empty sets it, nil leaves it untouched.
#Delete a project
/v1/projects/{id}Delete a project by its ID.
Path parameters
idstringProject ID
Response codes
200OK
400Bad Request
401Unauthorized
403Forbidden
curl -X DELETE "https://api.rendley.com/v1/projects/ID" \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://api.rendley.com/v1/projects/ID", {
method: "DELETE",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();import requests
res = requests.delete(
"https://api.rendley.com/v1/projects/ID",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects/ID");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
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("DELETE", "https://api.rendley.com/v1/projects/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/projects/ID")
req = Net::HTTP::Delete.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"]#Duplicate a project
/v1/projects/{id}/duplicateCreate a copy of an existing project, including its media assets.
Path parameters
idstringProject ID
Response codes
200OK
401Unauthorized
403Forbidden
404Not Found
curl -X POST "https://api.rendley.com/v1/projects/ID/duplicate" \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://api.rendley.com/v1/projects/ID/duplicate", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();import requests
res = requests.post(
"https://api.rendley.com/v1/projects/ID/duplicate",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects/ID/duplicate");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
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("POST", "https://api.rendley.com/v1/projects/ID/duplicate", 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/projects/ID/duplicate")
req = Net::HTTP::Post.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"]Response
{
"data": {
"agent_prompt": "string",
"created_at": "string",
"created_by": "string",
"deleted_at": "string",
"fit_duration": 0,
"id": "string",
"last_viewed_at": "string",
"name": "string",
"project_json": "string",
"thumbnail_url": "string",
"updated_at": "string",
"version": 0,
"workspace_id": "string"
}
}#Register a project view
/v1/projects/{id}/last-viewMark the project as viewed now. Updates only last_viewed_at; does not change the project version.
Path parameters
idstringProject ID
Response codes
200OK
401Unauthorized
403Forbidden
404Not Found
curl -X PATCH "https://api.rendley.com/v1/projects/ID/last-view" \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://api.rendley.com/v1/projects/ID/last-view", {
method: "PATCH",
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();import requests
res = requests.patch(
"https://api.rendley.com/v1/projects/ID/last-view",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects/ID/last-view");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
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("PATCH", "https://api.rendley.com/v1/projects/ID/last-view", 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/projects/ID/last-view")
req = Net::HTTP::Patch.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 a thumbnail upload URL
/v1/projects/{id}/thumbnailRequest a presigned URL to upload a new thumbnail for the project.
Path parameters
idstringProject ID
Request body
file_sizeintegerOptionalResponse codes
200OK
400Bad Request
401Unauthorized
403Forbidden
curl -X PATCH "https://api.rendley.com/v1/projects/ID/thumbnail" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_size": 0
}'const res = await fetch("https://api.rendley.com/v1/projects/ID/thumbnail", {
method: "PATCH",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"file_size": 0
}),
});
const { data } = await res.json();import requests
res = requests.patch(
"https://api.rendley.com/v1/projects/ID/thumbnail",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"file_size": 0
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects/ID/thumbnail");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["file_size" => 0]));
$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(`{
"file_size": 0
}`)
req, _ := http.NewRequest("PATCH", "https://api.rendley.com/v1/projects/ID/thumbnail", 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/projects/ID/thumbnail")
req = Net::HTTP::Patch.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { file_size: 0 }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]#Get a project's version
/v1/projects/{id}/versionRetrieve the current version number of a project.
Path parameters
idstringProject ID
Response codes
200OK
401Unauthorized
403Forbidden
404Not Found
curl "https://api.rendley.com/v1/projects/ID/version" \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://api.rendley.com/v1/projects/ID/version", {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();import requests
res = requests.get(
"https://api.rendley.com/v1/projects/ID/version",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/projects/ID/version");
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/projects/ID/version", 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/projects/ID/version")
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"]