Skip to main content

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.

API Access Required

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

FieldTypeRequiredDescription
kind"movie"YesMust be "movie". Selects the scene-based render path.
projectIdstringYesThe project this render job belongs to. Visible in Dashboard → Projects.
movieMovieYesThe full Movie definition — scenes, layers, canvas settings. See Movie Schema.
renderOptionsRenderOptionsNoControls parallelism and performance. See Render Options.
callbackUrlstringNoA 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

FieldTypeDefaultDescription
qualityPreset"stable" | "balanced" | "fast" | "turbo""balanced"Controls how many scene workers run in parallel. Does not affect visual quality — a higher preset renders faster.
requestedConcurrencyinteger 1–32derived from presetOverride the number of parallel scene workers directly.
PresetParallel scene workersBest for
stable2Debugging; predictable scene ordering
balanced3Most use cases (default)
fast4Short videos (≤5 scenes)
turbo6Long 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

StatusCodeCause
400INVALID_MOVIE_JSONThe movie object failed validation. Check that all id fields are present, duration > 0, and required layer fields exist.
400PLAN_RESOLUTION_EXCEEDEDThe requested width × height exceeds your plan's maximum resolution. Reduce dimensions or upgrade.
400PLAN_DURATION_EXCEEDEDTotal scene duration exceeds your plan's per-job limit (10 min on Free/Pro, 20 min on Business).
401UNAUTHORIZEDMissing or invalid x-api-key header.
402RENDER_QUOTA_EXCEEDEDMonthly render minute limit reached. Wait for monthly reset or upgrade.
402RENDER_QUOTA_DAILY_EXCEEDEDFree-plan daily cap (5 min/day) reached. Resets at midnight UTC.
403FORBIDDENYour plan does not include API access. Upgrade to Pro.
409CONCURRENCY_LIMIT_EXCEEDEDYou have reached the maximum number of concurrent running jobs for your plan. Wait for a job to complete.
429RATE_LIMITEDToo 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 →