> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vibepeak.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Living Property Video

> Create an AI-powered real estate video with virtual staging and automatic narration

## Example Output

<Frame>
  <video autoPlay muted loop playsInline poster="https://web-files.vibepeak.ai/use-cases/realestate/en/real-estate-3-thumb.webp" className="w-full rounded-lg">
    <source src="https://web-files.vibepeak.ai/use-cases/realestate/en/real-estate-3-preview.webm" type="video/webm" />

    <source src="https://web-files.vibepeak.ai/use-cases/realestate/en/real-estate-3-preview.mp4" type="video/mp4" />
  </video>
</Frame>

***

Creates a new living property video from real estate images. This endpoint uses AI to transform static property photos into dynamic videos with optional virtual staging, AI-generated narration, and background music.

The video generation is asynchronous - you'll receive a task ID to poll for status or configure a webhook to be notified when complete.

## Key Features

* **Virtual Staging**: Add people, furniture, or redecorate rooms using AI
* **AI Narration**: Provide your own script for professional text-to-speech narration — or set `voiceover_enabled: false` for a music-only video
* **Background Music**: Optional ambient music that complements your property video

## Request Body

<ParamField body="images" type="object[]" required>
  Array of image objects for the video. Must contain **5 to 9 images**.

  You can also pass a plain URL string instead of an object — it behaves the same as `{ "url": "..." }`.

  Each image object contains:

  * `url` (required): Publicly accessible HTTP(S) URL of the property image
  * `room_type` (optional): Type of room for better AI processing
  * `modification_mode` (optional): per-image override of the request-level `modification_mode` — omit to inherit
  * `include_humans_and_pets` (optional): per-image override of the request-level `include_humans_and_pets` — omit to inherit

  <Expandable title="Available room types">
    `bedroom`, `kitchen`, `living_room`, `bathroom`, `dining_room`, `office`, `garage`, `basement`, `attic`, `patio`, `balcony`, `garden`, `pool`, `exterior`, `entrance`, `hallway`, `laundry`, `other`
  </Expandable>

  <Tip>
    **Per-image exceptions.** The top-level `modification_mode` / `include_humans_and_pets` apply to every image. To make an exception for one image — say, keep a facade original while the rest of the gallery is restyled — set those fields on that image object only:

    ```json theme={null}
    {
      "modification_mode": "change_decoration",
      "include_humans_and_pets": true,
      "images": [
        "https://example.com/property/living-room.jpg",
        {
          "url": "https://example.com/property/facade.jpg",
          "room_type": "exterior",
          "modification_mode": "no_modify",
          "include_humans_and_pets": false
        }
      ]
    }
    ```

    `decoration_style` stays request-level — it is a global aesthetic, not a per-image toggle.
  </Tip>

  <Warning>
    All image URLs must be unique. Duplicate URLs are not allowed.
  </Warning>

  <Warning>
    **Minimum resolution (HD floor):** every image's long side must be at least **1280 px** and short side at least **720 px**. Images below this threshold are rejected with `IMAGE_RESOLUTION_TOO_LOW`. CRMs that expose thumbnail URLs by default usually have a higher-resolution variant — use that one.
  </Warning>
</ParamField>

<ParamField body="voiceover_enabled" type="boolean" default="true">
  Whether the video has a voiceover (narration). Defaults to `true`.

  Set to `false` to create a **music-only** video: omit `voice` and `script`, and the video is produced with background music only (or silent if `background_music` is `false`). Subtitles are not available without a voiceover.
</ParamField>

<ParamField body="voice" type="object">
  Voice configuration for text-to-speech narration. **Required when `voiceover_enabled` is `true`** (the default); omit it together with `script` when `voiceover_enabled` is `false`.

  <Expandable title="Voice properties">
    <ParamField body="voice_id" type="string" required>
      Voice ID to use for narration. You can find available voices using the [List Voices](/api-reference/voices/list-voices) endpoint.
    </ParamField>

    <ParamField body="language" type="string" required>
      ISO 639-1 language code for TTS pronunciation (e.g., `en`, `es`, `de`, `fr`, `pt`).

      This helps produce more accurate pronunciation for the target language.

      <Tip>
        Use the same language code as the script content for best results.
      </Tip>
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="modification_mode" type="string" required>
  How to process the property images using AI.

  | Value               | Description                                                |
  | ------------------- | ---------------------------------------------------------- |
  | `no_modify`         | Keep rooms as-is, add realistic people for a lived-in feel |
  | `change_decoration` | Modernize old or outdated furniture and decor              |

  <Note>
    The `change_decoration` mode uses AI virtual staging to transform your images. Processing may take longer for this mode.
  </Note>

  <Note>
    Whether people are added is controlled by `include_humans_and_pets`. Together with `modification_mode`, it also selects the per-scene script budget — see `script`.
  </Note>

  <Warning>
    `furnish` was previously accepted but is **no longer supported**. Requests using it are rejected with a `VALIDATION_ERROR`. Use `change_decoration` to restyle or furnish the room, or `no_modify` to keep it unchanged.
  </Warning>
</ParamField>

<ParamField body="decoration_style" type="string">
  Interior decoration style applied when `modification_mode` is `change_decoration`. Ignored for the other modes. Defaults to a modern aesthetic when omitted.

  <Expandable title="Available styles">
    `scandinavian`, `minimalist`, `traditional`, `mid-century-modern`, `industrial`, `mediterranean`, `modern`, `bohemian`, `mountain-rustic`, `luxury`, `japandi`, `wabi-sabi`, `organic-modern`, `quiet-luxury`
  </Expandable>
</ParamField>

<ParamField body="include_humans_and_pets" type="boolean" default="true">
  Whether to add realistic people (and occasionally a pet) to the staged scenes.

  When enabled together with `change_decoration`, the video uses longer **two-step** scenes (the room is restyled, then animated), which widens the per-scene script budget — see `script`. Set to `false` to keep scenes free of people and use the single-step budget.
</ParamField>

<ParamField body="script" type="string">
  Narration script for text-to-speech. **Required when `voiceover_enabled` is `true`** (the default); omit it together with `voice` when `voiceover_enabled` is `false`. The length **must scale with the number of images**, and the per-scene budget **depends on the render mode**:

  **Single-step** — `no_modify`, or any mode with `include_humans_and_pets` set to `false`. Scenes are \~5 seconds, requiring **65–85 characters per image**:

  | Images | Min characters | Max characters |
  | ------ | -------------- | -------------- |
  | 5      | 325            | 425            |
  | 9      | 585            | 765            |

  **Two-step** — `change_decoration` with `include_humans_and_pets` set to `true` (the default). Scenes are \~7 seconds (restyle + animation), requiring **110–140 characters per image**:

  | Images | Min characters | Max characters |
  | ------ | -------------- | -------------- |
  | 5      | 550            | 700            |
  | 9      | 990            | 1260           |

  Scripts outside the applicable range are rejected with `SCRIPT_TOO_SHORT` or `SCRIPT_TOO_LONG`.

  <Warning>
    **Numbers and symbols are allowed.** Write the script naturally — numbers (e.g. `3 bedrooms`, `580.000 €`) and symbols are read correctly by text-to-speech. Only emojis and other non-speech characters (pictographs, control characters) are rejected.
  </Warning>

  <Tip>
    Write compelling property descriptions that highlight key features. The script should flow naturally when spoken aloud, and its length must fit the per-scene budget above.
  </Tip>
</ParamField>

<ParamField body="background_music" type="boolean" default="true">
  Enable AI-generated background music.

  When `true`, adds ambient music that complements the property video. The music is automatically mixed at an appropriate volume to not overpower the narration.
</ParamField>

<ParamField body="subtitle" type="object">
  Subtitle configuration for word-level animated overlays. Use `subtitle_style_preset` for quick setup or `styles` for granular control. Providing both will result in a validation error.

  <Note>
    Requires voiceover. Subtitles are derived from the narration's word timing, so omit `subtitle` (or set it to `false`) when `voiceover_enabled` is `false` — the request is rejected otherwise.
  </Note>

  <Expandable title="Subtitle Config properties">
    <ParamField body="subtitle_style_preset" type="string">
      Name of a predefined style to apply.
      Options: `classic`, `cinematic`, `gradient`, `handwritten`, `hustle`, `karaoke_highlight_no_box`, `karaoke_red_box_phrase`, `karaoke_word_box_clip`, `minimal`, `neon`, `one_word_red_box`, `phrase_yellow`, `retro`, `tiktok_default`, `youtube_caption`.
    </ParamField>

    <ParamField body="styles" type="object">
      Granular styling properties for subtitle rendering.

      <Expandable title="Styles properties">
        <ParamField body="alignment" type="integer" default="2">
          SSA alignment: 1-9 (e.g., 2 for bottom-center).
        </ParamField>

        <ParamField body="backColor" type="string" default="#000000">
          Background color in hex format (e.g., `#000000`).
        </ParamField>

        <ParamField body="backOpacity" type="integer" default="100">
          Transparency of background box: 0-255.
        </ParamField>

        <ParamField body="behavior" type="string" default="phrase_blocks">
          Subtitle reveal behavior. Options: `phrase_blocks`, `one_word`, `karaoke_highlight`, `karaoke_box_word`.
        </ParamField>

        <ParamField body="borderStyle" type="integer" default="1">
          Border style: 1 (Outline) or 3 (Box).
        </ParamField>

        <ParamField body="fontFamily" type="string" default="Arial">
          System font name.
        </ParamField>

        <ParamField body="fontSize" type="integer" default="28">
          Font size in pixels (14-96).
        </ParamField>

        <ParamField body="marginL" type="integer" default="40">
          Left margin in pixels (0-500).
        </ParamField>

        <ParamField body="marginR" type="integer" default="40">
          Right margin in pixels (0-500).
        </ParamField>

        <ParamField body="marginV" type="integer" default="200">
          Vertical/Bottom margin in pixels (0-500).
        </ParamField>

        <ParamField body="maxGapSeconds" type="number" default="0.3">
          Max silence (sec) between words before phrase break (0.01-2).
        </ParamField>

        <ParamField body="maxWordsPerLine" type="integer" default="6">
          Automatic line wrapping constraint (1-12).
        </ParamField>

        <ParamField body="outline" type="integer" default="2">
          Thickness of text stroke (0-10).
        </ParamField>

        <ParamField body="outlineColor" type="string" default="#000000">
          Color of text stroke in hex format.
        </ParamField>

        <ParamField body="primaryColor" type="string" default="#FFFFFF">
          Default text color in hex format.
        </ParamField>

        <ParamField body="secondaryColor" type="string" default="#FFFFFF">
          Alt color for highlights/karaoke in hex format.
        </ParamField>

        <ParamField body="shadow" type="integer" default="0">
          Thickness of text drop shadow (0-10).
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="webhook_url" type="string">
  HTTPS URL to receive webhook notification when the task completes.

  See [Webhooks](/concepts/webhooks) for payload format and verification details.

  <Warning>
    Webhook URLs must use HTTPS and cannot point to private/internal networks (SSRF protection).
  </Warning>
</ParamField>

<ParamField body="elements_config" type="object">
  Configuration for visual elements and branding overlays. If not provided, elements are disabled by default.

  <Expandable title="Elements Config properties">
    <ParamField body="enabled" type="boolean" default="false">
      Global toggle for the elements overlay feature.
    </ParamField>

    <ParamField body="watermark" type="object">
      Watermark (logo) branding configuration.

      <Expandable title="Watermark properties">
        <ParamField body="url" type="string" required>
          URL of the uploaded watermark image. Must be a valid public URL.
        </ParamField>

        <ParamField body="position" type="string" default="bottom-right">
          Anchor point for the watermark placement.
          Options: `top-left`, `top-center`, `top-right`, `center-left`, `center`, `center-right`, `bottom-left`, `bottom-center`, `bottom-right`.
        </ParamField>

        <ParamField body="size" type="number" default="20">
          Relative scale percentage of the watermark (0-100).
        </ParamField>

        <ParamField body="opacity" type="number" default="100">
          Transparency level (0 for transparent, 100 for opaque).
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="text" type="object">
      Text overlay configuration for static labels or call-to-actions.

      <Expandable title="Text properties">
        <ParamField body="content" type="string" required>
          Text content to be rendered on the video (max 20 characters).
        </ParamField>

        <ParamField body="color" type="string" default="#FFFFFF">
          Hex color code for the text (e.g., `#FFFFFF`).
        </ParamField>

        <ParamField body="font" type="string" default="Inter">
          Font family for the text overlay.
          Options: `Alegreya`, `DM Mono`, `Inter`, `Libre Bodoni`, `Quicksand`, `Roboto`, `Raleway`, `Noto Sans`, `Zilla Slab`.
        </ParamField>

        <ParamField body="opacity" type="number" default="100">
          Transparency level of the text (0-100).
        </ParamField>

        <ParamField body="size" type="number" default="20">
          Font size scale relative to video height (1-100).
        </ParamField>

        <ParamField body="position" type="string" default="center">
          Anchor point for the text placement. Same options as watermark position.
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

### Test Mode

<ParamField body="test_scenario" type="string" default="success">
  Sandbox-only scenario selector. **Honored only for test-mode (`vpk_test_`) keys and silently ignored for live keys**, so it is safe to leave in shared request-building code.

  | Value     | Outcome                                                       |
  | --------- | ------------------------------------------------------------- |
  | `success` | Synthetic task completes with a watermarked sample video      |
  | `fail`    | Synthetic task fails with a sanitized, public-safe error      |
  | `slow`    | Like `success`, but completes after a noticeably longer delay |

  <Note>
    Test mode never spends credits or runs the real pipeline. See [Test Mode](/concepts/test-mode) for the full sandbox model.
  </Note>
</ParamField>

## Response

Returns a `202 Accepted` response with task details.

<ResponseField name="task_id" type="string" required>
  Unique identifier for the task. Use this to poll for status via [Get Task](/api-reference/videos/get-task).
</ResponseField>

<ResponseField name="status" type="string" required>
  Initial task status. Always `queued` for new tasks.
</ResponseField>

<ResponseField name="message" type="string" required>
  Human-readable confirmation message.
</ResponseField>

<ResponseField name="created_at" type="string" required>
  Task creation timestamp (ISO 8601 format).
</ResponseField>

<ResponseField name="credits_charged" type="integer" required>
  Number of credits charged for this request (15 credits). Always `0` for test-mode requests.
</ResponseField>

<ResponseField name="livemode" type="boolean" required>
  `true` for live (`vpk_live_`) requests; `false` for test-mode (`vpk_test_`) requests. Use this to tell a real task from a sandbox one. See [Test Mode](/concepts/test-mode).
</ResponseField>

<ResponseField name="request_id" type="string" required>
  Unique request ID for support reference.
</ResponseField>

<ResponseField name="_links" type="object" required>
  HATEOAS links for navigation.

  * `self`: URL to poll for task status
  * `poll_interval_seconds`: Recommended polling interval (30 seconds)
</ResponseField>

### Response Headers

| Header        | Description                                        |
| ------------- | -------------------------------------------------- |
| `Location`    | URL to poll for task status (`/v1/tasks/{taskId}`) |
| `Retry-After` | Recommended polling interval in seconds (30)       |

<RequestExample>
  ```bash cURL (with custom script) theme={null}
  curl -X POST https://api.vibepeak.ai/v1/real-estate/living-property \
    -H "Authorization: Bearer vpk_live_xxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "images": [
        { "url": "https://example.com/property/living-room.jpg", "room_type": "living_room" },
        { "url": "https://example.com/property/kitchen.jpg", "room_type": "kitchen" },
        { "url": "https://example.com/property/bedroom.jpg", "room_type": "bedroom" },
        { "url": "https://example.com/property/bathroom.jpg", "room_type": "bathroom" },
        { "url": "https://example.com/property/exterior.jpg", "room_type": "exterior" }
      ],
      "voice": {
        "voice_id": "EXAVITQu4vr4xnSDxMaL",
        "language": "en"
      },
      "modification_mode": "no_modify",
      "script": "Welcome to this stunning modern home where comfort meets contemporary design. The spacious living room is filled with natural light and elegant finishes. The kitchen offers sleek cabinetry and generous counter space. Each bedroom feels calm and inviting, while the bright bathroom adds a touch of luxury. Step outside to enjoy a beautiful private garden.",
      "webhook_url": "https://yourserver.com/webhooks/vibepeak",
      "subtitle": {
        "subtitle_style_preset": "classic"
      },
      "elements_config": {
        "enabled": true,
        "watermark": {
          "url": "https://example.com/logo.png",
          "position": "bottom-right",
          "size": 20,
          "opacity": 100
        },
        "text": {
          "content": "Powered by Vibepeak",
          "color": "#FFFFFF",
          "font": "Inter",
          "size": 20,
          "position": "center"
        }
      }
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://api.vibepeak.ai/v1/real-estate/living-property', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer vpk_live_xxxxx',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      images: [
        { url: 'https://example.com/property/living-room.jpg', room_type: 'living_room' },
        { url: 'https://example.com/property/kitchen.jpg', room_type: 'kitchen' },
        { url: 'https://example.com/property/bedroom.jpg', room_type: 'bedroom' },
        { url: 'https://example.com/property/bathroom.jpg', room_type: 'bathroom' },
        { url: 'https://example.com/property/exterior.jpg', room_type: 'exterior' }
      ],
      voice: {
        voice_id: 'EXAVITQu4vr4xnSDxMaL',
        language: 'en'
      },
      modification_mode: 'no_modify',
      script: 'Welcome to this stunning modern home where comfort meets contemporary design. The spacious living room is filled with natural light and elegant finishes. The kitchen offers sleek cabinetry and generous counter space. Each bedroom feels calm and inviting, while the bright bathroom adds a touch of luxury. Step outside to enjoy a beautiful private garden.',
      webhook_url: 'https://yourserver.com/webhooks/vibepeak',
      subtitle: {
        subtitle_style_preset: 'classic'
      },
      elements_config: {
        enabled: true,
        watermark: {
          url: 'https://example.com/logo.png',
          position: 'bottom-right',
          size: 20,
          opacity: 100
        },
        text: {
          content: 'Powered by Vibepeak',
          color: '#FFFFFF',
          font: 'Inter',
          size: 20,
          position: 'center'
        }
      }
    })
  });

  const task = await response.json();
  console.log(`Task created: ${task.task_id}`);
  console.log(`Poll at: ${response.headers.get('Location')}`);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'https://api.vibepeak.ai/v1/real-estate/living-property',
      headers={
          'Authorization': 'Bearer vpk_live_xxxxx',
          'Content-Type': 'application/json'
      },
      json={
          'images': [
              {'url': 'https://example.com/property/living-room.jpg', 'room_type': 'living_room'},
              {'url': 'https://example.com/property/kitchen.jpg', 'room_type': 'kitchen'},
              {'url': 'https://example.com/property/bedroom.jpg', 'room_type': 'bedroom'},
              {'url': 'https://example.com/property/bathroom.jpg', 'room_type': 'bathroom'},
              {'url': 'https://example.com/property/exterior.jpg', 'room_type': 'exterior'}
          ],
          'voice': {
              'voice_id': 'EXAVITQu4vr4xnSDxMaL',
              'language': 'en'
          },
          # change_decoration + include_humans_and_pets (default true) → two-step scenes,
          # so the script uses the wider 110-140 chars/scene budget (550-700 for 5 images).
          'modification_mode': 'change_decoration',
          'include_humans_and_pets': True,
          'script': 'Welcome to this beautifully renovated apartment where modern comfort meets timeless elegance throughout every room. The bright living room invites you to relax, with large windows that fill the space with warm natural light. The kitchen features sleek cabinetry, premium finishes, and generous counter space for cooking and gathering. Each bedroom offers a calm and restful retreat, while the elegant bathroom adds a genuine touch of luxury. Step outside to discover a private garden, perfect for morning coffee or relaxing evenings under the open sky. The home has been finished to a high standard and is ready for you to move in and enjoy from the very first day.',
          'background_music': True,
          'subtitle': {
              'subtitle_style_preset': 'classic'
          },
          'elements_config': {
              'enabled': True,
              'watermark': {
                  'url': 'https://example.com/logo.png',
                  'position': 'bottom-right',
                  'size': 20,
                  'opacity': 100
              },
              'text': {
                  'content': 'Powered by Vibepeak',
                  'color': '#FFFFFF',
                  'font': 'Inter',
                  'size': 20,
                  'position': 'center'
              }
          }
      }
  )

  task = response.json()
  print(f"Task created: {task['task_id']}")
  print(f"Credits charged: {task['credits_charged']}")
  ```
</RequestExample>

<ResponseExample>
  ```json 202 Accepted theme={null}
  {
    "task_id": "task_abc123xyz",
    "status": "queued",
    "message": "Real estate video generation request accepted",
    "created_at": "2026-01-19T12:00:00Z",
    "credits_charged": 15,
    "livemode": true,
    "request_id": "req_xyz123",
    "_links": {
      "self": "/v1/tasks/task_abc123xyz",
      "poll_interval_seconds": 30
    }
  }
  ```

  ```json 202 Accepted (Test Mode) theme={null}
  {
    "task_id": "task_abc123xyz",
    "status": "queued",
    "message": "Real estate video generation request accepted",
    "created_at": "2026-01-19T12:00:00Z",
    "credits_charged": 0,
    "livemode": false,
    "request_id": "req_xyz123",
    "_links": {
      "self": "/v1/tasks/task_abc123xyz",
      "poll_interval_seconds": 30
    }
  }
  ```

  ```json 400 Bad Request (Validation Error) theme={null}
  {
    "error": {
      "code": "VALIDATION_ERROR",
      "message": "script is required",
      "request_id": "req_xyz123",
      "details": {
        "field": "script",
        "issues": [
          {
            "path": "script",
            "message": "Required"
          }
        ]
      }
    }
  }
  ```

  ```json 400 Bad Request (Invalid Characters) theme={null}
  {
    "error": {
      "code": "SCRIPT_INVALID_CHARACTERS",
      "message": "Script contains characters not supported by text-to-speech: \"🏠\". Emojis and other non-speech symbols are not allowed.",
      "request_id": "req_xyz123",
      "details": {
        "invalid_characters": ["3", "$"]
      }
    }
  }
  ```

  ```json 400 Bad Request (Subtitle Conflict) theme={null}
  {
    "error": {
      "code": "VALIDATION_ERROR",
      "message": "Provide either 'subtitle_style_preset' or 'styles', but not both.",
      "request_id": "req_xyz123"
    }
  }
  ```

  ```json 400 Bad Request (Script Too Short) theme={null}
  {
    "error": {
      "code": "SCRIPT_TOO_SHORT",
      "message": "Script is too short for 5 image(s). Minimum 325 characters required (65 per scene), but got 200. Either lengthen the script or send fewer images.",
      "request_id": "req_xyz123",
      "details": {
        "script_length": 200,
        "min_length": 325,
        "max_length": 425,
        "image_count": 5,
        "chars_per_scene_min": 65,
        "chars_per_scene_max": 85
      }
    }
  }
  ```

  ```json 400 Bad Request (Script Too Long — two-step budget for change_decoration + people) theme={null}
  {
    "error": {
      "code": "SCRIPT_TOO_LONG",
      "message": "Script is too long for 5 image(s). Maximum 700 characters allowed (140 per scene), but got 800. Either shorten the script or send more images.",
      "request_id": "req_xyz123",
      "details": {
        "script_length": 800,
        "min_length": 550,
        "max_length": 700,
        "image_count": 5,
        "chars_per_scene_min": 110,
        "chars_per_scene_max": 140
      }
    }
  }
  ```

  ```json 400 Bad Request (Image Resolution Too Low) theme={null}
  {
    "error": {
      "code": "IMAGE_RESOLUTION_TOO_LOW",
      "message": "1 image(s) below the minimum resolution. Required: long side ≥ 1280px and short side ≥ 720px.",
      "request_id": "req_xyz123",
      "details": {
        "invalid_images": ["https://example.com/thumbnail.jpg"]
      }
    }
  }
  ```

  ```json 400 Bad Request (Elements Config Missing) theme={null}
  {
    "error": {
      "code": "VALIDATION_ERROR",
      "message": "If elements_config is enabled, you must provide at least a 'watermark' or 'text' configuration.",
      "request_id": "req_xyz123",
      "details": {
        "path": ["elements_config", "enabled"]
      }
    }
  }
  ```

  ```json 400 Bad Request (Invalid Hex Color) theme={null}
  {
    "error": {
      "code": "VALIDATION_ERROR",
      "message": "Invalid hex color",
      "request_id": "req_xyz123",
      "details": {
        "path": ["elements_config", "text", "color"]
      }
    }
  }
  ```

  ```json 400 Bad Request (Invalid Voice) theme={null}
  {
    "error": {
      "code": "VOICE_NOT_FOUND",
      "message": "Voice ID not found",
      "request_id": "req_xyz123"
    }
  }
  ```

  ```json 403 Forbidden (Voice Access) theme={null}
  {
    "error": {
      "code": "VOICE_ACCESS_DENIED",
      "message": "Voice not accessible",
      "request_id": "req_xyz123"
    }
  }
  ```

  ```json 429 Too Many Requests theme={null}
  {
    "error": {
      "code": "CONCURRENCY_LIMIT_EXCEEDED",
      "message": "You have reached your concurrent task limit of 1. Please wait for existing tasks to complete.",
      "request_id": "req_xyz123",
      "details": {
        "limit": 1,
        "in_flight": 1,
        "plan": "Plus"
      }
    }
  }
  ```

  ```json 503 Service Unavailable theme={null}
  {
    "error": {
      "code": "SERVICE_UNAVAILABLE",
      "message": "Video generation service is temporarily unavailable. Please try again later.",
      "request_id": "req_xyz123"
    }
  }
  ```
</ResponseExample>

## Error Codes

| Code                         | Status | Description                                                                                     |
| ---------------------------- | ------ | ----------------------------------------------------------------------------------------------- |
| `INVALID_JSON`               | 400    | Request body is not valid JSON (malformed/truncated payload)                                    |
| `VALIDATION_ERROR`           | 400    | Invalid request parameters                                                                      |
| `INVALID_IMAGE_URL`          | 400    | One or more image URLs are inaccessible or invalid                                              |
| `INVALID_WATERMARK_URL`      | 400    | The `elements_config` watermark URL is inaccessible or does not return an image                 |
| `IMAGE_RESOLUTION_TOO_LOW`   | 400    | One or more images are below the HD floor (long ≥ 1280 px, short ≥ 720 px)                      |
| `SCRIPT_TOO_SHORT`           | 400    | Script is shorter than the per-scene minimum (`image_count × 65` single-step, `× 120` two-step) |
| `SCRIPT_TOO_LONG`            | 400    | Script is longer than the per-scene maximum (`image_count × 85` single-step, `× 150` two-step)  |
| `SCRIPT_INVALID_CHARACTERS`  | 400    | Script contains emojis or other non-speech characters not supported by TTS                      |
| `VOICE_NOT_FOUND`            | 404    | The specified voice ID does not exist                                                           |
| `VOICE_ACCESS_DENIED`        | 403    | The specified voice is not accessible to your account                                           |
| `INVALID_API_KEY`            | 401    | Invalid or missing API key                                                                      |
| `PLAN_REQUIRED`              | 403    | Plan doesn't include API access                                                                 |
| `INSUFFICIENT_CREDITS`       | 402    | Not enough credits to process the request                                                       |
| `CONCURRENCY_LIMIT_EXCEEDED` | 429    | Concurrent task limit reached                                                                   |
| `SERVICE_UNAVAILABLE`        | 503    | Video generation service temporarily unavailable                                                |

See [Error Handling](/concepts/error-handling) for more details.

## Credits

This endpoint charges **15 credits** per request upon successful task creation. If the task fails during processing, credits are not refunded.

## Processing Time

Video generation typically takes **3-5 minutes** depending on:

* Number of images
* Selected modification mode (`change_decoration` takes longer)
* Current system load

Use the `Retry-After` header (30 seconds) as a guide for polling frequency.

## Next Steps

After creating a task:

1. **Poll for status**: Use [Get Task](/api-reference/videos/get-task) to check progress
2. **Wait for webhook**: If configured, receive notification when complete
3. **Download video**: Access the video URL from the completed task result
