Rendley docs

Jobs and polling

Anything that takes real time, rendering a video, transcribing audio, generating an image or a clip, runs asynchronously. The endpoint that starts the work returns a job id right away, and you poll that job until it finishes. This page explains the job lifecycle and the polling loop once, so every async endpoint behaves the same way for you.

How it works

  1. Call an endpoint that starts work, for example POST /export. It returns a job_id.
  2. Poll GET /jobs/{id} until the job reaches a terminal status.
  3. When the status is completed, read the output from result_data. When it is failed, read error.

The job id is the only handle you need. You do not keep the connection open or wait on the first request; the render runs on Rendley’s workers while you poll.

Job status

A job moves through these statuses. Three of them are terminal: once a job is completed, failed, or canceled, it will not change again.

StatusTerminalMeaning
queuednoAccepted and waiting for a worker.
processingnoA worker is running the job.
completedyesFinished successfully. Read result_data.
failedyesDid not finish. Read error.
canceledyesCanceled by you with DELETE /jobs/{id}.

The job object

GET /jobs/{id} returns a job in the standard data envelope:

{
  "data": {
    "id": "job_8f2c...",
    "type": "export_video",
    "status": "completed",
    "input_data": "{\"project_id\":\"...\"}",
    "result_data": "{\"storage_url\":\"https://...\",\"media_id\":\"...\"}",
    "error": null,
    "acknowledged": false,
    "source_type": "api",
    "source_id": "..."
  }
}
Name Type Description
id string The job id. Use it to poll, cancel, or fetch the job.
type string What the job does, e.g. export_video, transcription, generate_image, generate_video.
status string One of queued, processing, completed, failed, canceled.
input_data string JSON-encoded string of the request that created the job.
result_data string | null JSON-encoded string with the output. Null until the job is completed.
error string | null A short error code or message. Null unless the job failed.
acknowledged boolean Whether the job has been marked as seen. Optional, for your own bookkeeping.
source_type string Where the job came from. Jobs you start over the API are api.
source_id string An id that ties the job back to its origin, such as a project id.

input_data and result_data are JSON encoded as strings, not nested objects. Parse them before reading fields:

const job = (await res.json()).data;
const result = job.result_data ? JSON.parse(job.result_data) : null;
const fileUrl = result?.storage_url;

Start a job

Most async endpoints return a job_id. The export endpoint is the canonical example.

POST /v1/export
curl -X POST https://api.rendley.com/v1/export \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "project_id": "prj_123",
  "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_123",
  settings: { target_resolution: "1080p", codec: "h264" },
}),
});
const { data } = await res.json();
const jobId = data.job_id;
import requests

res = requests.post(
  "https://api.rendley.com/v1/export",
  headers={"Authorization": "Bearer YOUR_API_KEY"},
  json={
      "project_id": "prj_123",
      "settings": {"target_resolution": "1080p", "codec": "h264"},
  },
)
job_id = res.json()["data"]["job_id"]

The response is just the id:

{ "data": { "job_id": "job_8f2c..." } }

Billable work, like exports and AI tools, has a matching .../cost endpoint (for example POST /export/cost) that returns the credit price for the exact request without starting it. Call it first if you want to confirm the cost before you commit.

Poll the job

GET /v1/jobs/{id}

Fetch the job on an interval until status is terminal. A few seconds between polls is plenty; there is no benefit to polling faster than once per second. For long renders, back off to every 5 to 10 seconds.

# Poll once. Repeat until status is completed, failed, or canceled.
curl https://api.rendley.com/v1/jobs/job_8f2c... \
-H "Authorization: Bearer YOUR_API_KEY"
async function waitForJob(jobId, apiKey) {
const terminal = ["completed", "failed", "canceled"];
while (true) {
  const res = await fetch(`https://api.rendley.com/v1/jobs/${jobId}`, {
    headers: { Authorization: `Bearer ${apiKey}` },
  });
  const { data: job } = await res.json();
  if (terminal.includes(job.status)) return job;
  await new Promise((r) => setTimeout(r, 3000)); // wait 3s, then poll again
}
}

const job = await waitForJob(jobId, "YOUR_API_KEY");
if (job.status === "completed") {
const { storage_url } = JSON.parse(job.result_data);
console.log("Done:", storage_url);
} else {
throw new Error(job.error ?? "job did not complete");
}
import time, json, requests

def wait_for_job(job_id, api_key):
  terminal = {"completed", "failed", "canceled"}
  while True:
      res = requests.get(
          f"https://api.rendley.com/v1/jobs/{job_id}",
          headers={"Authorization": f"Bearer {api_key}"},
      )
      job = res.json()["data"]
      if job["status"] in terminal:
          return job
      time.sleep(3)  # wait 3s, then poll again

job = wait_for_job(job_id, "YOUR_API_KEY")
if job["status"] == "completed":
  result = json.loads(job["result_data"])
  print("Done:", result["storage_url"])
else:
  raise RuntimeError(job.get("error") or "job did not complete")

Polling a job by its id always works, regardless of how the job was created.

Read the result

When status is completed, parse result_data. For an export it carries the URL of the finished file:

{
  "storage_url": "https://storage.rendley.com/exports/...mp4",
  "media_id": "med_..."
}

Download the file from storage_url. These links are time limited, so fetch the file soon after the job completes rather than storing the URL for later. If a link has expired, fetch the job again to confirm it is still completed and re-read the URL.

Other job types put their own fields in result_data. A transcription returns the transcript, an image generation returns the image URL, and so on. The shape always matches the operation that started the job, and each endpoint’s reference page documents it.

When a job fails

A failed job has status: "failed" and a short code or message in error. Common causes:

  • A media URL in an inline export could not be reached. Every asset referenced by an inline render must be at a permanent, publicly reachable URL. Temporary or signed URLs that expire cause the render to fail.
  • The account ran out of credits partway through, or hit a plan limit.
  • The input was malformed in a way that only surfaced during processing.

Treat error as a reason to surface to your own logs or users. The job will not retry itself; start a new job once you have fixed the cause.

Cancel a job

DELETE /v1/jobs/{id}

Cancel a job that is still queued or processing. The job moves to canceled. A job that has already finished cannot be canceled.

curl -X DELETE https://api.rendley.com/v1/jobs/job_8f2c... \
  -H "Authorization: Bearer YOUR_API_KEY"

List your jobs

GET /v1/jobs

You normally poll a job by the id you got back, but you can also list jobs, for example to reconcile state after a restart.

Listing defaults to jobs created in Rendley (source_type=studio). Jobs you start over the API have source_type=api, so pass that filter to see them:

curl "https://api.rendley.com/v1/jobs?source_type=api" \
  -H "Authorization: Bearer YOUR_API_KEY"

Other filters narrow the list further:

Query param Type Description
source_type string Where the job came from. Pass api to list jobs you started over the API. Defaults to studio.
project_id string Only jobs tied to this project.
job_type string Only jobs of this type, e.g. export_video or transcription.
acknowledged boolean Filter by whether the job has been marked acknowledged.

Status codes

These are the codes you will see while starting and polling jobs.

StatusMeaning
200 OKThe poll or list call succeeded. Check the job’s status field for progress.
400 Bad RequestThe request body or query was invalid.
401 UnauthorizedThe API key is missing, malformed, or invalid. See Authentication.
402 Payment RequiredToo few credits for a billable operation.
403 ForbiddenThe key is valid but cannot access this resource, or a plan limit was reached.
404 Not FoundNo job with that id belongs to your account.
429 Too Many RequestsRate limited. Back off and retry.

A 4xx here is about the HTTP call itself. A job that was accepted but then failed during processing still returns 200 from GET /jobs/{id}, with status: "failed" and a reason in error.

Full reference

For the field-by-field schema of each job endpoint, see the Jobs reference, or the interactive Swagger document at api.rendley.com/swagger.