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

Create movie

POST https://api.json2video.com/v2/movies

Submits a Movie JSON payload for rendering. The endpoint returns immediately with a project ID. The render runs asynchronously; clients poll GET /v2/movies for completion.

Request

Headers

Header Required Value
x-api-key yes API key issued from the dashboard.
Content-Type yes application/json

Query parameters

None.

Body

A JSON object that follows the Movie JSON syntax. The minimum valid body has a single scenes array (or, equivalently, a movie-level elements array with no scenes); everything else has defaults.

{
    "resolution": "full-hd",
    "scenes": [
        {
            "elements": [
                { "type": "video", "src": "https://example.com/video.mp4" }
            ]
        }
    ]
}

The body may also reference a saved template:

{
    "template": "your-template-id",
    "variables": { "headline": "Hello" }
}

Size limit

The request body can be up to 2 MB (2,097,152 bytes, counted in UTF-8 bytes). A larger body is rejected with 413 and "code": "movie_json_too_large", and nothing is created or charged:

{
    "message": "The movie JSON is too large: 2.35 MB (2,461,234 bytes). The maximum size of a movie JSON is 2 MB (2,097,152 bytes).",
    "code": "movie_json_too_large"
}

There is no separate limit on the number of scenes, elements or images: only the size of the JSON counts, and the length of your render is capped by your plan (see Plans). In practice, media URLs take most of the space in a large movie. A signed URL can be 1 KB or more, so a slideshow with hundreds of photos grows quickly. If you get near the limit:

  • use shorter media URLs (for example, your own short links or a CDN path instead of long signed URLs);
  • split a very long video into several movies.

Media files are downloaded while the movie renders, not when you submit it. If you use signed URLs that expire, give them enough lifetime to cover the whole render, especially when you submit many movies at once.

Idempotency

POST /v2/movies is not idempotent. Each call creates a new project, even with the same body. To deduplicate at the asset layer, set cache: true (default) on elements and on the movie — identical assets and identical movies are served from cache without re-rendering.

Response

200 OK

{
    "success": true,
    "project": "JkGxEoPRF9EgRb32",
    "timestamp": "2026-05-12T10:49:52.924Z"
}
Field Type Description
success boolean Always true on 200.
project string 16-character project identifier. Use it to poll status.
timestamp string ISO-8601 timestamp of the submission.

Errors

Status Message Cause
400 No movie JSON received Empty request body.
400 Error parsing movie JSON or the movie was empty Body is not valid JSON.
400 No valid movie JSON received Body parsed to null or non-object.
400 AWS keys cannot be sent in the movie (exports[0].destinations[0]). … A destination in exports carries AWS keys. The body also has "code": "aws_keys_in_movie". Save the keys in an Amazon S3 destination and reference it with id.
401 You exceeded the quota of movies in your plan. Please upgrade your plan to continue. Render quota exhausted.
401 Movie is larger ({w}x{h}) than your plan allowance ({w}x{h}) Resolution exceeds account plan.
404 Template not found Body references a template ID that does not exist or belongs to another account.
413 The movie JSON is too large: … The maximum size of a movie JSON is 2 MB (2,097,152 bytes). The body is over 2 MB. The body also has "code": "movie_json_too_large". See Size limit. Do not retry the same body.
413 Error creating movie: the movie record is larger than the database limit … The movie could not be saved because of its size. The body also has "code": "movie_record_too_large". This should not happen with a body under 2 MB; contact support.
500 Error creating movie: the movie JSON could not be stored. No movie was created; please try again. A temporary storage error. The body also has "code": "movie_json_not_stored". Nothing was created or charged. Retry with exponential backoff.
500 Error creating movie: … Server error. Retry with exponential backoff.
500 Error starting subprocess The render could not be started. Retry with exponential backoff.

Examples

cURL

curl --location --request POST 'https://api.json2video.com/v2/movies' \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "resolution": "full-hd",
    "scenes": [
      {
        "elements": [
          { "type": "text", "text": "Hello", "duration": 5 }
        ]
      }
    ]
  }'

Node.js

const res = await fetch("https://api.json2video.com/v2/movies", {
    method: "POST",
    headers: {
        "x-api-key": process.env.J2V_API_KEY,
        "Content-Type": "application/json"
    },
    body: JSON.stringify({
        resolution: "full-hd",
        scenes: [{ elements: [{ type: "text", text: "Hello", duration: 5 }] }]
    })
});
const { project } = await res.json();

Polling pattern

After submission, poll GET /v2/movies?project={id} every 5–10 seconds until status is done, error, or timeout.

async function waitForRender(projectId) {
    while (true) {
        const r = await fetch(`https://api.json2video.com/v2/movies?project=${projectId}`, {
            headers: { "x-api-key": process.env.J2V_API_KEY }
        });
        const { movie } = await r.json();
        if (["done", "error", "timeout"].includes(movie.status)) return movie;
        await new Promise(r => setTimeout(r, 5000));
    }
}

For production workflows, prefer a webhook destination over polling. See Webhooks.