Quickstart: Your First Render in 5 Minutes
This guide takes you from zero to a rendered MP4 file using only curl. No SDK, no setup — just HTTP.
API access requires a Pro plan or higher. Free-plan users can render videos through the visual editor in the dashboard. See plans →
Prerequisites
- A ViralSync account (sign up)
- An API key — create one in Dashboard → Settings → API Keys
- A project ID — visible in Dashboard → Projects or in the URL when you open a project
curlinstalled (macOS/Linux built-in; Windows: Git Bash or WSL)
Step 1 — Set your credentials
Export your API key and project ID as environment variables so you don't have to repeat them:
export VIRALSYNC_API_KEY="vs_prod_YOUR_API_KEY_HERE"
export VIRALSYNC_PROJECT_ID="proj_abc123"
Test that your key works:
curl -s \
-H "x-api-key: $VIRALSYNC_API_KEY" \
https://api.viralsync.io/v1/me
Expected response:
{
"userId": "user_...",
"plan": "pro",
"email": "you@example.com"
}
If you see a 401 error, double-check your key in the dashboard.
Step 2 — Submit a render job
The core of the ViralSync API is the Movie JSON — a structured description of your video. Here is the smallest possible movie: one scene, one text layer, 5 seconds long.
Save this as movie.json:
{
"kind": "movie",
"projectId": "proj_abc123",
"movie": {
"width": 1920,
"height": 1080,
"fps": 30,
"scenes": [
{
"id": "scene_1",
"duration": 5,
"bgColor": "#1a1a2e",
"layers": [
{
"id": "title",
"type": "text",
"text": "Hello, ViralSync!",
"startTime": 0,
"duration": 5,
"zIndex": 1,
"position": { "x": 360, "y": 460 },
"size": { "width": 1200, "height": 160 },
"fontSize": 80,
"fontWeight": "bold",
"color": "#ffffff",
"textAlign": "center"
}
]
}
]
}
}
Submit it:
curl -s -X POST https://api.viralsync.io/v1/render/jobs \
-H "x-api-key: $VIRALSYNC_API_KEY" \
-H "Content-Type: application/json" \
-d @movie.json
You'll receive an immediate 202 Accepted response:
{
"jobId": "job_a1b2c3d4e5f6",
"status": "queued"
}
Save the jobId — you'll use it in the next step.
export JOB_ID="job_a1b2c3d4e5f6"
Step 3 — Poll for completion
Check the job status every few seconds until it reaches done:
curl -s \
-H "x-api-key: $VIRALSYNC_API_KEY" \
https://api.viralsync.io/v1/jobs/$JOB_ID
While the job is running, you'll see something like:
{
"jobId": "job_a1b2c3d4e5f6",
"status": "running",
"progress": 0.62,
"phase": "rendering"
}
Once it completes:
{
"jobId": "job_a1b2c3d4e5f6",
"status": "done",
"progress": 1.0,
"outputUrl": "https://r2.viralsync.io/outputs/job_a1b2c3d4e5f6/output.mp4",
"mediaData": {
"duration": 5.0,
"width": 1920,
"height": 1080
}
}
A 5-second, 1-scene text-only video typically renders in 5–15 seconds on a Pro plan. Longer videos with video/image layers take longer.
Poll loop in bash:
while true; do
RESPONSE=$(curl -s -H "x-api-key: $VIRALSYNC_API_KEY" \
https://api.viralsync.io/v1/jobs/$JOB_ID)
STATUS=$(echo $RESPONSE | python3 -c "import sys,json; print(json.load(sys.stdin)['status'])")
echo "Status: $STATUS"
if [ "$STATUS" = "done" ] || [ "$STATUS" = "failed" ] || [ "$STATUS" = "cancelled" ]; then
echo "$RESPONSE"
break
fi
sleep 3
done
Step 4 — Download your video
OUTPUT_URL=$(curl -s -H "x-api-key: $VIRALSYNC_API_KEY" \
https://api.viralsync.io/v1/jobs/$JOB_ID \
| python3 -c "import sys,json; print(json.load(sys.stdin)['outputUrl'])")
curl -L "$OUTPUT_URL" -o my-first-video.mp4
echo "Saved to my-first-video.mp4"
Open my-first-video.mp4 — you should see a 5-second video with white text on a dark background.
What you just built
Let's look at what the movie JSON did:
{
"kind": "movie", // tells the API this is a scene-based render
"projectId": "proj_abc123", // links the job to your project
"movie": {
"width": 1920, "height": 1080, "fps": 30, // 1080p at 30fps
"scenes": [{
"id": "scene_1", // unique identifier (used for caching)
"duration": 5, // this scene is 5 seconds long
"bgColor": "#1a1a2e", // dark blue background
"layers": [{
"id": "title",
"type": "text", // rendered as text (no source URL needed)
"text": "Hello, ViralSync!",
"startTime": 0, // appears at the very start of the scene
"duration": 5, // visible for the full 5 seconds
"zIndex": 1, // rendered on top of any background layers
"position": { "x": 360, "y": 460 }, // top-left of the text box
"size": { "width": 1200, "height": 160 }, // bounding box
"fontSize": 80,
"fontWeight": "bold",
"color": "#ffffff",
"textAlign": "center"
}]
}]
}
}
Adding video and image layers
To render with real media, add a video or image layer with a public source URL:
{
"id": "background_clip",
"type": "video",
"source": "https://cdn.example.com/footage/cityscape.mp4",
"startTime": 0,
"duration": 5,
"zIndex": 0,
"position": { "x": 0, "y": 0 },
"size": { "width": 1920, "height": 1080 },
"mute": true
}
The render worker downloads your media at render time. The source URL must be publicly accessible — no authentication headers, no short-lived presigned URLs. Use CDN URLs.
Next Steps
- Movie & Layer Schema — every property explained
- Render API Reference — all render job options
- Node.js Quickstart — integrate with Node.js
- Python Quickstart — integrate with Python
- Plans & Limits — render minutes and quotas
- Webhooks — get notified when a job completes (no polling)