Automated video editing
You send a prompt to the Rendley agent, it edits a project for you, and you get a project_url back. From there you can open the project in the editor to review it, make more edits, or export it to a downloadable MP4 through the API.
#Step 1: Start the agent
mcp.rendley.com/v1/agentSend a prompt describing what you want. You can optionally attach source files (as public URLs) and target an existing project.
curl -X POST "https://mcp.rendley.com/v1/agent" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Cut this interview into a 2-minute highlight reel with captions and music.",
"files": [
{
"url": "https://cdn.example.com/interview.mp4"
}
]
}'const res = await fetch("https://mcp.rendley.com/v1/agent", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"prompt": "Cut this interview into a 2-minute highlight reel with captions and music.",
"files": [
{
"url": "https://cdn.example.com/interview.mp4"
}
]
}),
});
const { data } = await res.json();import requests
res = requests.post(
"https://mcp.rendley.com/v1/agent",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"prompt": "Cut this interview into a 2-minute highlight reel with captions and music.",
"files": [
{
"url": "https://cdn.example.com/interview.mp4"
}
]
},
)
data = res.json()["data"]$ch = curl_init("https://mcp.rendley.com/v1/agent");
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(["prompt" => "Cut this interview into a 2-minute highlight reel with captions and music.", "files" => [["url" => "https://cdn.example.com/interview.mp4"]]]));
$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(`{
"prompt": "Cut this interview into a 2-minute highlight reel with captions and music.",
"files": [
{
"url": "https://cdn.example.com/interview.mp4"
}
]
}`)
req, _ := http.NewRequest("POST", "https://mcp.rendley.com/v1/agent", 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://mcp.rendley.com/v1/agent")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { prompt: "Cut this interview into a 2-minute highlight reel with captions and music.", files: [{ url: "https://cdn.example.com/interview.mp4" }] }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]What you want done, in plain language.
Edit an existing project. When omitted, a new project is created.
filesMedia to bring in.
Public https URL of the file.
Continue a previous conversation.
Response
{
"job_id": "job_8f2c...",
"project_id": "prj_abc...",
"thread_id": "thr_xyz..."
}#Step 2: Wait for the agent to finish
mcp.rendley.com/v1/jobs/{job_id}Poll this endpoint every 3-5 seconds until status is completed or failed. The agent usually finishes in 1-3 minutes depending on what you asked for.
When the job completes, you get a project_url you can open in the browser to review and edit further. See Jobs and polling for the full polling loop.
curl "https://mcp.rendley.com/v1/jobs/{job_id}" \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://mcp.rendley.com/v1/jobs/{job_id}", {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();import requests
res = requests.get(
"https://mcp.rendley.com/v1/jobs/{job_id}",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://mcp.rendley.com/v1/jobs/{job_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://mcp.rendley.com/v1/jobs/{job_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://mcp.rendley.com/v1/jobs/{job_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
{
"status": "completed",
"result": {
"project_url": "https://app.rendley.com/project/prj_abc..."
}
}At this point the project timeline is ready. You can stop here and use the editor, or continue to export a video file.
#Step 3: Export to MP4 (optional)
/v1/exportIf you need a downloadable video file, start an export. This is a separate step because you might want to review the project first, or you might not need a rendered file at all.
curl -X POST "https://api.rendley.com/v1/export" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_id": "prj_abc...",
"settings": {
"target_resolution": "1080p",
"codec": "h264"
}
}'const res = await fetch("https://api.rendley.com/v1/export", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"project_id": "prj_abc...",
"settings": {
"target_resolution": "1080p",
"codec": "h264"
}
}),
});
const { data } = await res.json();import requests
res = requests.post(
"https://api.rendley.com/v1/export",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"project_id": "prj_abc...",
"settings": {
"target_resolution": "1080p",
"codec": "h264"
}
},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/export");
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" => "prj_abc...", "settings" => ["target_resolution" => "1080p", "codec" => "h264"]]));
$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": "prj_abc...",
"settings": {
"target_resolution": "1080p",
"codec": "h264"
}
}`)
req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/export", 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/export")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { project_id: "prj_abc...", settings: { target_resolution: "1080p", codec: "h264" } }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]The project to export.
settingsExport settings.
e.g. 1080p, 720p, 4k.
e.g. h264, h265.
Response
{
"data": {
"job_id": "job_9d3a..."
}
}#Step 4: Download the rendered file
/v1/jobs/{job_id}Poll this endpoint the same way until status is completed. The result_data field contains a storage_url you can download from. See Jobs and polling for the full polling loop.
The storage_url is a time-limited presigned link. Download the file soon after the export completes.
curl "https://api.rendley.com/v1/jobs/{job_id}" \
-H "Authorization: Bearer YOUR_API_KEY"const res = await fetch("https://api.rendley.com/v1/jobs/{job_id}", {
headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();import requests
res = requests.get(
"https://api.rendley.com/v1/jobs/{job_id}",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]$ch = curl_init("https://api.rendley.com/v1/jobs/{job_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/jobs/{job_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/jobs/{job_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": {
"status": "completed",
"result_data": "{\"storage_url\":\"https://storage.rendley.com/exports/...mp4\",\"media_id\":\"med_...\"}"
}
}#Continuing a conversation
mcp.rendley.com/v1/agentTo make follow-up edits, send another request with the same project_id and thread_id. The agent keeps the full context of what it did before.
curl -X POST "https://mcp.rendley.com/v1/agent" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Make the intro shorter and add a call-to-action at the end.",
"project_id": "prj_abc...",
"thread_id": "thr_xyz..."
}'const res = await fetch("https://mcp.rendley.com/v1/agent", {
method: "POST",
headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
"prompt": "Make the intro shorter and add a call-to-action at the end.",
"project_id": "prj_abc...",
"thread_id": "thr_xyz..."
}),
});
const { data } = await res.json();import requests
res = requests.post(
"https://mcp.rendley.com/v1/agent",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"prompt": "Make the intro shorter and add a call-to-action at the end.",
"project_id": "prj_abc...",
"thread_id": "thr_xyz..."
},
)
data = res.json()["data"]$ch = curl_init("https://mcp.rendley.com/v1/agent");
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(["prompt" => "Make the intro shorter and add a call-to-action at the end.", "project_id" => "prj_abc...", "thread_id" => "thr_xyz..."]));
$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(`{
"prompt": "Make the intro shorter and add a call-to-action at the end.",
"project_id": "prj_abc...",
"thread_id": "thr_xyz..."
}`)
req, _ := http.NewRequest("POST", "https://mcp.rendley.com/v1/agent", 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://mcp.rendley.com/v1/agent")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { prompt: "Make the intro shorter and add a call-to-action at the end.", project_id: "prj_abc...", thread_id: "thr_xyz..." }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]The follow-up instruction.
The same project from the first request.
The thread_id returned from the first request.