Rendering
Kick off a render job, choose between direct / template / project modes, poll for completion, and understand credit cost and output format.
A render is an asynchronous job. You POST /renders with a composition, get back a jobId, then either poll GET /renders/{jobId} or wait for a webhook. When the job completes, the response includes an outputUrl pointing at the finished MP4.
Three render modes
POST /renders accepts the same body shape for three different rendering modes. Send exactly one of inputProps, templateId, or projectId per request.
Mode 1 — direct (inputProps)
You supply the entire composition inline. Use this when you're building compositions programmatically and don't want them stored anywhere.
curl -X POST https://renderly.video/api/v1/renders \
-H "Authorization: Bearer rnd_..." \
-H "Content-Type: application/json" \
-d '{
"inputProps": {
"backgroundColor": "#0a0e27",
"overlays": [ /* ... */ ],
"durationInFrames": 180, "fps": 30,
"width": 1080, "height": 1920
}
}'The full overlay schema is in the overlays reference.
Mode 2 — template (templateId)
The composition lives in Renderly's public template gallery. You pass an ID and optional replacements:
curl -X POST https://renderly.video/api/v1/renders \
-H "Authorization: Bearer rnd_..." \
-H "Content-Type: application/json" \
-d '{
"templateId": "tpl_real_estate_v1",
"replacements": {
"propertyAddress": "456 Ocean Drive",
"agentName": "Jane Smith"
}
}'The server loads the template's composition from storage, applies your replacements to any overlay flagged isDynamic, and queues the render. List available templates via GET /templates.
Mode 3 — project (projectId)
The composition is one of your own saved projects (built in the editor or stored from a previous flow). Same payload shape as template mode:
curl -X POST https://renderly.video/api/v1/renders \
-H "Authorization: Bearer rnd_..." \
-H "Content-Type: application/json" \
-d '{
"projectId": "proj_abc123",
"replacements": {
"headline": "Q2 Recap",
"background": "https://your-cdn.example.com/q2-bg.mp4"
}
}'The project must belong to the same user as the API key. This is the workflow we recommend for "designer builds it once → engineer automates variations".
Optional overrides
width, height, fps, and durationInFrames can be set at the top level of the request body as overrides applied after the composition is loaded:
{
"templateId": "tpl_real_estate_v1",
"replacements": { /* ... */ },
"width": 1080,
"height": 1080,
"fps": 30
}Use them to render a 9:16 template at 1:1 without forking, or to crop the length down.
In direct mode, prefer setting these inside inputProps. Top-level values exist mainly so template / project renders can override stored defaults; in direct mode they're redundant. If both are set, the top-level value wins.
Polling for completion
curl https://renderly.video/api/v1/renders/<jobId> \
-H "Authorization: Bearer rnd_..."Response while in-flight:
{
"success": true,
"data": {
"jobId": "clx456def",
"status": "PROCESSING",
"progressPercentage": 42,
"estimatedTimeRemaining": 18,
"outputUrl": null
}
}Once done:
{
"success": true,
"data": {
"jobId": "clx456def",
"status": "COMPLETED",
"progressPercentage": 100,
"outputUrl": "https://renderly-output.s3.amazonaws.com/.../final.mp4",
"outputSize": 12458960,
"duration": 45000,
"completedAt": "2026-05-16T10:01:30Z"
}
}Possible status values: PENDING, PROCESSING, COMPLETED, FAILED. On FAILED the response carries a human-readable errorMessage.
Polling cadence: every 2–5 seconds is fine. For long renders (multi-minute output) every 10 seconds is plenty.
Hate polling? Register a webhook and Renderly will POST to your endpoint when the job finishes or fails. Includes an HMAC signature for verification.
Credit cost & pricing
- 1 credit = 1 minute of finished video at any resolution.
- Duration is rounded up to the nearest minute, per job. A 10-second render still costs 1 credit; a 65-second render costs 2.
- The cost is deducted when the job is queued. If the render fails for an internal reason, credits are refunded automatically.
- Each template can carry its own
creditsPerMinutemultiplier — most are 1, but premium templates can charge more. The exact figure comes back in the create response ascreditsUsed.
If you don't have enough credits the request fails with 402 Payment Required:
{
"success": false,
"error": "Insufficient credits",
"details": {
"creditsNeeded": 5,
"creditsAvailable": 2,
"creditsShort": 3
}
}Output format
Renderly produces an MP4 (H.264) file. The encoding is tuned for cross-platform playback — works in browsers, social platforms, and editing tools without conversion.
- Container: MP4
- Video codec: H.264 (libx264, high profile)
- Audio codec: AAC, embedded if the composition includes any sound overlays
The output URL points at S3 and is publicly readable. There's no expiry on the URL itself, but the file is retained according to your account's retention policy (visible in dashboard → Settings → Storage).
Creating a project alongside the render
By default, direct renders are one-offs — they don't get saved. To persist the composition (so you can re-render it via project mode later), opt in:
{
"inputProps": { /* ... */ },
"createProject": true,
"projectName": "Onboarding Video v2"
}The response then includes a projectId you can reuse.
Template renders create a project by default; pass createProject: false to opt out.
Errors at a glance
| Status | When |
|---|---|
400 Bad Request | Validation failure — bad overlay shape, missing required field, both inputProps and templateId, etc. |
401 Unauthorized | Missing / invalid API key. |
402 Payment Required | Not enough credits. |
403 Forbidden | Trying to render someone else's project, or a private template. |
404 Not Found | Template / project ID doesn't exist. |
Where to next
- Webhooks — get notified instead of polling
- Overlays reference — full schema for the
inputProps.overlaysarray - Templates — when to use template vs project mode