/api/function/video-generation/* · developer reference

JSON-to-video API

One X-API-Key to turn structured JSON into finished video. Combine images, video, voice-over, music and captions — submit a generation job, poll its progress, and pull the rendered MP4. Mix, simple and loop builders share the same contract.

Base URL
https://samautomation.work/api
Auth header
X-API-Key
Request format
application/json
Flow
submit · poll · collect
On this page
// overview

API Overview

The JSON-to-video API offers a powerful set of features for video generation, letting you easily create professional videos from images, videos, audio and text — all driven by a single JSON payload.

Key features
  • Mix Video Generation — combine images, videos, voice-overs and background music.
  • Simple Video Generation — create a video from a single media file.
  • Loop Video Generation — create looping videos with a background and media files.
  • Video Progress Tracking — track the progress of your generation task.
  • Video Credits Management — purchase and manage video credits.

Getting started

To start using the JSON-to-video API you need an API key:

  1. Log in to your account.
  2. Navigate to Account Settings > API Keys.
  3. Generate a new API key.
  4. Send this key with every API request in the X-API-Key header.
// authentication

Authentication

All API requests require an API key. Send it in the X-API-Key header. Query-parameter auth is still supported for legacy clients, but the header is recommended.

Adding an API key

X-API-Key: your_api_key_here
Important: API key security Protect your API key to prevent unauthorized use.
  • Never share your API key publicly.
  • Do not store it in public repositories or code.
  • If you suspect your key is compromised, generate a new one immediately.
  • Use environment variables to store your API key in your codebase.

Example API request

POST /api/function/video-generation/mix-video
curl -X POST "https://samautomation.work/api/function/video-generation/mix-video" \
    -H "X-API-Key: your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{"data": {...}}'
// limits

Rate Limiting

Understanding rate limits and quotas:

Plan limits
PlanVideo limitReset period
Free Tier5 videosMonthly (1st of month)
Basic50 videosMonthly
Pro100 videosMonthly

Rate limit headers

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 45
// quickstart

Basic API Usage

Create your first video with this simple example. Media fields must contain final public http or https URLs, not local file paths or unresolved workflow expressions.

{
  "type": "video",
  "data": {
    "settings": {
      "aspect_ratio": "9:16",
      "background_volume": 0.02,
      "voice_volume": 1.0
    },
    "background_url": "https://cdn.example.com/background-music.mp3",
    "voice_url": "https://cdn.example.com/voice-over.mp3",
    "media_list": [
      {
        "type": "image",
        "url": "https://cdn.example.com/intro-frame.jpg"
      }
    ]
  }
}
// workflow validation

n8n Media URLs

When you submit a render from n8n, media_list[].url must contain the resolved media URL that the renderer can download. The API rejects unresolved n8n expressions before a render task starts.

Common n8n mistake If the API receives ={{ $('Code in JavaScript2').item.json.videoUrl }} as text, n8n did not resolve the expression. In the HTTP Request node, use Expression mode for that field or build the final JSON body in a Code node.
URL validation errors
StatusResponse bodyFix
400{"success": false, "message": "media_list[0].url must be a valid HTTP(S) URL"}Send a final https://... media URL, not an unresolved expression or relative path.
400{"success": false, "message": "Invalid payload shape"}Send a JSON object such as {"media_list":[...]}, not a JSON string or array.

Wrong n8n output

{
  "media_list": [
    {
      "type": "video",
      "url": "={{ $('Code in JavaScript2').item.json.videoUrl }}",
      "duration": 60
    }
  ]
}

Correct resolved output

{
  "media_list": [
    {
      "type": "video",
      "url": "https://cdn.example.com/rendered-product-video.mp4",
      "duration": 60
    }
  ],
  "settings": {
    "aspect_ratio": "9:16"
  }
}
// video generation

Mix Video Generation

Create a video by combining various media elements (images, videos, audio) with an optional voice-over and background media.

Endpoint

POST  /api/function/video-generation/mix-video

Request parameters
ParameterTypeRequiredDescription
X-API-Key (header)stringYesYour API key
Request body
ParameterTypeRequiredDescription
media_listarrayYesArray of media objects used in the video
settingsobjectNoVideo settings such as aspect_ratio, quality, etc.
voice_urlstringNoURL to a voice-over audio file
background_urlstringNoURL to a background image or video
transcriptsarrayNoArray of caption objects
Media list object
ParameterTypeRequiredDescription
urlstringYesPublic http or https URL to the media file
typestringYesMedia type ('image', 'video', 'audio')
durationnumberYesDuration in seconds to display this element
start_timenumberNoStart time within media file (for video/audio)
end_timenumberNoEnd time within media file (for video/audio)
text_overlaystringNoText to overlay on the media
Settings object
ParameterTypeDefaultDescription
aspect_ratiostring"16:9"Aspect ratio of the video ("16:9", "1:1", "9:16")
resolutionstring"720p"Resolution of the video ("480p", "720p", "1080p")
fpsnumber30Frames per second
qualitystring"medium"Quality of the video ("low", "medium", "high")

Example request

{
  "media_list": [
    {
      "url": "https://example.com/image1.jpg",
      "type": "image",
      "duration": 5,
      "text_overlay": "Welcome to our presentation"
    },
    {
      "url": "https://example.com/video1.mp4",
      "type": "video",
      "duration": 10,
      "start_time": 2,
      "end_time": 12
    }
  ],
  "voice_url": "https://example.com/voice.mp3",
  "background_url": "https://example.com/background.jpg",
  "settings": {
    "aspect_ratio": "16:9",
    "resolution": "720p"
  }
}

Response

{
  "success": true,
  "message": "Video generation started",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "progress_url": "/api/function/video-generation/progress/550e8400-e29b-41d4-a716-446655440000"
  }
}
Error responses
StatusResponse bodyDescription
400{"success": false, "message": "Invalid JSON data"}Invalid JSON in the request
400{"success": false, "message": "Invalid payload shape"}Request body or nested data value is not a JSON object
400{"success": false, "message": "No media items provided"}media_list is empty or missing
400{"success": false, "message": "media_list[0].url must be a valid HTTP(S) URL"}A media URL is missing, relative, private, or an unresolved workflow expression
401{"success": false, "message": "API key required"}API key is missing
403{"success": false, "message": "Invalid API key"}Invalid API key
403{"success": false, "message": "Free tier limit reached..."}Quota limit reached
500{"success": false, "message": "Internal server error"}Server error

Code example: Python

import requests
import json

api_key = "YOUR_API_KEY"
url = "https://samautomation.work/api/function/video-generation/mix-video"

# Video data
data = {
    "media_list": [
        {
            "url": "https://example.com/image1.jpg",
            "type": "image",
            "duration": 5,
            "text_overlay": "Welcome to our presentation"
        },
        {
            "url": "https://example.com/video1.mp4",
            "type": "video",
            "duration": 10
        }
    ],
    "voice_url": "https://example.com/voice.mp3",
    "background_url": "https://example.com/background.jpg",
    "settings": {
        "aspect_ratio": "16:9",
        "resolution": "720p"
    }
}

# API request
response = requests.post(
    url,
    headers={
        "X-API-Key": api_key,
        "Content-Type": "application/json",
    },
    data=json.dumps(data)
)

# Process the result
result = response.json()
if result["success"]:
    video_id = result["data"]["id"]
    progress_url = result["data"]["progress_url"]
    print(f"Video generation started. ID: {video_id}")
    print(f"Check progress at: {progress_url}")
else:
    print(f"Error: {result['message']}")

Code example: JavaScript

const apiKey = "YOUR_API_KEY";
const url = "https://samautomation.work/api/function/video-generation/mix-video";

// Video data
const data = {
    media_list: [
        {
            url: "https://example.com/image1.jpg",
            type: "image",
            duration: 5,
            text_overlay: "Welcome to our presentation"
        },
        {
            url: "https://example.com/video1.mp4",
            type: "video",
            duration: 10
        }
    ],
    voice_url: "https://example.com/voice.mp3",
    background_url: "https://example.com/background.jpg",
    settings: {
        aspect_ratio: "16:9",
        resolution: "720p"
    }
};

// API request
fetch(url, {
    method: "POST",
    headers: {
        "X-API-Key": apiKey,
        "Content-Type": "application/json"
    },
    body: JSON.stringify(data)
})
.then(response => response.json())
.then(result => {
    if (result.success) {
        const videoId = result.data.id;
        const progressUrl = result.data.progress_url;
        console.log(`Video generation started. ID: ${videoId}`);
        console.log(`Check progress at: ${progressUrl}`);
    } else {
        console.error(`Error: ${result.message}`);
    }
})
.catch(error => console.error("API call failed:", error));
// video generation

Simple Video Generation

Create a simple video with a single media file.

Endpoint

POST  /api/function/video-generation/simple-video

Request parameters
ParameterTypeRequiredDescription
X-API-Key (header)stringYesYour API key
Request body
ParameterTypeRequiredDescription
media_listarrayYesArray with one or more media objects. Each item must include type and url.
settingsobjectNoVideo settings such as aspect_ratio, quality, etc.

Example request

{
  "media_list": [
    {
      "type": "video",
      "url": "https://example.com/video.mp4"
    }
  ],
  "settings": {
    "aspect_ratio": "16:9",
    "quality": "high"
  }
}

Response

{
  "success": true,
  "message": "Video generation started",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "progress_url": "/api/function/video-generation/progress/550e8400-e29b-41d4-a716-446655440000"
  }
}
Error responses
StatusResponse bodyDescription
400{"success": false, "message": "Invalid JSON data"}Invalid JSON in the request
400{"success": false, "message": "Invalid payload shape"}Request body or nested data value is not a JSON object
400{"success": false, "message": "No media items provided"}media_list is empty or missing
400{"success": false, "message": "media_list[0].url must be a valid HTTP(S) URL"}A media URL is missing, relative, private, or an unresolved workflow expression
401{"success": false, "message": "API key required"}API key is missing
403{"success": false, "message": "Invalid API key"}Invalid API key
403{"success": false, "message": "Free tier limit reached..."}Quota limit reached
500{"success": false, "message": "Internal server error"}Server error

Code example: Python

import requests
import json

api_key = "YOUR_API_KEY"
url = "https://samautomation.work/api/function/video-generation/simple-video"

# Video data
data = {
    "media_list": [
        {
            "type": "video",
            "url": "https://example.com/video.mp4",
        }
    ],
    "settings": {
        "aspect_ratio": "16:9",
        "quality": "high"
    }
}

# API request
response = requests.post(
    url,
    headers={
        "X-API-Key": api_key,
        "Content-Type": "application/json",
    },
    data=json.dumps(data)
)

# Process the result
result = response.json()
if result["success"]:
    video_id = result["data"]["id"]
    progress_url = result["data"]["progress_url"]
    print(f"Video generation started. ID: {video_id}")
    print(f"Check progress at: {progress_url}")
else:
    print(f"Error: {result['message']}")

Code example: JavaScript

const apiKey = "YOUR_API_KEY";
const url = "https://samautomation.work/api/function/video-generation/simple-video";

// Video data
const data = {
    media_list: [
        {
            type: "video",
            url: "https://example.com/video.mp4"
        }
    ],
    settings: {
        aspect_ratio: "16:9",
        quality: "high"
    }
};

// API request
fetch(url, {
    method: "POST",
    headers: {
        "X-API-Key": apiKey,
        "Content-Type": "application/json"
    },
    body: JSON.stringify(data)
})
.then(response => response.json())
.then(result => {
    if (result.success) {
        const videoId = result.data.id;
        const progressUrl = result.data.progress_url;
        console.log(`Video generation started. ID: ${videoId}`);
        console.log(`Check progress at: ${progressUrl}`);
    } else {
        console.error(`Error: ${result.message}`);
    }
})
.catch(error => console.error("API call failed:", error));
// video generation

Loop Video Generation

Create looping videos with background and media files.

Endpoint

POST  /api/function/video-generation/loop-video

Request parameters
ParameterTypeRequiredDescription
X-API-Key (header)stringYesYour API key
Request body
ParameterTypeRequiredDescription
typestringYesMust be LoopVideo
dataobjectYesContainer for loop-video payload fields
data.media_listarrayYesArray of media items used in the loop video
data.background_urlstringYesURL to a background image or video
data.durationnumberNoOptional output duration in seconds (must be positive)
data.settingsobjectNoVideo settings such as aspect_ratio and quality
Media list object
ParameterTypeRequiredDescription
urlstringYesURL to the media file
typestringYesMedia type ('image', 'video', 'audio')
durationnumberYesDuration in seconds to display this element
start_timenumberNoStart time within media file (for video/audio)
end_timenumberNoEnd time within media file (for video/audio)
text_overlaystringNoText to overlay on the media
Settings object
ParameterTypeDefaultDescription
aspect_ratiostring"16:9"Aspect ratio of the video ("16:9", "1:1", "9:16")
resolutionstring"720p"Resolution of the video ("480p", "720p", "1080p")
fpsnumber30Frames per second
qualitystring"medium"Quality of the video ("low", "medium", "high")

Example request

{
  "type": "LoopVideo",
  "data": {
    "media_list": [
      {
        "url": "https://example.com/image1.jpg",
        "type": "image",
        "duration": 5
      }
    ],
    "background_url": "https://example.com/background.jpg",
    "duration": 15,
    "settings": {
      "aspect_ratio": "16:9",
      "resolution": "720p"
    }
  }
}

Response

{
  "success": true,
  "message": "Video generation started",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "celery_task_id": "c8a67f60-2e65-4fa1-9be2-1ffaf8b6f9c5"
  }
}
Error responses
StatusResponse bodyDescription
400{"success": false, "message": "Invalid JSON data"}Invalid JSON in the request
400{"success": false, "message": "Invalid video type. Only 'LoopVideo' is supported."}type is missing or not LoopVideo
400{"success": false, "message": "Background URL is required"}data.background_url is missing
401{"success": false, "message": "API key required"}API key is missing
403{"success": false, "message": "Invalid API key"}Invalid API key
403{"success": false, "message": "Free tier limit reached..."}Quota limit reached
500{"success": false, "message": "Internal server error"}Server error

Code example: Python

import requests
import json

api_key = "YOUR_API_KEY"
url = "https://samautomation.work/api/function/video-generation/loop-video"

# Video data
data = {
    "type": "LoopVideo",
    "data": {
        "media_list": [
            {
                "url": "https://example.com/image1.jpg",
                "type": "image",
                "duration": 5
            }
        ],
        "background_url": "https://example.com/background.jpg",
        "duration": 15,
        "settings": {
            "aspect_ratio": "16:9",
            "resolution": "720p"
        }
    }
}

# API request
response = requests.post(
    url,
    headers={
        "X-API-Key": api_key,
        "Content-Type": "application/json",
    },
    data=json.dumps(data)
)

# Process the result
result = response.json()
if result["success"]:
    video_id = result["data"]["id"]
    progress_url = f"/api/function/video-generation/progress/{video_id}"
    print(f"Video generation started. ID: {video_id}")
    print(f"Check progress at: {progress_url}")
else:
    print(f"Error: {result['message']}")

Code example: JavaScript

const apiKey = "YOUR_API_KEY";
const url = "https://samautomation.work/api/function/video-generation/loop-video";

// Video data
const data = {
    type: "LoopVideo",
    data: {
        media_list: [
            {
                url: "https://example.com/image1.jpg",
                type: "image",
                duration: 5
            }
        ],
        background_url: "https://example.com/background.jpg",
        duration: 15,
        settings: {
            aspect_ratio: "16:9",
            resolution: "720p"
        }
    }
};

// API request
fetch(url, {
    method: "POST",
    headers: {
        "X-API-Key": apiKey,
        "Content-Type": "application/json"
    },
    body: JSON.stringify(data)
})
.then(response => response.json())
.then(result => {
    if (result.success) {
        const videoId = result.data.id;
        const progressUrl = `/api/function/video-generation/progress/${videoId}`;
        console.log(`Video generation started. ID: ${videoId}`);
        console.log(`Check progress at: ${progressUrl}`);
    } else {
        console.error(`Error: ${result.message}`);
    }
})
.catch(error => console.error("API call failed:", error));
// video management

Task Status Details

Understanding video task statuses:

StatusDescription
pendingTask is queued for processing
processingVideo is being generated
completedVideo is ready for download
failedTask failed with error
cancelledTask was cancelled by user
timeoutTask timed out after inactivity
// video management

Advanced Settings

Customize your video generation with these advanced settings parameters:

Video layout settings — configure the appearance and dimensions of your video
ParameterTypeDefaultDescription
aspect_ratiostring"16:9"Sets the aspect ratio of the video. Options: "16:9" (landscape), "9:16" (vertical/shorts), "1:1" (square)
resolutionstring"720p"Sets the resolution quality. Options: "480p", "720p", "1080p"
fpsnumber24Frames per second for the video
Audio settings — control audio levels and mixing
ParameterTypeDefaultDescription
background_volumenumber0.7Background music volume level (0.0-1.0). Lower values make background music quieter.
voice_volumenumber1.0Voice-over volume level (0.0-1.0). The API automatically boosts voice volume by 20%.
Caption settings — control the appearance and behavior of captions
ParameterTypeDefaultDescription
disable_captionsbooleanfalseWhen set to true, disables caption display while preserving timing information
caption_stylestringnullCaption style. Set to "impact" to use Impact font with dynamic styling
fontstring"bangers"Font to use for captions. Options: "bangers", "mandarin", "montserrat", "montserrat-italic", or fallback to "Impact"
font_sizenumber110Font size for captions (60-200). Automatically scales down if text is too wide.
text_colorstring"white"Color of caption text. Use color names ("white", "yellow", etc.) or hex codes.
stroke_colorstring"black"Color of the text outline/stroke. Use color names or hex codes.
stroke_widthnumber10Width of the text outline/stroke (1-10). Higher values create thicker outlines.

Example settings object

{
  "settings": {
    "aspect_ratio": "9:16",
    "background_volume": 0.3,
    "voice_volume": 1.0,
    "font": "montserrat",
    "font_size": 120,
    "text_color": "yellow",
    "stroke_color": "black",
    "stroke_width": 5,
    "caption_style": "impact",
    "disable_captions": false
  }
}
Media-specific behaviors Additional behaviors to keep in mind.

Image animation

Images automatically receive a subtle zoom effect alternating between zoom-in and zoom-out based on their position in the media list:

  • Even-indexed images: Zoom out (1.1x → 1.0x)
  • Odd-indexed images: Zoom in (1.0x → 1.1x)

Video durations

The system handles video durations as follows:

  • When not specified, videos use their actual duration.
  • The last video automatically gets a 2-second freeze frame of its last frame added.
  • Images get 6 seconds by default (8 seconds for the last image).

Caption chunking

Captions longer than 3 words are automatically split into chunks of 3 words with alternating colors (white-white-yellow pattern) for better readability.

Audio handling

When both voice-over and background audio are present:

  • Background music is automatically ducked to 20% volume during voice sections.
  • Fade-in and fade-out effects are applied to background music.
  • If background music is shorter than the video, it loops automatically.
// advanced features

Video Support

You can use videos in your projects alongside images. Mix images and videos to make richer content.

Mixing images and videos Treat your media list like a box of media — some items are images, some are short video clips. You can use both in the same media list.

Special behavior — last-clip freeze frame

When you place a video at the very end of your media list, the last frame of that video is held on screen for 2 extra seconds — a clean visual "end card" without extra text.

How to use videos

  1. Pick a video you want to include.
  2. Add it to your media list with type: "video".
  3. The video plays for exactly its own length (its "original duration").
  4. If it is the last video in your list, the last frame is shown for 2 extra seconds.
Image
Shows for 5 seconds
Video
Plays for its length
Last Video
+2 seconds at end

Example: mixing images and videos

{
  "type": "video",
  "data": {
    "settings": {
      "aspect_ratio": "9:16"
    },
    "media_list": [
      {
        "type": "image",
        "url": "https://example.com/my_picture.jpg",
      },
      {
        "type": "video",
        "url": "https://example.com/my_video.mp4"
        // No need for duration! We use the video's actual length
      },
      {
        "type": "video",
        "url": "https://example.com/my_last_video.mp4"
        // This is the last video, so its last frame will stay for 2 extra seconds!
      }
    ]
  }
}
Tips for using videos
  • Use short videos (5-15 seconds) for the best results.
  • Make sure your videos match your images in style and colors.
  • Put your most important video at the end to get that special 2-second freeze frame.
  • Videos with no sound work best (the API uses your voice-over and music).
// advanced features

Audio Options

Configure audio settings for your video generation task:

{
  "voice_url": "https://example.com/voice.mp3",
  "background_url": "https://example.com/music.mp3",
  "settings": {
    "background_volume": 0.3,
    "voice_volume": 1.0
  }
}
// advanced features

Captions

Add captions to your video generation task:

{
  "transcripts": [
    {
      "text": "Caption text here",
      "start": 0,
      "end": 5
    }
  ]
}
// examples

Example Requests

Example requests for video generation tasks:

Basic image to video

{
  "data": {
    "background_url": "https://cdn.example.com/background-music.mp3",
    "voice_url": "https://cdn.example.com/voice-over.mp3",
    "media_list": [
      {
        "type": "image",
        "url": "https://cdn.example.com/product-frame.jpg",
        "duration": 5
      }
    ],
    "transcripts": [
      {"words": "Here are your words", "start": 0, "end": 0.88},
      {"words": "Second caption line", "start": 0.88, "end": 1.76}
    ],
    "settings": {
      "aspect_ratio": "16:9",
      "background_volume": 0.15,
      "voice_volume": 1.0,
      "font_size": 120,
      "stroke_color": "green",
      "stroke_width": 10
    }
  }
}

Video generation process

Understanding the API workflow from request to finished file.

01 Initial request response

When you submit a video generation request, the API returns a task ID:

{
  "success": true,
  "message": "Video generation started",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "progress_url": "/api/function/video-generation/progress/550e8400-e29b-41d4-a716-446655440000"
  }
}
02 Check generation progress

Use the task ID to check the progress:

curl -X GET "http://localhost:8000/api/function/video-generation/progress/550e8400-e29b-41d4-a716-446655440000" \
-H "X-API-Key: YOUR_API_KEY"

Response during processing:

{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "processing",
    "progress": 0.45
  }
}
03 Final result

When processing is complete, the status endpoint returns:

{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "completed",
    "progress": 1.0,
    "output_url": "https://media.samautomation.work/videos/123/final.mp4"
  }
}
! Error handling

If an error occurs during processing:

{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "failed",
    "error": "Invalid media URL provided"
  }
}
Best practices
  • Poll the status endpoint every 5 seconds.
  • Implement exponential backoff if needed.
  • Cache the video URL once completed.
  • Handle timeout scenarios (typical processing time: 30-60 seconds).
// billing

Subscription Management

Manage your subscription and video credits:

Available endpoints

# Buy video pack
POST /api/video-packs/{pack_id}/buy/

# Stripe webhook for payment processing
POST /api/video-packs/webhook/

# List recent tasks
GET /api/function/video-generation/tasks

# Summarize usage for the last 30 days
GET /api/function/video-generation/usage-summary?days=30

Subscription response example

{
  "subscription": {
    "plan": "Pro",
    "active": true,
    "videos_remaining": 45,
    "period_reset_date": "2024-04-01T00:00:00Z",
    "extra_credits": 10
  }
}

Ship your first video

One key, one JSON payload, one finished MP4. White-label and ready for your pipeline.