Rendley docs

Approvals

By default the agent decides everything itself. Turn that off when you want a human, or your own code, to approve the plan before credits are spent.

Unattended by default

Runs are unattended unless you ask otherwise. The agent approves its own plan, resolves ambiguity with the most reasonable assumption, and runs straight through to a terminal status. Start it, poll it, read the result. There is nothing to answer.

Your prompt is the only chance to steer the run. Be specific about duration, aspect ratio, tone and which file goes where.

Two things still end an unattended run early. No assumption can stand in for either one:

reasonWhat happened
needs_upgradeThe edit required a paid capability your plan does not include. retryable is false. Upgrading is the only fix.
unexpected_interruptThe agent hit a question it could not answer for itself. Rare. Usually the prompt left something essential undecided.

Both arrive as status: "failed" with that reason set, not as a pause.

Interactive runs

Send "interactive": true to approve the plan before credits are spent, or to answer the agent’s questions yourself. Omit it for the unattended behavior above.

An interactive run pauses at status: "waiting_input" and carries an interrupt describing the question:

{
  "status": "waiting_input",
  "reason": "waiting_input",
  "interrupt": {
    "id": "int_abc...",
    "type": "plan_review",
    "summary": "Generate music, transcribe the interview, add captions.",
    "cost_credits": 42,
    "options": [
      { "label": "Approve plan", "value": "approve" },
      { "label": "Reject", "value": "reject" }
    ],
    "allow_input_text": true
  }
}

#Answer a paused job

POSThttps://api.rendley.com/v1/agent/jobs/{jobID}/respond

An empty response means approve, so {} is a valid body.

statusMeaning
resumingAccepted. The run continues; keep polling.
not_waitingThe job was not paused. Nothing happened.
invalid_responseThe answer was not one of the offered options and the pause does not accept free text. The job stays paused; answer again.

An answer is matched against the interrupt’s options by value or label, case-insensitively. Free text is accepted only when allow_input_text is true.

reject does not always abort. On a plan or tool review it means “skip this and carry on”, so the agent still composes what you already paid for. On other pause types it stops the run.

This endpoint applies to interactive runs only. An unattended run never reaches waiting_input.

Don't have one? Create an API key

Body

One of the interrupt's option values, or free text when allow_input_text is true. Empty means approve.

const res = await fetch("https://api.rendley.com/v1/agent/jobs/{jobID}/respond", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
  body: JSON.stringify({
    "response": "approve"
  }),
});
const { data } = await res.json();
curl -X POST "https://api.rendley.com/v1/agent/jobs/{jobID}/respond" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "response": "approve"
  }'
import requests

res = requests.post(
    "https://api.rendley.com/v1/agent/jobs/{jobID}/respond",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={
        "response": "approve"
    },
)
data = res.json()["data"]
$ch = curl_init("https://api.rendley.com/v1/agent/jobs/{jobID}/respond");
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" => "approve"]));

$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": "approve"
}`)
	req, _ := http.NewRequest("POST", "https://api.rendley.com/v1/agent/jobs/{jobID}/respond", 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/jobs/{jobID}/respond")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = { response: "approve" }.to_json

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)["data"]

Response

{
  "data": {
    "status": "resuming",
    "job": {
      "job_id": "c41d8f2b-7a63-4e09-bd15-8f3a29c7e604",
      "status": "running"
    }
  }
}

#Cancel a running edit

POSThttps://api.rendley.com/v1/agent/jobs/{jobID}/cancel

Cancels a job that is pending, running, or paused. The response is the job in its final state. A job that already finished is returned unchanged.

Don't have one? Create an API key

const res = await fetch("https://api.rendley.com/v1/agent/jobs/{jobID}/cancel", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_API_KEY" },
});
const { data } = await res.json();
curl -X POST "https://api.rendley.com/v1/agent/jobs/{jobID}/cancel" \
  -H "Authorization: Bearer YOUR_API_KEY"
import requests

res = requests.post(
    "https://api.rendley.com/v1/agent/jobs/{jobID}/cancel",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = res.json()["data"]
$ch = curl_init("https://api.rendley.com/v1/agent/jobs/{jobID}/cancel");
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/agent/jobs/{jobID}/cancel", 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/jobs/{jobID}/cancel")
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": {
    "job_id": "c41d8f2b-7a63-4e09-bd15-8f3a29c7e604",
    "status": "canceled",
    "reason": "canceled"
  }
}