Archived docs Get your API Key
Get started
Tutorials
Guides
Reference
Help for AI agents
🤖 AI Assistant

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 scenes array.
  • A scene contains elements. Every element has a type (image, text, video, …).
  • Element order in the array sets layering — later elements draw on top.
  • resolution sets canvas size; duration sets how long an element renders.
  • You submit the JSON to POST /v2/movies and poll until the render is done.

Next chapter

2. Images, videos & audios →