1. Your first video
This chapter renders your first video with JSON2Video: a single still image with a "For Sale" text overlay. It introduces the four building blocks every JSON2Video movie has — scenes, elements, type, and src/text — and the duration property that controls how long each element stays on screen.
Prerequisites: none. If you have not done the Quickstart, that's fine — this tutorial reproduces the same render with annotations.
Throughline. Across all 16 chapters you will build a real-estate listing video for a single property at 123 Oak Street. By the end you will have a multi-scene listing with voice-over, subtitles, AI b-roll, variables, conditions, and webhook delivery. We start small: one image, one line of text.
Step 1 — A movie is a JSON document
The smallest valid JSON2Video movie is a scenes array with one scene. A scene must contain at least one element. Without elements there is nothing to render.
{
"scenes": [
{ "elements": [] }
]
}
This renders a 360p, 5-second black video. Not useful yet, but valid. Let's add content.
Step 2 — Add the property photo
Add an image element pointing at the exterior shot of the house. Every element needs a type field that tells JSON2Video what it is. For images, type is "image" and src is the public URL of the file.
{
"scenes": [
{
"elements": [
{
"type": "image",
"src": "https://cdn.json2video.com/assets/images/sample-house-front.jpg"
}
]
}
]
}
The image fills the canvas. Default resolution is small (640×360), so let's also pick a sensible movie size.
Step 3 — Set the canvas size
Add resolution: "full-hd" at the top level. This is the most common 16:9 size (1920×1080). Other valid values are documented in the Movie reference.
{
"resolution": "full-hd",
"scenes": [
{
"elements": [
{
"type": "image",
"src": "https://cdn.json2video.com/assets/images/sample-house-front.jpg"
}
]
}
]
}
Step 4 — Overlay a "For Sale" text
Elements in a scene stack from bottom to top in array order. Add a text element after the image so it appears on top. type: "text" requires a text field with the literal string to show.
{
"resolution": "full-hd",
"scenes": [
{
"elements": [
{
"type": "image",
"src": "https://cdn.json2video.com/assets/images/sample-house-front.jpg"
},
{
"type": "text",
"text": "FOR SALE — 123 Oak Street"
}
]
}
]
}
Step 5 — Control how long the scene lasts
By default an image element renders for the scene's duration; without a duration the scene runs for 5 seconds. To make a slower-paced 8-second card, set duration on each element. The scene takes the maximum of its elements' durations.
{
"resolution": "full-hd",
"scenes": [
{
"elements": [
{
"type": "image",
"src": "https://cdn.json2video.com/assets/images/sample-house-front.jpg",
"duration": 8
},
{
"type": "text",
"text": "FOR SALE — 123 Oak Street",
"duration": 8
}
]
}
]
}
Step 6 — Send it to the API
Submit the JSON with POST /v2/movies. You can use any HTTP client. Replace YOUR_API_KEY with the key from the Dashboard → API keys.
curl -X POST https://api.json2video.com/v2/movies \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d @movie.json
import { writeFileSync } from "node:fs";
const movie = JSON.parse(await import("node:fs").then(fs => fs.promises.readFile("movie.json", "utf8")));
const res = await fetch("https://api.json2video.com/v2/movies", {
method: "POST",
headers: {
"x-api-key": process.env.JSON2VIDEO_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify(movie),
});
const { project } = await res.json();
console.log("Project ID:", project);
import os, json, requests
with open("movie.json") as f:
movie = json.load(f)
r = requests.post(
"https://api.json2video.com/v2/movies",
headers={
"x-api-key": os.environ["JSON2VIDEO_API_KEY"],
"Content-Type": "application/json",
},
json=movie,
)
print("Project ID:", r.json()["project"])
<?php
$movie = json_decode(file_get_contents("movie.json"), true);
$ch = curl_init("https://api.json2video.com/v2/movies");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"x-api-key: " . getenv("JSON2VIDEO_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode($movie),
]);
$res = json_decode(curl_exec($ch), true);
echo "Project ID: " . $res["project"];
The response gives you a project ID. Poll GET /v2/movies?project=<id> until status is done, then download the url. See Get movie status for the polling contract.
The complete final JSON
{
"resolution": "full-hd",
"scenes": [
{
"elements": [
{
"type": "image",
"src": "https://cdn.json2video.com/assets/images/sample-house-front.jpg",
"duration": 8
},
{
"type": "text",
"text": "FOR SALE — 123 Oak Street",
"duration": 8
}
]
}
]
}
Expected output
An 8-second 1920×1080 MP4 showing the property photo with a centred "FOR SALE — 123 Oak Street" text card on top. Sample render: tutorial-01.mp4 (placeholder — see _assets for notes on sample URLs).
What you learned
- A JSON2Video movie is a JSON document with a
scenesarray. - A scene contains
elements. Every element has atype(image,text,video, …). - Element order in the array sets layering — later elements draw on top.
resolutionsets canvas size;durationsets how long an element renders.- You submit the JSON to
POST /v2/moviesand poll until the render is done.