Story

Overview

The Story API enables you to generate professional video stories from text ideas or existing images using AI-powered video generation. The API supports two distinct workflows:

Automatic Mode

Streamlined endpoints that handle the entire video generation pipeline automatically:

  • POST /story/idea-2-video - Generate a complete video from a text idea
  • POST /story/url-2-video - Generate a complete video from a URL.
  • POST /story/images-2-video - Generate a video from your own images

Advanced Mode

Step-by-step workflow providing granular control over each stage:

  • POST /story - Create a storyboard with characters, environments, objects and scenes
  • POST /story/{story_id}/elements - Generate element images (optional)
  • POST /story/{story_id}/scenes - Generate scene images and narrations
  • POST /story/{story_id}/videos - Create videos from scenes
  • GET /story/{story_id} - Get story status and details

Quick Start Examples

Example 1: Generate Video from Idea (Automatic Mode)

import requests
import json

BASE_URL = "https://api.vimmerse.net"
API_KEY = "YOUR_API_KEY"

# Step 1: Create a story from an idea
url = f"{BASE_URL}/story/idea-2-video"
headers = {"X-Api-Key": API_KEY}

payload = {
    "idea": "Create a promotional video where cute animals play musical instruments in a sunny meadow",
    "title": "Musical Animals Story",
    "aspect_ratio": "9:16",
    "scene_count": 4,
    "image_tool": "Seedream",
    "video_tool": "Auto",
    "scene_duration": "5",
    "audio_option": json.dumps({
        "has_bg_music": True,
        "has_narration": True,
        "native_audio": False,
        "narrator": "Rachel"
    }),
    "language": "English",
    "webhook_url": "https://your-domain.com/webhook/callback"
}

try:
    response = requests.post(url, headers=headers, data=payload, timeout=60)
    response.raise_for_status()

    result = response.json()
    story_data = result["data"]
    story_id = story_data["id"]

    print(f"Story created successfully! Story ID: {story_id}")
    print(f"Status: {story_data['status']}")
    print(f"Progress: {story_data['progress_percentage']}%")

except requests.exceptions.RequestException as e:
    print(f"Error creating story: {e}")
    if hasattr(e, 'response') and e.response is not None:
        print(f"Response: {e.response.text}")
    exit(1)

Example 2: Generate Video from Images (Automatic Mode)

import requests
import json

BASE_URL = "https://api.vimmerse.net"
API_KEY = "YOUR_API_KEY"

url = f"{BASE_URL}/story/images-2-video"
headers = {"X-Api-Key": API_KEY}

payload = {
    "idea": "Create a cinematic promotional video showcasing these beautiful landscapes with smooth transitions",
    "title": "Landscape Showcase",
    "aspect_ratio": "16:9",
    "image_urls": [
        "https://example.com/images/landscape1.jpg",
        "https://example.com/images/landscape2.jpg",
        "https://example.com/images/landscape3.jpg",
        "https://example.com/images/landscape4.jpg"
    ],
    "video_tool": "Auto",
    "is_transition": True,
    "scene_duration": "5",
    "audio_option": json.dumps({
        "has_bg_music": True,
        "has_narration": False,
        "native_audio": False
    }),
    "language": "English"
}

try:
    response = requests.post(url, headers=headers, data=payload, timeout=60)
    response.raise_for_status()

    result = response.json()
    story_data = result["data"]
    print(f"Story created! ID: {story_data['id']}")

except requests.exceptions.RequestException as e:
    print(f"Error: {e}")
    exit(1)

Example 3: Polling for Story Completion

import requests
import time

BASE_URL = "https://api.vimmerse.net"
API_KEY = "YOUR_API_KEY"
STORY_ID = "your-story-id-here"

def get_story_status(story_id):
    """Retrieve the current status of a story."""
    url = f"{BASE_URL}/story/{story_id}"
    headers = {"X-Api-Key": API_KEY}

    try:
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()
        return response.json()["data"]
    except requests.exceptions.RequestException as e:
        print(f"Error retrieving story status: {e}")
        return None

# Poll until story is complete
max_attempts = 60  # Maximum 30 minutes (60 * 30 seconds)
attempt = 0

while attempt < max_attempts:
    story_data = get_story_status(STORY_ID)

    if not story_data:
        print("Failed to retrieve story status. Retrying...")
        time.sleep(30)
        attempt += 1
        continue

    status = story_data.get("status")
    progress = story_data.get("progress_percentage", 0)

    print(f"Status: {status} | Progress: {progress}%")

    if status == "success":
        video_url = story_data.get("video_url")
        if video_url:
            print(f"\n✓ Story completed successfully!")
            print(f"Video URL: {video_url}")

            # Download the video
            try:
                video_response = requests.get(video_url, stream=True, timeout=60)
                video_response.raise_for_status()

                output_path = "story_video.mp4"
                with open(output_path, "wb") as f:
                    for chunk in video_response.iter_content(chunk_size=8192):
                        f.write(chunk)
                print(f"Video downloaded to: {output_path}")
            except Exception as e:
                print(f"Error downloading video: {e}")
        break
    elif status == "fail":
        print("✗ Story generation failed. Please check the story details for more information.")
        break

    time.sleep(30)  # Wait 30 seconds before next check
    attempt += 1

if attempt >= max_attempts:
    print("Timeout: Story generation is taking longer than expected.")

Webhook Integration

Instead of polling, you can configure a webhook URL to receive notifications when story generation completes.

Setting Up Webhooks

Include the webhook_url parameter when creating a story:

payload = {
    "idea": "Your story idea here",
    "webhook_url": "https://your-domain.com/api/webhooks/story-complete",
    # ... other parameters
}

Webhook Payload

When the story completes, your webhook endpoint will receive a POST request with:

{
    "customer_id": "your-customer-id",
    "batch_id": "story-id-here",
    "status": "success"
}

Webhook Implementation Example

from flask import Flask, request, jsonify
import requests

app = Flask(__name__)

@app.route("/api/webhooks/story-complete", methods=["POST"])
def story_webhook():
    """Handle story completion webhook."""
    data = request.json

    customer_id = data.get("customer_id")
    story_id = data.get("batch_id")
    status = data.get("status")

    if status == "success":
        # Fetch full story details
        url = f"https://api.vimmerse.net/story/{story_id}"
        headers = {"X-Api-Key": "YOUR_API_KEY"}

        response = requests.get(url, headers=headers)
        story_data = response.json()["data"]

        # Process the completed story
        video_url = story_data.get("video_url")
        # ... your processing logic here

        return jsonify({"status": "received"}), 200

    return jsonify({"status": "received"}), 200

if __name__ == "__main__":
    app.run(port=5000)

Note: Your webhook endpoint must respond with a 2xx status code within 10 seconds, or the webhook may be retried.

[AUTO] Idea-to-Video

Creates a complete video automatically from a text idea using AI-powered story generation.

Workflow

Once submitted, Vimmerse automatically executes the following pipeline:

  1. Storyboard Generation - Creates a structured storyboard with characters, environments, objects, and scenes
  2. Element Image Creation - Generates consistent character, object, and environment images
  3. Scene Image Generation - Produces scene images based on the storyboard
  4. Narration Generation - Creates voice narrations for each scene (if enabled)
  5. Background Music - Generates appropriate background music (if enabled)
  6. Video Animation - Animates images into videos using the specified video tool
  7. Video Composition - Composes all scene videos into a final story video

Response

The API returns a story object containing:

  • id - Unique story identifier for tracking progress
  • status - Current processing status (new, processing, success, fail)
  • progress_percentage - Completion percentage (0-100)
  • video_url - Final video URL (available when status is success)

Monitor progress using GET /story/{story_id} or configure a webhook_url for automatic notifications.

Parameters

Parameter Type Required Default Description
idea string Yes - Detailed text description of your story concept. Be specific about characters, settings, actions, and style.
scene_count integer No 3 Number of scenes to generate. Maximum varies by subscription plan.
image_tool string No "Seedream" Image generation model. Options: Seedream, FluxTurbo, NanoBanana, QwenImage
video_tool string No "Auto" Animation method. Options: Auto, KlingAI, VeoFast, etc.
scene_duration string No "5" Duration per scene in seconds. Options: "5", "10". Ignored when narration is enabled.
aspect_ratio string No "16:9" Video aspect ratio. Options: 16:9, 4:3, 1:1, 3:4, 9:16
is_transition boolean No false If true, creates transition videos between scene images.
elements string (JSON) No null Initial elements to include. JSON string containing objects, characters, or environments arrays. Useful for product placement or character consistency.
audio_option string (JSON) No See below Audio configuration. JSON string with has_bg_music, has_narration, native_audio, narrator fields.
language string No "English" Language for narration and storyboard generation.
title string No "" Optional title for your story.
webhook_url string No null URL to receive completion notification via POST request.

Default Audio Options

{
    "has_bg_music": true,
    "has_narration": true,
    "native_audio": false,
    "narrator": "Rachel"
}

Example Request

import requests
import json

url = "https://api.vimmerse.net/story/idea-2-video"
headers = {"X-Api-Key": "YOUR_API_KEY"}

payload = {
    "idea": "Create a realistic winter commercial for SkinRevive Moisturiser set in snowy mountains. Three girls are on a winter camping trip. Show two girls outside the camp, dressed in warm jackets, taking fun photos together in the snowy mountains. Soft snowfall, visible cold breath, playful interaction. Meanwhile, one girl is sitting inside the tent, wrapped in a blanket, looking hesitant and afraid to step outside because of the cold and her dry, irritated hands. She peeks out while the others call her to join, but she hesitates. Then one girl comes inside the tent, sits with her, smiles, and shows SkinRevive Moisturiser. She gently applies it on her friend's dry hands. Show close-up macro shots: smooth creamy texture, instant hydration, natural skin transformation. The inside girl now feels confident. She steps outside slowly, smiles, and joins her friends. Show them laughing, posing, and taking photos of each other against the beautiful snowy mountain background. Natural warm emotions, winter glow, soft daylight. End with a clean hero shot of SkinRevive Moisturiser placed on a wooden camping table with snowflakes falling softly around it. Cinematic, high-detail, warm winter storytelling mood.",
    "title": "SkinRevive Winter Commercial",
    "aspect_ratio": "9:16",
    "scene_count": 5,
    "image_tool": "Seedream",
    "video_tool": "Auto",
    "scene_duration": "5",
    "audio_option": json.dumps({
        "has_bg_music": True,
        "has_narration": False,
        "native_audio": True
    }),
    "elements": json.dumps({
        "objects": [
            {
                "name": "SkinRevive Moisturiser",
                "description": "Style:cinematic, In a sleek glass jar with a frosted finish and an elegant silver lid. The luxurious cream has a marbled white color, giving an aura of purity and soothing relief. Its rich formulation is the solution to winter's touch.",
                "image_url":"https://dev-media.vimmerse.net/vimmerse-product/ai_images/4a6b359a-c347-4453-a6ff-109cd8616dc4/8i9vvs4.png"
            }
        ]
    }),
    "language": "English",
}

try:
    response = requests.post(url, headers=headers, data=payload, timeout=60)
    response.raise_for_status()

    result = response.json()
    story_data = result["data"]

    print(f"Story ID: {story_data['id']}")
    print(f"Status: {story_data['status']}")
    print(f"Used Credits: {story_data['used_credits']}")

except requests.exceptions.HTTPError as e:
    print(f"HTTP Error: {e}")
    print(f"Response: {e.response.text}")
except requests.exceptions.RequestException as e:
    print(f"Request failed: {e}")

Complete Example with Polling

This complete example creates a story, polls for completion, and downloads the final video:

import requests
import json
import time

BASE_URL = "https://api.vimmerse.net"
API_KEY = "YOUR_API_KEY"

# Step 1: Create the story
url = f"{BASE_URL}/story/idea-2-video"
headers = {"X-Api-Key": API_KEY}

payload = {
    "idea": "Create a realistic winter commercial for SkinRevive Moisturiser set in snowy mountains. Three girls are on a winter camping trip. Show two girls outside the camp, dressed in warm jackets, taking fun photos together in the snowy mountains. Soft snowfall, visible cold breath, playful interaction. Meanwhile, one girl is sitting inside the tent, wrapped in a blanket, looking hesitant and afraid to step outside because of the cold and her dry, irritated hands. She peeks out while the others call her to join, but she hesitates. Then one girl comes inside the tent, sits with her, smiles, and shows SkinRevive Moisturiser. She gently applies it on her friend's dry hands. Show close-up macro shots: smooth creamy texture, instant hydration, natural skin transformation. The inside girl now feels confident. She steps outside slowly, smiles, and joins her friends. Show them laughing, posing, and taking photos of each other against the beautiful snowy mountain background. Natural warm emotions, winter glow, soft daylight. End with a clean hero shot of SkinRevive Moisturiser placed on a wooden camping table with snowflakes falling softly around it. Cinematic, high-detail, warm winter storytelling mood.",
    "title": "SkinRevive Winter Commercial",
    "aspect_ratio": "9:16",
    "scene_count": 5,
    "image_tool": "Seedream",
    "video_tool": "Auto",
    "scene_duration": "5",
    "audio_option": json.dumps({
        "has_bg_music": True,
        "has_narration": False,
        "native_audio": True
    }),
    "language": "English"
}

print("Creating story...")
try:
    response = requests.post(url, headers=headers, data=payload, timeout=60)
    response.raise_for_status()

    result = response.json()
    story_data = result["data"]
    story_id = story_data["id"]

    print(f"✓ Story created successfully!")
    print(f"  Story ID: {story_id}")
    print(f"  Status: {story_data['status']}")
    print(f"  Used Credits: {story_data['used_credits']}")

except requests.exceptions.HTTPError as e:
    print(f"✗ HTTP Error: {e}")
    if e.response is not None:
        print(f"  Response: {e.response.text}")
    exit(1)
except requests.exceptions.RequestException as e:
    print(f"✗ Request failed: {e}")
    exit(1)

# Step 2: Poll for completion
print("\nPolling for story completion...")
max_attempts = 120  # Maximum 60 minutes (120 * 30 seconds)
attempt = 0
poll_interval = 30  # Check every 30 seconds

def get_story_status(story_id):
    """Retrieve the current status of a story."""
    url = f"{BASE_URL}/story/{story_id}"
    headers = {"X-Api-Key": API_KEY}

    try:
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()
        return response.json()["data"]
    except requests.exceptions.RequestException as e:
        print(f"  Warning: Error retrieving status: {e}")
        return None

while attempt < max_attempts:
    story_data = get_story_status(story_id)

    if not story_data:
        print(f"  Attempt {attempt + 1}/{max_attempts}: Failed to retrieve status, retrying...")
        time.sleep(poll_interval)
        attempt += 1
        continue

    status = story_data.get("status")
    progress = story_data.get("progress_percentage", 0)

    print(f"  Attempt {attempt + 1}/{max_attempts}: Status={status}, Progress={progress}%")

    if status == "success":
        video_url = story_data.get("video_url")
        if video_url:
            print(f"\n✓ Story completed successfully!")
            print(f"  Video URL: {video_url}")

            # Step 3: Download the video
            print("\nDownloading video...")
            try:
                video_response = requests.get(video_url, stream=True, timeout=60)
                video_response.raise_for_status()

                output_path = "story_video.mp4"
                total_size = int(video_response.headers.get('content-length', 0))
                downloaded = 0

                with open(output_path, "wb") as f:
                    for chunk in video_response.iter_content(chunk_size=8192):
                        if chunk:
                            f.write(chunk)
                            downloaded += len(chunk)
                            if total_size > 0:
                                percent = (downloaded / total_size) * 100
                                print(f"  Download progress: {percent:.1f}%", end="\r")

                print(f"\n✓ Video downloaded successfully!")
                print(f"  Saved to: {output_path}")
                print(f"  File size: {downloaded / (1024 * 1024):.2f} MB")

            except Exception as e:
                print(f"\n✗ Error downloading video: {e}")
            break
        else:
            print("  Warning: Story completed but video_url is not available yet. Waiting...")
            time.sleep(poll_interval)
            attempt += 1
            continue
    elif status == "fail":
        print(f"\n✗ Story generation failed.")
        print(f"  Please check the story details for more information.")
        print(f"  Story ID: {story_id}")
        exit(1)

    time.sleep(poll_interval)
    attempt += 1

if attempt >= max_attempts:
    print(f"\n⚠ Timeout: Story generation is taking longer than expected.")
    print(f"  Story ID: {story_id}")
    print(f"  Please check the status later using: GET {BASE_URL}/story/{story_id}")

Error Handling

The API may return the following HTTP status codes:

  • 200 - Success. Story creation initiated.
  • 400 - Bad Request. Invalid parameters or missing required fields.
  • 402 - Payment Required. Insufficient credits in your account.
  • 429 - Too Many Requests. Rate limit exceeded or concurrency limit reached.
  • 500 - Internal Server Error. Please retry or contact support.
SecurityAPIKeyHeader
Request
Request Body schema: application/x-www-form-urlencoded
required
idea
required
string (Idea)

Detailed text description of your story concept. Be specific about characters, settings, actions, visual style, and mood. The more detail you provide, the better the generated story will match your vision.

scene_count
integer (Number of Scenes)
Default: 3

Number of scenes to generate in the story. Default is 3. Maximum value depends on your subscription plan. If omitted, scenes are generated automatically based on the story complexity.

image_tool
string (Image Generation Model)
Default: "Seedream"

AI model used for generating scene images. Options: 'Seedream' (default), 'FluxTurbo', 'NanoBanana', 'QwenImage'. Each model has different strengths in style, quality, and generation speed.

Enum: "Seedream" "FluxTurbo" "NanoBanana" "QwenImage"
video_tool
string (Video Animation Method)
Default: "Auto"

Animation method used to convert images into videos. Options: 'Auto' (default, automatically selects best method), 'KlingAI', 'VeoFast', and others. 'Auto' is recommended for most use cases.

Enum: "Auto" "KlingAI" "Seedance" "Pixverse" "VeoFast"
scene_duration
any (Scene Duration)
Default: "5"

Duration of each scene in seconds. Options: '5' (default) or '10'. Note: This value is automatically adjusted when narration is enabled to match the narration length.

Enum: "5" "10" 5 10
aspect_ratio
string (Aspect Ratio)
Default: "16:9"

Video aspect ratio. Options: '16:9' (landscape, default), '4:3' (standard), '1:1' (square), '3:4' (portrait), '9:16' (vertical/mobile). Choose based on your target platform.

Enum: "16:9" "4:3" "1:1" "3:4" "9:16"
is_transition
boolean (Enable Transitions)
Default: false

If true, creates smooth transition videos between scene images, providing a more cinematic flow. Default is false. Enabling transitions may increase processing time and credit usage.

elements
string (Story Elements)

JSON string containing initial elements (characters, environments, objects) to include in the story. Useful for product placement, brand logos, or maintaining character consistency. Format: JSON string with 'objects', 'characters', or 'environments' arrays.

audio_option
string (Audio Configuration)

Audio configuration options for story generation.

Configure background music, narration, and native audio settings using a JSON string.

Audio Parameters

Parameter Type Default Description
narrator string "Rachel" Voice for narration. Available voices: Rachel, Aria, Roger, Sarah, Laura, Charlie, George, Callum, River, Liam, Charlotte, Alice, Matilda, Will, Jessica, Eric, Chris, Brian, Daniel, Lily, Bill
has_narration boolean true Whether to include narration. Note: This field is ignored when native_audio is true
has_bg_music boolean true Whether to include background music
native_audio boolean false Whether to include native sound effects and lip sync. When true, narration is automatically disabled

Usage Examples

Example 1: Background Music Only

{
    "has_bg_music": true,
    "has_narration": false,
    "native_audio": false
}

Example 2: Narration with Background Music

{
    "has_bg_music": true,
    "has_narration": true,
    "native_audio": false,
    "narrator": "Rachel"
}

Example 3: Native Audio (Sound Effects + Lip Sync)

{
    "has_bg_music": true,
    "has_narration": false,
    "native_audio": true
}

Example 4: No Audio

{
    "has_bg_music": false,
    "has_narration": false,
    "native_audio": false
}

Python Usage

import json

audio_option = json.dumps({
    "has_bg_music": True,
    "has_narration": True,
    "native_audio": False,
    "narrator": "Rachel"
})

payload = {
    "idea": "Your story idea",
    "audio_option": audio_option,
    # ... other parameters
}

Notes

  • When native_audio is true, has_narration is automatically set to false regardless of the provided value
  • narrator is only used when has_narration is true and native_audio is false
  • Background music is generated automatically to match the story's mood and style
language
string (Language)
Default: "English"

Language used for narration and storyboard generation. Supported languages include English, Spanish, French, German, and others. Default is 'English'.

Enum: "Arabic" "Chinese" "English" "French" "German" "Hindi" "Japanese" "Korean" "Spanish" "Turkish"
title
string (Story Title)
Default: ""

Optional title for your story. Used for organization and display purposes. If not provided, an empty string is used.

webhook_url
string (Webhook URL)

URL endpoint to receive a POST request notification when story generation completes. Your endpoint must respond with a 2xx status code within 10 seconds. The webhook payload contains 'customer_id', 'batch_id', and 'status' fields.

Responses
200

Story Object

400

Bad Request

402

Insufficient Credit

422

Validation Error

post/story/idea-2-video
Request samples
Response samples
application/json
{
  • "data": {
    }
}

[AUTO] URL-to-Video

Creates a complete video automatically from a website URL and idea prompt.

This endpoint analyzes the provided website URL and generates a video based on your idea description. It's ideal for creating marketing videos, product showcases, or brand commercials.

Workflow

The generation pipeline is identical to idea-2-video:

  1. Storyboard Generation - Creates a structured storyboard
  2. Element Image Creation - Generates consistent visual elements
  3. Scene Image Generation - Produces scene images
  4. Narration Generation - Creates voice narrations (if enabled)
  5. Background Music - Generates background music (if enabled)
  6. Video Animation - Animates images into videos
  7. Video Composition - Composes final story video

Parameters

Parameter Type Required Default Description
idea string Yes - Text description including the website URL. Example: "Create a marketing video for https://www.example.com highlighting their product features"
scene_count integer No 3 Number of scenes to generate
image_tool string No "Seedream" Image generation model
video_tool string No "Auto" Animation method
scene_duration string No "5" Duration per scene ("5" or "10" seconds)
aspect_ratio string No "16:9" Video aspect ratio
is_transition boolean No false Enable transition videos between scenes
elements string (JSON) No null Initial elements (objects, characters, environments)
audio_option string (JSON) No See audio options Audio configuration
language string No "English" Narration language
title string No "" Story title
webhook_url string No null Webhook URL for completion notification

Example Request

import requests
import json

url = "https://api.vimmerse.net/story/url-2-video"
headers = {"X-Api-Key": "YOUR_API_KEY"}

payload = {
    "idea": "Create a marketing video for https://www.vimmerse.net/ highlighting the AI Video production capabilities on platform using best AI image and video tools. Showcase the platform's features, user interface, and generated video examples.",
    "title": "Vimmerse Platform Showcase",
    "aspect_ratio": "16:9",
    "scene_count": 3,
    "image_tool": "Seedream",
    "video_tool": "Auto",
    "audio_option": json.dumps({
        "has_bg_music": True,
        "has_narration": True,
        "native_audio": False,
        "narrator": "Rachel"
    }),
    "elements": json.dumps({
        "objects": [
            {
                "name": "Logo",
                "description": "Vimmerse Logo",
                "image_url": "https://distribution.vimmerse.net/presets/logo/vimmerse_logo.png"
            }
        ]
    }),
    "language": "English"
}

try:
    response = requests.post(url, headers=headers, data=payload, timeout=60)
    response.raise_for_status()

    result = response.json()
    print(f"Story created: {result['data']['id']}")

except requests.exceptions.RequestException as e:
    print(f"Error: {e}")

Complete Example with Polling

This complete example creates a story from a URL, polls for completion, and downloads the final video:

import requests
import json
import time

BASE_URL = "https://api.vimmerse.net"
API_KEY = "YOUR_API_KEY"

# Step 1: Create the story
url = f"{BASE_URL}/story/url-2-video"
headers = {"X-Api-Key": API_KEY}

payload = {
    "idea": "Create a marketing video for https://www.vimmerse.net/ highlighting the AI Video production capabilities on platform using best AI image and video tools. Showcase the platform's features, user interface, and generated video examples.",
    "title": "Vimmerse Platform Showcase",
    "aspect_ratio": "16:9",
    "scene_count": 3,
    "image_tool": "Seedream",
    "video_tool": "Auto",
    "audio_option": json.dumps({
        "has_bg_music": True,
        "has_narration": True,
        "native_audio": False,
        "narrator": "Rachel"
    }),
    "language": "English"
}

print("Creating story from URL...")
try:
    response = requests.post(url, headers=headers, data=payload, timeout=60)
    response.raise_for_status()

    result = response.json()
    story_data = result["data"]
    story_id = story_data["id"]

    print(f"✓ Story created successfully!")
    print(f"  Story ID: {story_id}")
    print(f"  Status: {story_data['status']}")
    print(f"  Used Credits: {story_data['used_credits']}")

except requests.exceptions.HTTPError as e:
    print(f"✗ HTTP Error: {e}")
    if e.response is not None:
        print(f"  Response: {e.response.text}")
    exit(1)
except requests.exceptions.RequestException as e:
    print(f"✗ Request failed: {e}")
    exit(1)

# Step 2: Poll for completion
print("\nPolling for story completion...")
max_attempts = 120  # Maximum 60 minutes
attempt = 0
poll_interval = 30  # Check every 30 seconds

def get_story_status(story_id):
    """Retrieve the current status of a story."""
    url = f"{BASE_URL}/story/{story_id}"
    headers = {"X-Api-Key": API_KEY}

    try:
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()
        return response.json()["data"]
    except requests.exceptions.RequestException as e:
        print(f"  Warning: Error retrieving status: {e}")
        return None

while attempt < max_attempts:
    story_data = get_story_status(story_id)

    if not story_data:
        print(f"  Attempt {attempt + 1}/{max_attempts}: Failed to retrieve status, retrying...")
        time.sleep(poll_interval)
        attempt += 1
        continue

    status = story_data.get("status")
    progress = story_data.get("progress_percentage", 0)

    print(f"  Attempt {attempt + 1}/{max_attempts}: Status={status}, Progress={progress}%")

    if status == "success":
        video_url = story_data.get("video_url")
        if video_url:
            print(f"\n✓ Story completed successfully!")
            print(f"  Video URL: {video_url}")

            # Step 3: Download the video
            print("\nDownloading video...")
            try:
                video_response = requests.get(video_url, stream=True, timeout=60)
                video_response.raise_for_status()

                output_path = "url_story_video.mp4"
                total_size = int(video_response.headers.get('content-length', 0))
                downloaded = 0

                with open(output_path, "wb") as f:
                    for chunk in video_response.iter_content(chunk_size=8192):
                        if chunk:
                            f.write(chunk)
                            downloaded += len(chunk)
                            if total_size > 0:
                                percent = (downloaded / total_size) * 100
                                print(f"  Download progress: {percent:.1f}%", end="\r")

                print(f"\n✓ Video downloaded successfully!")
                print(f"  Saved to: {output_path}")
                print(f"  File size: {downloaded / (1024 * 1024):.2f} MB")

            except Exception as e:
                print(f"\n✗ Error downloading video: {e}")
            break
        else:
            print("  Warning: Story completed but video_url is not available yet. Waiting...")
            time.sleep(poll_interval)
            attempt += 1
            continue
    elif status == "fail":
        print(f"\n✗ Story generation failed.")
        print(f"  Story ID: {story_id}")
        exit(1)

    time.sleep(poll_interval)
    attempt += 1

if attempt >= max_attempts:
    print(f"\n⚠ Timeout: Story generation is taking longer than expected.")
    print(f"  Story ID: {story_id}")
    print(f"  Please check the status later using: GET {BASE_URL}/story/{story_id}")
SecurityAPIKeyHeader
Request
Request Body schema: application/x-www-form-urlencoded
required
idea
required
string (Idea)

Detailed text description of your story concept. Be specific about characters, settings, actions, visual style, and mood. The more detail you provide, the better the generated story will match your vision.

scene_count
integer (Number of Scenes)
Default: 3

Number of scenes to generate in the story. Default is 3. Maximum value depends on your subscription plan. If omitted, scenes are generated automatically based on the story complexity.

image_tool
string (Image Generation Model)
Default: "Seedream"

AI model used for generating scene images. Options: 'Seedream' (default), 'FluxTurbo', 'NanoBanana', 'QwenImage'. Each model has different strengths in style, quality, and generation speed.

Enum: "Seedream" "FluxTurbo" "NanoBanana" "QwenImage"
video_tool
string (Video Animation Method)
Default: "Auto"

Animation method used to convert images into videos. Options: 'Auto' (default, automatically selects best method), 'KlingAI', 'VeoFast', and others. 'Auto' is recommended for most use cases.

Enum: "Auto" "KlingAI" "Seedance" "Pixverse" "VeoFast"
scene_duration
any (Scene Duration)
Default: "5"

Duration of each scene in seconds. Options: '5' (default) or '10'. Note: This value is automatically adjusted when narration is enabled to match the narration length.

Enum: "5" "10" 5 10
aspect_ratio
string (Aspect Ratio)
Default: "16:9"

Video aspect ratio. Options: '16:9' (landscape, default), '4:3' (standard), '1:1' (square), '3:4' (portrait), '9:16' (vertical/mobile). Choose based on your target platform.

Enum: "16:9" "4:3" "1:1" "3:4" "9:16"
is_transition
boolean (Enable Transitions)
Default: false

If true, creates smooth transition videos between scene images, providing a more cinematic flow. Default is false. Enabling transitions may increase processing time and credit usage.

elements
string (Story Elements)

JSON string containing initial elements (characters, environments, objects) to include in the story. Useful for product placement, brand logos, or maintaining character consistency. Format: JSON string with 'objects', 'characters', or 'environments' arrays.

audio_option
string (Audio Configuration)

Audio configuration options for story generation.

Configure background music, narration, and native audio settings using a JSON string.

Audio Parameters

Parameter Type Default Description
narrator string "Rachel" Voice for narration. Available voices: Rachel, Aria, Roger, Sarah, Laura, Charlie, George, Callum, River, Liam, Charlotte, Alice, Matilda, Will, Jessica, Eric, Chris, Brian, Daniel, Lily, Bill
has_narration boolean true Whether to include narration. Note: This field is ignored when native_audio is true
has_bg_music boolean true Whether to include background music
native_audio boolean false Whether to include native sound effects and lip sync. When true, narration is automatically disabled

Usage Examples

Example 1: Background Music Only

{
    "has_bg_music": true,
    "has_narration": false,
    "native_audio": false
}

Example 2: Narration with Background Music

{
    "has_bg_music": true,
    "has_narration": true,
    "native_audio": false,
    "narrator": "Rachel"
}

Example 3: Native Audio (Sound Effects + Lip Sync)

{
    "has_bg_music": true,
    "has_narration": false,
    "native_audio": true
}

Example 4: No Audio

{
    "has_bg_music": false,
    "has_narration": false,
    "native_audio": false
}

Python Usage

import json

audio_option = json.dumps({
    "has_bg_music": True,
    "has_narration": True,
    "native_audio": False,
    "narrator": "Rachel"
})

payload = {
    "idea": "Your story idea",
    "audio_option": audio_option,
    # ... other parameters
}

Notes

  • When native_audio is true, has_narration is automatically set to false regardless of the provided value
  • narrator is only used when has_narration is true and native_audio is false
  • Background music is generated automatically to match the story's mood and style
language
string (Language)
Default: "English"

Language used for narration and storyboard generation. Supported languages include English, Spanish, French, German, and others. Default is 'English'.

Enum: "Arabic" "Chinese" "English" "French" "German" "Hindi" "Japanese" "Korean" "Spanish" "Turkish"
title
string (Story Title)
Default: ""

Optional title for your story. Used for organization and display purposes. If not provided, an empty string is used.

webhook_url
string (Webhook URL)

URL endpoint to receive a POST request notification when story generation completes. Your endpoint must respond with a 2xx status code within 10 seconds. The webhook payload contains 'customer_id', 'batch_id', and 'status' fields.

Responses
200

Story Object

400

Bad Request

402

Insufficient Credit

422

Validation Error

post/story/url-2-video
Request samples
Response samples
application/json
{
  • "data": {
    }
}

[AUTO] Images-to-Video

Generates a story video using both your idea and a set of existing images.

This endpoint is ideal when you want to:

  • Maintain character consistency using your own images
  • Use a specific art style as reference
  • Animate existing artwork or product photos
  • Create videos from a series of related images

Workflow

  1. Accepts Images - Takes your provided images and idea description
  2. Generates Narrations - Creates appropriate voice narrations for each scene (if enabled)
  3. Creates Background Music - Generates matching background music (if enabled)
  4. Animates Images - Converts each image into an animated video with motion
  5. Composes Final Video - Combines all scene videos into a final story video

Parameters

Parameter Type Required Default Description
idea string Yes - Text description of your story concept
image_urls array[string] Yes* [] Array of publicly accessible image URLs
image_files array[file] Yes* [] Upload image files directly (multipart/form-data)
video_tool string No "Auto" Animation method
is_transition boolean No false Create transition videos between scenes
scene_duration string No "5" Duration per scene ("5" or "10" seconds)
aspect_ratio string No "16:9" Video aspect ratio
audio_option string (JSON) No See below Audio configuration
language string No "English" Narration language
title string No "" Story title
webhook_url string No null Webhook URL for completion notification

Either image_urls or image_files must be provided.

Example 1: Using Image URLs

import requests
import json

url = "https://api.vimmerse.net/story/images-2-video"
headers = {"X-Api-Key": "YOUR_API_KEY"}

payload = {
    "idea": "Cinematic product-only smoothie promo: fresh berries, bananas, and oranges falling onto rustic wooden table in slow-motion, glass blender mixing fruits with smoothie swirling inside, smoothie pouring from blender into glass with condensation, pink smoothie glass showcased on wooden table in top-down and angled shots, cinematic lighting, photorealistic textures, colorful and vibrant, no humans, final branding overlay with tagline 'Freshness in Every Sip', 16:9, consistent warm cinematic glow across all scenes",
    "title": "Promo Video Showcase",
    "aspect_ratio": "16:9",
    "image_urls": [
        "https://media.vimmerse.net/vimmerse-product/assets/a979b86e-abf2-476e-b1ec-3a13657caee9/uploads/20250924_101637_7c5ygv.jpg",
        "https://media.vimmerse.net/vimmerse-product/assets/a979b86e-abf2-476e-b1ec-3a13657caee9/uploads/20250924_101654_jpj5wi.jpg",
        "https://media.vimmerse.net/vimmerse-product/assets/a979b86e-abf2-476e-b1ec-3a13657caee9/uploads/20250924_101711_3tw2er.jpg",
        "https://media.vimmerse.net/vimmerse-product/assets/a979b86e-abf2-476e-b1ec-3a13657caee9/uploads/20250924_101742_vkcfl9.jpg",
        "https://media.vimmerse.net/vimmerse-product/assets/a979b86e-abf2-476e-b1ec-3a13657caee9/uploads/20250924_101802_75q49f.jpg",
        "https://media.vimmerse.net/vimmerse-product/assets/a979b86e-abf2-476e-b1ec-3a13657caee9/uploads/20250924_101837_jhqbhc.jpg",
        "https://media.vimmerse.net/vimmerse-product/assets/a979b86e-abf2-476e-b1ec-3a13657caee9/uploads/20250924_102132_s8xzfv.jpg",
    ],
    "video_tool": "Auto",
    "is_transition": True,
    "scene_duration": "5",
    "audio_option": json.dumps({
        "has_bg_music": True,
        "has_narration": True,
        "native_audio": False
    }),
    "language": "English"
}

try:
    response = requests.post(url, headers=headers, data=payload, timeout=60)
    response.raise_for_status()

    result = response.json()
    story_data = result["data"]

    print(f"Story created! ID: {story_data['id']}")
    print(f"Scenes: {story_data.get('scene_count', len(payload['image_urls']))}")

except requests.exceptions.RequestException as e:
    print(f"Error: {e}")

Example 2: Uploading Image Files

import requests
import json

url = "https://api.vimmerse.net/story/images-2-video"
headers = {"X-Api-Key": "YOUR_API_KEY"}

# Prepare files
files = [
    ("image_files", open("image1.jpg", "rb")),
    ("image_files", open("image2.jpg", "rb")),
    ("image_files", open("image3.jpg", "rb"))
]

payload = {
    "idea": "Create a product showcase video highlighting these product images",
    "title": "Product Showcase",
    "aspect_ratio": "9:16",
    "video_tool": "Auto",
    "audio_option": json.dumps({
        "has_bg_music": True,
        "has_narration": True,
        "native_audio": False,
        "narrator": "Rachel"
    })
}

try:
    response = requests.post(url, headers=headers, data=payload, files=files, timeout=120)
    response.raise_for_status()

    result = response.json()
    print(f"Story created: {result['data']['id']}")

    # Close file handles
    for _, f in files:
        f.close()

except requests.exceptions.RequestException as e:
    print(f"Error: {e}")
    # Ensure files are closed on error
    for _, f in files:
        f.close()

Complete Example with Polling

This complete example creates a story from images, polls for completion, and downloads the final video:

import requests
import json
import time

BASE_URL = "https://api.vimmerse.net"
API_KEY = "YOUR_API_KEY"

# Step 1: Create the story from images
url = f"{BASE_URL}/story/images-2-video"
headers = {"X-Api-Key": API_KEY}

payload = {
    "idea": "Cinematic product-only smoothie promo: fresh berries, bananas, and oranges falling onto rustic wooden table in slow-motion, glass blender mixing fruits with smoothie swirling inside, smoothie pouring from blender into glass with condensation, pink smoothie glass showcased on wooden table in top-down and angled shots, cinematic lighting, photorealistic textures, colorful and vibrant, no humans, final branding overlay with tagline 'Freshness in Every Sip', 16:9, consistent warm cinematic glow across all scenes",
    "title": "Promo Video Showcase",
    "aspect_ratio": "16:9",
    "image_urls": [
        "https://media.vimmerse.net/vimmerse-product/assets/a979b86e-abf2-476e-b1ec-3a13657caee9/uploads/20250924_101637_7c5ygv.jpg",
        "https://media.vimmerse.net/vimmerse-product/assets/a979b86e-abf2-476e-b1ec-3a13657caee9/uploads/20250924_101654_jpj5wi.jpg",
        "https://media.vimmerse.net/vimmerse-product/assets/a979b86e-abf2-476e-b1ec-3a13657caee9/uploads/20250924_101711_3tw2er.jpg",
        "https://media.vimmerse.net/vimmerse-product/assets/a979b86e-abf2-476e-b1ec-3a13657caee9/uploads/20250924_101742_vkcfl9.jpg",
        "https://media.vimmerse.net/vimmerse-product/assets/a979b86e-abf2-476e-b1ec-3a13657caee9/uploads/20250924_101802_75q49f.jpg",
        "https://media.vimmerse.net/vimmerse-product/assets/a979b86e-abf2-476e-b1ec-3a13657caee9/uploads/20250924_101837_jhqbhc.jpg",
        "https://media.vimmerse.net/vimmerse-product/assets/a979b86e-abf2-476e-b1ec-3a13657caee9/uploads/20250924_102132_s8xzfv.jpg",
    ],
    "video_tool": "Auto",
    "is_transition": True,
    "scene_duration": "5",
    "audio_option": json.dumps({
        "has_bg_music": True,
        "has_narration": True,
        "native_audio": False
    }),
    "language": "English"
}

print("Creating story from images...")
try:
    response = requests.post(url, headers=headers, data=payload, timeout=60)
    response.raise_for_status()

    result = response.json()
    story_data = result["data"]
    story_id = story_data["id"]

    print(f"✓ Story created successfully!")
    print(f"  Story ID: {story_id}")
    print(f"  Status: {story_data['status']}")
    print(f"  Scenes: {story_data.get('scene_count', len(payload['image_urls']))}")
    print(f"  Used Credits: {story_data['used_credits']}")

except requests.exceptions.HTTPError as e:
    print(f"✗ HTTP Error: {e}")
    if e.response is not None:
        print(f"  Response: {e.response.text}")
    exit(1)
except requests.exceptions.RequestException as e:
    print(f"✗ Request failed: {e}")
    exit(1)

# Step 2: Poll for completion
print("\nPolling for story completion...")
max_attempts = 120  # Maximum 60 minutes
attempt = 0
poll_interval = 30  # Check every 30 seconds

def get_story_status(story_id):
    """Retrieve the current status of a story."""
    url = f"{BASE_URL}/story/{story_id}"
    headers = {"X-Api-Key": API_KEY}

    try:
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()
        return response.json()["data"]
    except requests.exceptions.RequestException as e:
        print(f"  Warning: Error retrieving status: {e}")
        return None

while attempt < max_attempts:
    story_data = get_story_status(story_id)

    if not story_data:
        print(f"  Attempt {attempt + 1}/{max_attempts}: Failed to retrieve status, retrying...")
        time.sleep(poll_interval)
        attempt += 1
        continue

    status = story_data.get("status")
    progress = story_data.get("progress_percentage", 0)

    print(f"  Attempt {attempt + 1}/{max_attempts}: Status={status}, Progress={progress}%")

    if status == "success":
        video_url = story_data.get("video_url")
        if video_url:
            print(f"\n✓ Story completed successfully!")
            print(f"  Video URL: {video_url}")

            # Step 3: Download the video
            print("\nDownloading video...")
            try:
                video_response = requests.get(video_url, stream=True, timeout=60)
                video_response.raise_for_status()

                output_path = "images_story_video.mp4"
                total_size = int(video_response.headers.get('content-length', 0))
                downloaded = 0

                with open(output_path, "wb") as f:
                    for chunk in video_response.iter_content(chunk_size=8192):
                        if chunk:
                            f.write(chunk)
                            downloaded += len(chunk)
                            if total_size > 0:
                                percent = (downloaded / total_size) * 100
                                print(f"  Download progress: {percent:.1f}%", end="\r")

                print(f"\n✓ Video downloaded successfully!")
                print(f"  Saved to: {output_path}")
                print(f"  File size: {downloaded / (1024 * 1024):.2f} MB")

            except Exception as e:
                print(f"\n✗ Error downloading video: {e}")
            break
        else:
            print("  Warning: Story completed but video_url is not available yet. Waiting...")
            time.sleep(poll_interval)
            attempt += 1
            continue
    elif status == "fail":
        print(f"\n✗ Story generation failed.")
        print(f"  Story ID: {story_id}")
        exit(1)

    time.sleep(poll_interval)
    attempt += 1

if attempt >= max_attempts:
    print(f"\n⚠ Timeout: Story generation is taking longer than expected.")
    print(f"  Story ID: {story_id}")
    print(f"  Please check the status later using: GET {BASE_URL}/story/{story_id}")

Image Requirements

  • Format: JPEG, PNG, WebP
  • Size: Recommended minimum 1024x1024 pixels
  • Aspect Ratio: Images will be cropped/resized to match the specified aspect_ratio
  • Accessibility: Image URLs must be publicly accessible (no authentication required)

Error Handling

  • 400 - Missing required parameters (idea or images)
  • 402 - Insufficient credits
  • 429 - Rate limit or concurrency limit exceeded
SecurityAPIKeyHeader
Request
Request Body schema: multipart/form-data
idea
string (Idea)
Default: "Create a stunning video showcasing these images with a compelling narrative"

Text description of your story concept. Describes how the images should be presented and what narrative to create. Be specific about style, mood, and desired outcome.

image_files
Array of strings <binary> (Image Files)
Default: []

Image files to upload directly. Supported formats: JPEG, PNG, WebP. Recommended minimum size: 1024x1024 pixels. Either 'image_files' or 'image_urls' must be provided.

image_urls
Array of strings (Image URLs)
Default: []

Array of publicly accessible image URLs. URLs must be accessible without authentication. If 'image_files' are provided, this field is ignored. Either 'image_files' or 'image_urls' must be provided.

video_tool
string (Video Animation Method)
Default: "Auto"

Animation method used to convert images into videos. Options: 'Auto' (default, automatically selects best method), 'KlingAI', 'VeoFast', and others.

Enum: "Auto" "KlingAI" "Seedance" "Pixverse" "VeoFast"
is_transition
boolean (Enable Transitions)
Default: false

If true, creates smooth transition videos between scene images for a more cinematic flow. Default is false.

scene_duration
any (Scene Duration)
Default: "5"

Duration of each scene in seconds. Options: '5' (default) or '10'. Automatically adjusted when narration is enabled to match narration length.

Enum: "5" "10" 5 10
aspect_ratio
string (Aspect Ratio)
Default: "16:9"

Video aspect ratio. Options: '16:9' (landscape, default), '4:3', '1:1', '3:4', '9:16' (vertical/mobile).

Enum: "16:9" "4:3" "1:1" "3:4" "9:16"
audio_option
string (Audio Configuration)

Audio configuration options for story generation.

Configure background music, narration, and native audio settings using a JSON string.

Audio Parameters

Parameter Type Default Description
narrator string "Rachel" Voice for narration. Available voices: Rachel, Aria, Roger, Sarah, Laura, Charlie, George, Callum, River, Liam, Charlotte, Alice, Matilda, Will, Jessica, Eric, Chris, Brian, Daniel, Lily, Bill
has_narration boolean true Whether to include narration. Note: This field is ignored when native_audio is true
has_bg_music boolean true Whether to include background music
native_audio boolean false Whether to include native sound effects and lip sync. When true, narration is automatically disabled

Usage Examples

Example 1: Background Music Only

{
    "has_bg_music": true,
    "has_narration": false,
    "native_audio": false
}

Example 2: Narration with Background Music

{
    "has_bg_music": true,
    "has_narration": true,
    "native_audio": false,
    "narrator": "Rachel"
}

Example 3: Native Audio (Sound Effects + Lip Sync)

{
    "has_bg_music": true,
    "has_narration": false,
    "native_audio": true
}

Example 4: No Audio

{
    "has_bg_music": false,
    "has_narration": false,
    "native_audio": false
}

Python Usage

import json

audio_option = json.dumps({
    "has_bg_music": True,
    "has_narration": True,
    "native_audio": False,
    "narrator": "Rachel"
})

payload = {
    "idea": "Your story idea",
    "audio_option": audio_option,
    # ... other parameters
}

Notes

  • When native_audio is true, has_narration is automatically set to false regardless of the provided value
  • narrator is only used when has_narration is true and native_audio is false
  • Background music is generated automatically to match the story's mood and style
language
string (Language)
Default: "English"

Language used for narration and story generation. Default is 'English'.

Enum: "Arabic" "Chinese" "English" "French" "German" "Hindi" "Japanese" "Korean" "Spanish" "Turkish"
title
string (Story Title)
Default: ""

Optional title for your story. Used for organization and display purposes.

webhook_url
string (Webhook URL)

URL endpoint to receive a POST request notification when story generation completes. Your endpoint must respond with a 2xx status code within 10 seconds.

Responses
200

Story Object

400

Bad Request

402

Insufficient Credit

422

Validation Error

post/story/images-2-video
Request samples
Response samples
application/json
{
  • "data": {
    }
}

[ADVANCED] Step 1 - Create Storyboard

Creates a new storyboard (Step 1 of Advanced Mode) based on your idea and/or images.

This is the first step in the Advanced Mode workflow, providing granular control over the story generation process.

What It Does

  • Generates Storyboard - Creates a complete storyboard structure with:
    • Characters with detailed descriptions
    • Environments (settings/locations)
    • Objects (props, items)
    • Scenes with image descriptions, narrations, and camera movements
  • Creates Narrations - Generates voice-over text for each scene
  • Defines Camera Work - Specifies camera angles and movements for each scene
  • Sets Audio Options - Configures background music and narration settings

Next Steps

After creating the storyboard, proceed with:

  1. Optional: POST /story/{story_id}/elements - Generate element images for visual consistency
  2. Required: POST /story/{story_id}/scenes - Generate scene images and narrations
  3. Required: POST /story/{story_id}/videos - Create videos from the scenes

Parameters

Parameter Type Required Default Description
idea string Yes - Your story concept or narrative
scene_count integer No 3 Number of scenes to generate. Ignored if images are provided.
language string No "English" Language for storyboard generation
audio_option string (JSON) No See below Audio configuration
elements string (JSON) No null Pre-defined elements (characters, objects, environments)
image_urls array[string] No [] Array of image URLs. If provided, scene_count matches image count.
image_files array[file] No [] Upload image files directly. Alternative to image_urls.
story_id string No null Story ID to continue from (for editing existing stories)

Default Audio Options

{
    "has_bg_music": true,
    "has_narration": true,
    "native_audio": false,
    "narrator": "Rachel"
}

Example 1: Create Storyboard from Idea

import requests
import json

url = "https://api.vimmerse.net/story"
headers = {"X-Api-Key": "YOUR_API_KEY"}

payload = {
    "idea": "Create a promotional video where cute animals play musical instruments in a sunny meadow",
    "scene_count": 3,
    "title": "Musical Animals",
    "language": "English",
    "audio_option": json.dumps({
        "has_bg_music": True,
        "has_narration": True,
        "native_audio": False,
        "narrator": "Rachel"
    })
}

try:
    response = requests.post(url, headers=headers, data=payload, timeout=60)
    response.raise_for_status()

    result = response.json()
    story_data = result["data"]
    story_id = story_data["id"]

    print(f"Storyboard created! Story ID: {story_id}")
    print(f"Scenes: {len(story_data.get('storyboard', {}).get('scenes', []))}")

except requests.exceptions.RequestException as e:
    print(f"Error: {e}")

Example 2: Create Storyboard with Images

import requests

url = "https://api.vimmerse.net/story"
headers = {"X-Api-Key": "YOUR_API_KEY"}

payload = {
    "idea": "Create a promotional video showcasing these beautiful landscapes",
    "title": "Landscape Story",
    "image_urls": [
        "https://example.com/images/landscape1.jpg",
        "https://example.com/images/landscape2.jpg",
        "https://example.com/images/landscape3.jpg"
    ]
}

try:
    response = requests.post(url, headers=headers, data=payload, timeout=60)
    response.raise_for_status()

    result = response.json()
    story_data = result["data"]

    # Scene count automatically matches number of images
    print(f"Storyboard created with {len(story_data.get('storyboard', {}).get('scenes', []))} scenes")

except requests.exceptions.RequestException as e:
    print(f"Error: {e}")

Note: When providing images, the scene_count parameter is ignored, and scenes are generated based on the number of images provided.

SecurityAPIKeyHeader
Request
Request Body schema: multipart/form-data
required
story_id
string (Story ID)

Optional story ID to continue editing an existing story. If provided, updates the existing storyboard instead of creating a new one.

idea
required
string (Idea)

Detailed text description of your story concept. Be specific about characters, settings, actions, and visual style.

scene_count
integer (Number of Scenes)
Default: 3

Number of scenes to generate in the storyboard. Default is 3. If images are provided via 'image_files' or 'image_urls', this value is ignored and scenes are generated based on the number of images.

language
string (Language)
Default: "English"

Language used for storyboard generation and narration. Supported languages include English, Spanish, French, German, and others.

aspect_ratio
string (Aspect Ratio)

Video aspect ratio. Options: '16:9' (landscape, default), '4:3', '1:1', '3:4', '9:16' (vertical/mobile).

Enum: "16:9" "4:3" "1:1" "3:4" "9:16"
audio_option
string (Audio Configuration)

Audio configuration options for story generation.

Configure background music, narration, and native audio settings using a JSON string.

Audio Parameters

Parameter Type Default Description
narrator string "Rachel" Voice for narration. Available voices: Rachel, Aria, Roger, Sarah, Laura, Charlie, George, Callum, River, Liam, Charlotte, Alice, Matilda, Will, Jessica, Eric, Chris, Brian, Daniel, Lily, Bill
has_narration boolean true Whether to include narration. Note: This field is ignored when native_audio is true
has_bg_music boolean true Whether to include background music
native_audio boolean false Whether to include native sound effects and lip sync. When true, narration is automatically disabled

Usage Examples

Example 1: Background Music Only

{
    "has_bg_music": true,
    "has_narration": false,
    "native_audio": false
}

Example 2: Narration with Background Music

{
    "has_bg_music": true,
    "has_narration": true,
    "native_audio": false,
    "narrator": "Rachel"
}

Example 3: Native Audio (Sound Effects + Lip Sync)

{
    "has_bg_music": true,
    "has_narration": false,
    "native_audio": true
}

Example 4: No Audio

{
    "has_bg_music": false,
    "has_narration": false,
    "native_audio": false
}

Python Usage

import json

audio_option = json.dumps({
    "has_bg_music": True,
    "has_narration": True,
    "native_audio": False,
    "narrator": "Rachel"
})

payload = {
    "idea": "Your story idea",
    "audio_option": audio_option,
    # ... other parameters
}

Notes

  • When native_audio is true, has_narration is automatically set to false regardless of the provided value
  • narrator is only used when has_narration is true and native_audio is false
  • Background music is generated automatically to match the story's mood and style
elements
string (Story Elements)

JSON string containing pre-defined elements (characters, environments, objects) to include in the story. Useful for maintaining consistency or including specific products/logos. Format: JSON string with 'objects', 'characters', or 'environments' arrays.

image_files
Array of strings <binary> (Image Files)
Default: []

Image files to upload directly. Supported formats: JPEG, PNG, WebP. If provided, 'image_urls' is ignored and scene count matches the number of uploaded images.

image_urls
Array of strings (Image URLs)
Default: []

Array of publicly accessible image URLs. If 'image_files' are provided, this field is ignored. Scene count automatically matches the number of image URLs provided.

Responses
200

Story Object

400

Bad Request

402

Insufficient Credit

422

Validation Error

post/story
Request samples
Response samples
application/json
{
  • "data": {
    }
}

[ADVANCED] Step 1.5 - Create Element Images(Optional)

Generates images for storyboard elements (characters, objects, environments) to ensure visual consistency across scenes.

This is an optional step (Step 1.5) in Advanced Mode that helps maintain character and object consistency throughout your story.

What It Does

  • Generates Element Images - Creates images for characters, objects, and environments defined in your storyboard
  • Ensures Consistency - Uses the same visual style and appearance for elements across all scenes
  • Supports Custom Images - If you provide image_url or URL fields in your storyboard elements, those will be used instead

When to Use

  • Use this step when you want consistent character/object appearances across scenes
  • Skip this step if you're providing your own images or don't need element consistency

Parameters

Parameter Type Required Default Description
option string No "Seedream" Image generation model. Options: Seedream, FluxTurbo, NanoBanana, QwenImage
aspect_ratio string No "16:9" Aspect ratio for element images. Options: 16:9, 4:3, 1:1, 3:4, 9:16
storyboard string (JSON) No null Updated storyboard JSON. If not provided, uses the existing storyboard.
enhance_image boolean No false Apply 1× super-resolution enhancement to generated images

Example Request

import requests
import json

STORY_ID = "your-story-id-here"
url = f"https://api.vimmerse.net/story/{STORY_ID}/elements"
headers = {"X-Api-Key": "YOUR_API_KEY"}

payload = {
    "aspect_ratio": "16:9",
    "option": "Seedream",
    "enhance_image": False
}

try:
    response = requests.post(url, headers=headers, data=payload, timeout=120)
    response.raise_for_status()

    result = response.json()
    story_data = result["data"]

    # Check generated element images
    storyboard = story_data.get("storyboard", {})
    characters = storyboard.get("characters", [])

    for char in characters:
        if "URL" in char or "image_url" in char:
            print(f"Character '{char['name']}' image: {char.get('URL') or char.get('image_url')}")

except requests.exceptions.RequestException as e:
    print(f"Error: {e}")

Providing Custom Element Images

You can provide your own element images by including image_url or URL fields in your storyboard:

payload = {
    "storyboard": json.dumps({
        "characters": [
            {
                "name": "Hero Character",
                "description": "A brave warrior",
                "image_url": "https://example.com/character.png"  # Your custom image
            }
        ],
        "objects": [
            {
                "name": "Magic Sword",
                "description": "A glowing blade",
                "URL": "https://example.com/sword.png"  # Alternative field name
            }
        ]
    })
}

Note: If you're generating a story with idea and images (using image_urls in Step 1), you typically don't need to call this endpoint.

SecurityAPIKeyHeader
Request
Request Body schema: application/x-www-form-urlencoded
option
string (Image Generation Model)
Default: "Seedream"

AI model used for generating element images. Options: 'Seedream' (default), 'FluxTurbo', 'NanoBanana', 'QwenImage'. Each model offers different styles and quality characteristics.

Enum: "Seedream" "FluxPro" "FluxTurbo" "NanoBananaPro" "NanoBanana" "FluxKontextPro" "FluxFinetuned" "QwenImage" "StableDiffusion3.5" "LeonardoImage" "GPTImage" "Auto"
aspect_ratio
string (Aspect Ratio)

Aspect ratio for generated element images. Options: '16:9' (landscape), '4:3' (standard), '1:1' (square), '3:4' (portrait), '9:16' (vertical/mobile). Default is '16:9'.

storyboard
string (Storyboard)

Optional JSON string of updated storyboard object. If provided, regenerates elements based on the new storyboard structure. Must contain 'characters', 'environments', 'objects', and 'scenes' arrays.

enhance_image
boolean (Image Enhancement)
Default: false

If true, applies 1× super-resolution enhancement to generated images during post-processing, improving image quality at the cost of additional processing time.

has_bg_music
boolean (Background Music)
Default: true

⚠️ Deprecated: This field is ignored. Configure background music using the 'audio_option' parameter in Step 1 (Create Storyboard).

Responses
200

Story Object with element images generated

400

Bad Request

402

Insufficient Credit

404

Not Found

422

Validation Error

post/story/{story_id}/elements
Request samples
Response samples
application/json
{
  • "data": {
    }
}

[ADVANCED] Step 2 - Create Scenes

Generates scene images, narrations, and background music based on your storyboard.

This is Step 2 of Advanced Mode and is required before creating videos.

What It Does

  • Generates Scene Images - Creates images for each scene based on storyboard descriptions
  • Creates Narrations - Generates voice-over text and audio files for each scene (if narration is enabled)
  • Generates Background Music - Creates background music matching the story mood (if enabled)
  • Updates Storyboard - Optionally accepts an updated storyboard to regenerate scenes

Parameters

Parameter Type Required Default Description
option string No "Seedream" Image generation model
aspect_ratio string No "16:9" Aspect ratio for scene images
storyboard string (JSON) No null Updated storyboard JSON. If provided, regenerates scenes based on new storyboard.
enhance_image boolean No false Apply 1× super-resolution enhancement
audio_option string (JSON) No null Override audio options. If not provided, uses options from Step 1.

Example 1: Generate Scenes Without Updating Storyboard

import requests

STORY_ID = "your-story-id-here"
url = f"https://api.vimmerse.net/story/{STORY_ID}/scenes"
headers = {"X-Api-Key": "YOUR_API_KEY"}

payload = {
    "aspect_ratio": "16:9",
    "option": "Seedream",
    "enhance_image": False
}

try:
    response = requests.post(url, headers=headers, data=payload, timeout=180)
    response.raise_for_status()

    result = response.json()
    story_data = result["data"]

    # Check generated scenes
    scenes = story_data.get("storyboard", {}).get("scenes", [])
    print(f"Generated {len(scenes)} scenes")

    for scene in scenes:
        if "image_url" in scene:
            print(f"Scene '{scene.get('name')}' image: {scene['image_url']}")
        if "narration_url" in scene:
            print(f"Scene '{scene.get('name')}' narration: {scene['narration_url']}")

except requests.exceptions.RequestException as e:
    print(f"Error: {e}")

Example 2: Generate Scenes with Updated Storyboard

import requests
import json

STORY_ID = "your-story-id-here"
url = f"https://api.vimmerse.net/story/{STORY_ID}/scenes"
headers = {"X-Api-Key": "YOUR_API_KEY"}

# Updated storyboard with modified scenes
updated_storyboard = {
    "scenes": [
        {
            "name": "Opening Scene",
            "image_description": "A wide shot of a bustling city street at dawn",
            "narrator": "Welcome to the city that never sleeps"
        }
        # ... more scenes
    ],
    "characters": [...],
    "environments": [...],
    "objects": [...]
}

payload = {
    "aspect_ratio": "16:9",
    "option": "Seedream",
    "storyboard": json.dumps(updated_storyboard)
}

try:
    response = requests.post(url, headers=headers, data=payload, timeout=180)
    response.raise_for_status()

    result = response.json()
    print("Scenes generated successfully!")

except requests.exceptions.RequestException as e:
    print(f"Error: {e}")

Note: This step may take several minutes depending on the number of scenes and selected options.

SecurityAPIKeyHeader
Request
Request Body schema: application/x-www-form-urlencoded
option
string (Image Generation Model)
Default: "Seedream"

AI model used for generating scene images. Options: 'Seedream' (default), 'FluxTurbo', 'NanoBanana', 'QwenImage'. Each model offers different styles, quality, and generation speed.

Enum: "Seedream" "FluxPro" "FluxTurbo" "NanoBananaPro" "NanoBanana" "FluxKontextPro" "FluxFinetuned" "QwenImage" "StableDiffusion3.5" "LeonardoImage" "GPTImage" "Auto"
aspect_ratio
string (Aspect Ratio)

Aspect ratio for generated scene images. Options: '16:9' (landscape, default), '4:3' (standard), '1:1' (square), '3:4' (portrait), '9:16' (vertical/mobile).

storyboard
string (Storyboard)

Optional JSON string of updated storyboard object. If provided, regenerates scenes based on the new storyboard structure. Must contain 'characters', 'environments', 'objects', and 'scenes' arrays.

enhance_image
boolean (Image Enhancement)
Default: false

If true, applies 1× super-resolution enhancement to generated images during post-processing, improving image quality at the cost of additional processing time.

generate_elements
boolean (Generate Elements)
Deprecated
Default: true

⚠️ Deprecated: This parameter is no longer used and will be removed in a future version.

narrator
string (Narrator Voice)
Default: "Rachel"

⚠️ Deprecated: This field is ignored. Configure the narrator voice using the 'audio_option' parameter in Step 1 (Create Storyboard). Available voices: Aria, Roger, Sarah, Laura, Charlie, George, Callum, River, Liam, Charlotte, Alice, Matilda, Will, Jessica, Eric, Chris, Brian, Daniel, Lily, Bill.

has_narration
boolean (Enable Narration)
Default: true

⚠️ Deprecated: This field is ignored. Configure narration using the 'audio_option' parameter in Step 1 (Create Storyboard).

has_bg_music
boolean (Background Music)
Default: true

⚠️ Deprecated: This field is ignored. Configure background music using the 'audio_option' parameter in Step 1 (Create Storyboard).

audio_option
string (Audio Configuration)

Audio configuration options for story generation.

Configure background music, narration, and native audio settings using a JSON string.

Audio Parameters

Parameter Type Default Description
narrator string "Rachel" Voice for narration. Available voices: Rachel, Aria, Roger, Sarah, Laura, Charlie, George, Callum, River, Liam, Charlotte, Alice, Matilda, Will, Jessica, Eric, Chris, Brian, Daniel, Lily, Bill
has_narration boolean true Whether to include narration. Note: This field is ignored when native_audio is true
has_bg_music boolean true Whether to include background music
native_audio boolean false Whether to include native sound effects and lip sync. When true, narration is automatically disabled

Usage Examples

Example 1: Background Music Only

{
    "has_bg_music": true,
    "has_narration": false,
    "native_audio": false
}

Example 2: Narration with Background Music

{
    "has_bg_music": true,
    "has_narration": true,
    "native_audio": false,
    "narrator": "Rachel"
}

Example 3: Native Audio (Sound Effects + Lip Sync)

{
    "has_bg_music": true,
    "has_narration": false,
    "native_audio": true
}

Example 4: No Audio

{
    "has_bg_music": false,
    "has_narration": false,
    "native_audio": false
}

Python Usage

import json

audio_option = json.dumps({
    "has_bg_music": True,
    "has_narration": True,
    "native_audio": False,
    "narrator": "Rachel"
})

payload = {
    "idea": "Your story idea",
    "audio_option": audio_option,
    # ... other parameters
}

Notes

  • When native_audio is true, has_narration is automatically set to false regardless of the provided value
  • narrator is only used when has_narration is true and native_audio is false
  • Background music is generated automatically to match the story's mood and style
Responses
200

Story Object with scene images and narrations generated

400

Bad Request

402

Insufficient Credit

404

Not Found

422

Validation Error

post/story/{story_id}/scenes
Request samples
Response samples
application/json
{}

[ADVANCED] Step 3 - Create Videos

Creates videos from your storyboard scenes (Step 3 of Advanced Mode).

This final step animates the scene images into videos and composes them into a final story video.

What It Does

  • Animates Scene Images - Converts static scene images into animated videos
  • Applies Motion - Uses the specified motion type and duration for each scene
  • Composes Final Video - Combines all scene videos into a single story video
  • Handles Transitions - Creates transition videos between scenes if is_transition is enabled

Parameters

Parameter Type Required Default Description
title string No "" Final story title
storyboard string (JSON) No null Updated storyboard. If provided, uses updated scenes.
is_transition boolean No false Create transition videos between scenes
motion_type string No "Auto" Animation method. Options: Auto, KlingAI, VeoFast, etc.
duration integer No 5 Duration per scene in seconds (1-10). Ignored when narration is enabled.
loop integer No 1 Number of times to repeat motion (1-6). Ignored when narrator is used.
native_audio boolean No false Include native sound effects and lip sync. Deprecated - use audio_option in Step 1.
webhook_url string No null Webhook URL for completion notification

Example Request

import requests

STORY_ID = "your-story-id-here"
url = f"https://api.vimmerse.net/story/{STORY_ID}/videos"
headers = {"X-Api-Key": "YOUR_API_KEY"}

payload = {
    "title": "My Amazing Story",
    "motion_type": "Auto",
    "duration": 5,
    "is_transition": True,
    "webhook_url": "https://your-domain.com/webhook/video-complete"
}

try:
    response = requests.post(url, headers=headers, data=payload, timeout=60)
    response.raise_for_status()

    result = response.json()
    story_data = result["data"]

    print(f"Video generation started for story: {story_data['id']}")
    print(f"Status: {story_data['status']}")

except requests.exceptions.RequestException as e:
    print(f"Error: {e}")

Monitoring Progress

After initiating video creation, monitor progress using GET /story/{story_id}:

import requests
import time

STORY_ID = "your-story-id-here"

def check_video_status(story_id):
    url = f"https://api.vimmerse.net/story/{story_id}"
    headers = {"X-Api-Key": "YOUR_API_KEY"}

    try:
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()
        story_data = response.json()["data"]
        if story_data["status"] == "success" and story_data.get("video_url"):
            return story_data["video_url"]
    except requests.exceptions.RequestException:
        pass
    return None

# Poll until video is ready (max 60 minutes)
max_attempts = 120
poll_interval = 30
for attempt in range(max_attempts):
    video_url = check_video_status(STORY_ID)
    if video_url:
        print(f"Video ready: {video_url}")
        break
    time.sleep(poll_interval)
else:
    print("Timeout: Video generation is taking longer than expected. Check status later with GET /story/{story_id}")

Note: Video generation typically takes 5-15 minutes depending on the number of scenes and selected options.

SecurityAPIKeyHeader
Request
Request Body schema: application/x-www-form-urlencoded
title
string (Story Title)
Default: ""

Final title for your story video. Used for organization and display purposes. If not provided, uses the title from the storyboard.

storyboard
string (Storyboard)

Optional JSON string of updated storyboard object. If provided, uses the updated scenes for video generation. Must contain 'characters', 'environments', 'objects', and 'scenes' arrays.

is_transition
boolean (Enable Transitions)
Default: false

If true, creates smooth transition videos between scene images, providing a more cinematic flow. Default is false. Enabling transitions may increase processing time.

motion_type
string (Motion Type)
Default: "Auto"

Defines the motion style used for video animation.

Enum: "Auto" "AutoT3" "KlingAI" "KlingT4" "LumaAI" "LumaRay2" "VeoFast" "Veo" "RunwayML" "MinimaxHailuo" "Seedance" "SeedanceFast" "Hunyuan" "Pixverse" "PixverseT3" "PicoMotion" "StaticMotion" "Wan" "Sora" "SoraPro"
duration
integer (Scene Duration) [ 1 .. 10 ]
Default: 5

Duration of each scene in seconds. Range: 1-10. Default is 5. Note: This value is automatically adjusted when narration is enabled to match the narration length.

loop
integer (Motion Loop Count) [ 1 .. 6 ]
Default: 1

Number of times the same motion is repeated for each scene. Range: 1-6. Default is 1. Note: This setting is ignored when narration is enabled.

native_audio
boolean (Native Audio)
Default: false

⚠️ Deprecated: This field is ignored. Configure native audio (sound effects and lip sync) using the 'audio_option' parameter in Step 1 (Create Storyboard).

webhook_url
string (Webhook URL)

URL endpoint to receive a POST request notification when video generation completes. Your endpoint must respond with a 2xx status code within 10 seconds.

Responses
200

Story Object

400

Bad Request

402

Insufficient Credit

422

Validation Error

post/story/{story_id}/videos
Request samples
Response samples
application/json
{}

Get Story Detail

Retrieves detailed information about a story, including its current status, progress, and generated assets.

Response Fields

Field Type Description
id string Unique story identifier
status string Current status: new, processing, success, fail
progress_percentage integer Completion percentage (0-100)
video_url string URL of the final composed video (available when status is success)
storyboard object Generated storyboard with characters, environments, objects, and scenes
scenes array Array of scene objects with images, narrations, and video URLs
used_credits integer Credits consumed for this story
created_at string ISO 8601 timestamp of creation
updated_at string ISO 8601 timestamp of last update

Status Values

  • new - Story created but processing hasn't started
  • processing - Story is currently being generated
  • success - Story generation completed successfully
  • fail - Story generation failed

Example Request

import requests

BASE_URL = "https://api.vimmerse.net"
STORY_ID = "your-story-id-here"

url = f"{BASE_URL}/story/{STORY_ID}"
headers = {"X-Api-Key": "YOUR_API_KEY"}

try:
    response = requests.get(url, headers=headers, timeout=30)
    response.raise_for_status()

    result = response.json()
    story_data = result["data"]

    print(f"Story ID: {story_data['id']}")
    print(f"Status: {story_data['status']}")
    print(f"Progress: {story_data.get('progress_percentage', 0)}%")

    if story_data['status'] == 'success' and story_data.get('video_url'):
        print(f"Video URL: {story_data['video_url']}")
    elif story_data['status'] == 'fail':
        print("Story generation failed. Check the 'message' field for details.")

except requests.exceptions.HTTPError as e:
    if e.response.status_code == 404:
        print("Story not found. Please verify the story ID.")
    else:
        print(f"HTTP Error: {e}")
except requests.exceptions.RequestException as e:
    print(f"Request failed: {e}")

Error Responses

  • 404 - Story not found or you don't have access to this story
  • 400 - Invalid story ID format
SecurityAPIKeyHeader
Responses
200

Story Object

400

Bad Request

404

Not Found

422

Validation Error

get/story/{story_id}
Request samples
Response samples
application/json
{
  • "data": {
    }
}

Update Story

Update story metadata. You can update one or more of the following fields: title, description, visibility_status

SecurityAPIKeyHeader
Request
Request Body schema: application/x-www-form-urlencoded
title
string (Story Title)

New title for the story. If provided, updates the story title.

description
string (Story Description)

New description for the story. If provided, updates the story description.

visibility_status
string (Visibility Status)

Visibility Status:

Value Status
"0" Private
"1" Unlisted
"2" Public
Enum: "0" "1" "2"
additional_videos
string (Additional Videos)

JSON array of additional video URLs to associate with the story. For internal use only.

Responses
200

Updated Story Object

400

Bad Request

404

Not Found

422

Validation Error

put/story/{story_id}
Request samples
Response samples
application/json
{}

Delete Story

Delete story

SecurityAPIKeyHeader
Responses
200

Deleted Story Object

400

Bad Request

404

Not Found

422

Validation Error

delete/story/{story_id}
Request samples
Response samples
application/json
{ }

Concat Story

Composes all generated scene videos into a single final story video.

This endpoint concatenates individual scene videos (and optionally custom video URLs) into one cohesive story video with synchronized audio.

Use Cases

  • Compose scene videos generated in Advanced Mode
  • Combine custom video URLs with generated scenes
  • Add background audio to the final composition

Parameters

Parameter Type Required Default Description
concat_video_urls array[string] No null Array of video URLs to compose. If not provided, uses generated scene videos.
audio_urls array[string] No null Array of background audio URLs to overlay on the final video

Example Request

import requests

STORY_ID = "your-story-id-here"
url = f"https://api.vimmerse.net/story/{STORY_ID}/concat"
headers = {"X-Api-Key": "YOUR_API_KEY"}

# Option 1: Compose generated scene videos (no parameters needed)
payload = {}

# Option 2: Compose custom video URLs
payload = {
    "concat_video_urls": [
        "https://example.com/video1.mp4",
        "https://example.com/video2.mp4",
        "https://example.com/video3.mp4"
    ],
    "audio_urls": [
        "https://example.com/background-music.mp3"
    ]
}

try:
    response = requests.post(url, headers=headers, data=payload, timeout=60)
    response.raise_for_status()

    result = response.json()
    print(f"Composition started for story: {result['data']['id']}")

    # Monitor progress using GET /story/{story_id}
    # The video_url field will be populated when composition completes

except requests.exceptions.RequestException as e:
    print(f"Error: {e}")

Monitoring Composition

After initiating composition, check the story status:

import requests
import time

STORY_ID = "your-story-id-here"

def get_final_video(story_id):
    url = f"https://api.vimmerse.net/story/{story_id}"
    headers = {"X-Api-Key": "YOUR_API_KEY"}
    try:
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()
        return response.json()["data"].get("video_url")
    except requests.exceptions.RequestException:
        return None

# Wait for composition to complete (max ~5 minutes)
for _ in range(30):
    video_url = get_final_video(STORY_ID)
    if video_url:
        print(f"Final video: {video_url}")
        break
    print("Composition in progress...")
    time.sleep(10)
else:
    print("Timeout: Check status later with GET /story/{story_id}")

Note: Composition typically takes 1-3 minutes depending on video length and number of scenes.

SecurityAPIKeyHeader
Request
Request Body schema: application/x-www-form-urlencoded
concat_video_urls
Array of strings (Video URLs to Compose)

Array of video URLs to compose into the final story video. If not provided, uses the generated scene videos from the story.

audio_urls
Array of strings (Background Audio URLs)

Array of background audio URLs to overlay on the final composed video. Multiple audio files will be mixed together.

Responses
200

Story Object

400

Bad Request

402

Insufficient Credit

404

Not Found

422

Validation Error

post/story/{story_id}/concat
Request samples
Response samples
application/json
{ }