Render API
Submit a video render job from a Movie JSON definition. The job is queued and executed asynchronously. You receive a jobId immediately and can track progress via polling or Server-Sent Events.
Rendering via the API requires a Pro plan or higher. See Plans & Limits.
POST /v1/render/jobs
Endpoint: https://api.viralsync.io/v1/render/jobs
Authentication: x-api-key header
Content-Type: application/json
Response: 202 Accepted
Request Body
The request body is a JSON object with kind: "movie".
Top-level fields
| Field | Type | Required | Description |
|---|---|---|---|
kind | "movie" | Yes | Must be "movie". Selects the scene-based render path. |
projectId | string | Yes | The project this render job belongs to. Visible in Dashboard → Projects. |
movie | Movie | Yes | The full Movie definition — scenes, layers, canvas settings. See Movie Schema. |
renderOptions | RenderOptions | No | Controls parallelism and performance. See Render Options. |
callbackUrl | string | No | A webhook URL. ViralSync will POST progress and completion events to this URL. See Webhooks. |
movie object
The movie field accepts the following structure. All fields except scenes are optional:
{
"id": "string (optional — used for scene caching)",
"title": "string (optional — display label)",
"width": 1920,
"height": 1080,
"fps": 30,
"scenes": [ /* Scene[] — at least 1 required */ ]
}
Full property reference: Movie, Scene & Layer Schema →
renderOptions object
| Field | Type | Default | Description |
|---|---|---|---|
qualityPreset | "stable" | "balanced" | "fast" | "turbo" | "balanced" | Controls how many scene workers run in parallel. Does not affect visual quality — a higher preset renders faster. |
requestedConcurrency | integer 1–32 | derived from preset | Override the number of parallel scene workers directly. |
| Preset | Parallel scene workers | Best for |
|---|---|---|
stable | 2 | Debugging; predictable scene ordering |
balanced | 3 | Most use cases (default) |
fast | 4 | Short videos (≤5 scenes) |
turbo | 6 | Long videos on Business+ plans |
Minimal request example
curl -X POST https://api.viralsync.io/v1/render/jobs \
-H "x-api-key: vs_prod_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"kind": "movie",
"projectId": "proj_abc123",
"movie": {
"width": 1920,
"height": 1080,
"fps": 30,
"scenes": [
{
"id": "scene_1",
"duration": 5,
"bgColor": "#1a1a2e",
"layers": [
{
"id": "headline",
"type": "text",
"text": "Hello from the API",
"startTime": 0,
"duration": 5,
"zIndex": 1,
"position": { "x": 360, "y": 460 },
"size": { "width": 1200, "height": 160 },
"fontSize": 80,
"fontWeight": "bold",
"color": "#ffffff",
"textAlign": "center"
}
]
}
]
}
}'
Full request example (with media layers and options)
curl -X POST https://api.viralsync.io/v1/render/jobs \
-H "x-api-key: vs_prod_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"kind": "movie",
"projectId": "proj_abc123",
"callbackUrl": "https://your-server.com/webhooks/viralsync",
"renderOptions": {
"qualityPreset": "fast"
},
"movie": {
"id": "summer_promo_v3",
"title": "Summer Promo — Final Cut",
"width": 1920,
"height": 1080,
"fps": 30,
"scenes": [
{
"id": "scene_opening",
"name": "Opening",
"duration": 6,
"bgColor": "#000000",
"layers": [
{
"id": "bg_video",
"type": "video",
"role": "background",
"source": "https://cdn.example.com/footage/city.mp4",
"startTime": 0,
"duration": 6,
"zIndex": 0,
"position": { "x": 0, "y": 0 },
"size": { "width": 1920, "height": 1080 },
"mute": true,
"transform": { "opacity": 0.65 }
},
{
"id": "bg_music",
"type": "audio",
"source": "https://cdn.example.com/audio/upbeat.mp3",
"startTime": 0,
"duration": 6,
"zIndex": 0,
"position": { "x": 0, "y": 0 },
"size": { "width": 0, "height": 0 },
"volume": 0.35
},
{
"id": "logo",
"type": "image",
"source": "https://cdn.example.com/brand/logo-white.png",
"startTime": 0.5,
"duration": 5,
"zIndex": 2,
"position": { "x": 80, "y": 60 },
"size": { "width": 200, "height": 60 }
},
{
"id": "title",
"type": "text",
"text": "Summer Sale — Up to 50% Off",
"startTime": 1,
"duration": 4,
"zIndex": 3,
"position": { "x": 200, "y": 400 },
"size": { "width": 1520, "height": 200 },
"fontSize": 96,
"fontWeight": "bold",
"color": "#ffffff",
"textAlign": "center",
"transform": { "opacity": 0.95 }
}
]
},
{
"id": "scene_cta",
"name": "Call to Action",
"duration": 4,
"bgColor": "#0f172a",
"layers": [
{
"id": "cta",
"type": "text",
"text": "Shop now at example.com",
"startTime": 0,
"duration": 4,
"zIndex": 1,
"position": { "x": 360, "y": 460 },
"size": { "width": 1200, "height": 160 },
"fontSize": 64,
"color": "#00d4ff",
"textAlign": "center",
"fontWeight": "600"
}
]
}
]
}
}'
Success response
HTTP 202 Accepted:
{
"jobId": "job_a1b2c3d4e5f6",
"status": "queued"
}
Use the jobId to poll status via GET /v1/jobs/{jobId} or stream real-time progress via GET /v1/jobs/{jobId}/progress.
Error responses
| Status | Code | Cause |
|---|---|---|
400 | INVALID_MOVIE_JSON | The movie object failed validation. Check that all id fields are present, duration > 0, and required layer fields exist. |
400 | PLAN_RESOLUTION_EXCEEDED | The requested width × height exceeds your plan's maximum resolution. Reduce dimensions or upgrade. |
400 | PLAN_DURATION_EXCEEDED | Total scene duration exceeds your plan's per-job limit (10 min on Free/Pro, 20 min on Business). |
401 | UNAUTHORIZED | Missing or invalid x-api-key header. |
402 | RENDER_QUOTA_EXCEEDED | Monthly render minute limit reached. Wait for monthly reset or upgrade. |
402 | RENDER_QUOTA_DAILY_EXCEEDED | Free-plan daily cap (5 min/day) reached. Resets at midnight UTC. |
403 | FORBIDDEN | Your plan does not include API access. Upgrade to Pro. |
409 | CONCURRENCY_LIMIT_EXCEEDED | You have reached the maximum number of concurrent running jobs for your plan. Wait for a job to complete. |
429 | RATE_LIMITED | Too many API requests. Back off and retry after the Retry-After header value. |
Full error reference: Error Codes →
How the job progresses
After submission, the job moves through the following phases:
queued → planning → dispatching → waiting → rendering → assembling → uploading → done
Each phase is reflected in the status and phase fields returned by GET /v1/jobs/{jobId}. See Render Pipeline for a detailed explanation of each phase.
Webhooks
For production systems, use the callbackUrl field instead of polling. ViralSync posts events to your URL as the job progresses:
{
"jobId": "job_a1b2c3d4e5f6",
"status": "done",
"progress": 1.0,
"outputUrl": "https://r2.viralsync.io/outputs/job_a1b2c3d4e5f6/output.mp4",
"mediaData": {
"duration": 10.0,
"width": 1920,
"height": 1080
}
}
Full webhook guide: Webhooks →
Related
- Movie, Scene & Layer Schema — every field explained
- Render Options Reference — quality presets, concurrency
- Jobs API — polling, SSE streaming, cancellation
- Render Pipeline — how scenes are executed in parallel