Rendering and download

Queue the mp4 that turns a generated video into a file, poll its progress, and get a download URL that is known to resolve.

Rendering is the second of a video's two jobs. Generation produces the script, the voiceover, the transcript and the visuals; the render turns all of that into one mp4.

Rendering is asynchronous and can take longer than generation. POST /videos/{id}/render returns as soon as the job is queued, with render.status: "QUEUED". Poll GET /videos/{id}/render, or subscribe to video.render_completed.

Queue a render

curl -X POST https://app.shortfast.com/api/v1/videos/7bQxL2mF9dR4tK1sv/render \
  -H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: 8c3f1b90-77aa-4e51-b0d2-1e9f4a6c2d33"

The call clears any previous renderUrl, because the file it pointed at is about to be replaced. Passing process.render: true when the video is created (or on POST /videos/{id}/process) chains the render automatically as soon as generation finishes, which saves a poll-then-call round trip.

Poll the render

GET /videos/{id}/render is the cheap endpoint to poll: it returns the render job and the collapsed lifecycle status, without the rest of the video.

curl https://app.shortfast.com/api/v1/videos/7bQxL2mF9dR4tK1sv/render \
  -H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx"
{
  "data": {
    "videoId": "7bQxL2mF9dR4tK1sv",
    "status": "rendering",
    "render": {
      "status": "STARTED",
      "progress": 62,
      "queuedAt": "2026-08-06T09:18:02.000Z",
      "startedAt": "2026-08-06T09:18:05.000Z",
      "error": null
    },
    "renderUrl": null
  }
}

render.status is QUEUED, STARTED, COMPLETED or FAILED, and render.progress is a percentage from 0 to 100. status is the collapsed lifecycle value (draft, processing, rendering, ready, failed), the same one GET /videos filters on: poll on it if you only care whether the video is usable yet.

Never queue a second render for a video that is already QUEUED or STARTED. Use an Idempotency-Key so a retry after a client timeout replays the first response rather than starting the work twice.

When a render is refused

A render charges credits in proportion to the video's duration and counts against the monthly render limit, so it can be refused before the job is queued:

CodeWhyWhat clears it
warning-no-creditsThe balance will not cover this video's durationBuy credits
warning-plan-rendersThe plan's monthly render limit is used upUpgrade
warning-plan-render-timeThis video is longer than the plan's per-render ceilingUpgrade

The refusal arrives as a 400 with that code. The same vocabulary comes back on render.error.code when a job fails after it started, alongside error.blocked (an expected limit rather than a crash) and error.action (the fix: upgrade, credits, connect, configure or none).

Read the live ceilings for the connected workspace from GET /workspace (limits.maxRendersPerMonth, limits.maxRenderSeconds) or, with the counters already used, from GET /stats. maxRendersPerMonth is null on plans that do not cap renders, and it caps generations too. See Credits and limits.

Download the file

curl https://app.shortfast.com/api/v1/videos/7bQxL2mF9dR4tK1sv/download \
  -H "Authorization: Bearer sf_live_xxxxxxxxxxxxxxxxxxxxxxxx"
{
  "data": {
    "videoId": "7bQxL2mF9dR4tK1sv",
    "url": "https://cdn.shortfast.com/uploads/renders/7bQxL2mF9dR4tK1sv.mp4"
  }
}

Use this endpoint rather than caching media.renderUrl. For type: ai the finished video is stitched from its per-scene clips on demand, and a stored URL that no longer resolves is rebuilt rather than handed back dead. That work is why the call can take a few seconds, and why it is the only URL guaranteed to resolve.

A video with no render yet is refused with 400 warning-source-not-ready. media.renderUrl on the video document is still useful as a signal (it is null until a render completes, and cleared whenever the output goes stale), just not as a durable link.

Anything that invalidates the stitched output clears renderUrl for you: adding, editing or removing an AI scene, regenerating a scene's still, or queuing a fresh render. Re-render before publishing after any of those.

Reference

On this page