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

# Video Editing

> Learn how to edit and transform existing videos with AI.

Transform and edit existing videos using text prompts, reference images, or both. Upload a video, describe the changes you want, and Lucy 2.1 will modify it while preserving motion and temporal consistency — perfect for style transfers, object modifications, character replacements, and visual transformations.

## Quick start

Here's a simple example using `lucy-latest`, which always targets the newest video editing model (currently Lucy 2.1).

<CodeGroup>
  ```bash Curl theme={null}
  # Submit job
  JOB_ID=$(curl -s -X POST https://api.decart.ai/v1/jobs/lucy-latest \
    -H "X-API-KEY: $DECART_API_KEY" \
    -F "data=@input-video.mp4" \
    -F "prompt=Change the car to a vintage motorcycle" | jq -r '.job_id')

  # Poll until completed
  while true; do
    STATUS=$(curl -s -H "X-API-KEY: $DECART_API_KEY" \
      https://api.decart.ai/v1/jobs/$JOB_ID | jq -r '.status')
    echo "Status: $STATUS"
    [ "$STATUS" = "completed" ] && break
    [ "$STATUS" = "failed" ] && exit 1
    sleep 2
  done

  # Download result
  curl -H "X-API-KEY: $DECART_API_KEY" \
    https://api.decart.ai/v1/jobs/$JOB_ID/content --output edited-video.mp4
  ```

  ```python Python SDK theme={null}
  import asyncio
  from decart import DecartClient, models

  async def edit_video():
      async with DecartClient(api_key="your-api-key-here") as client:
          with open("input-video.mp4", "rb") as video_file:
              result = await client.queue.submit_and_poll({
                  "model": models.video("lucy-latest"),
                  "prompt": "Change the car to a vintage motorcycle",
                  "data": video_file,
                  "on_status_change": lambda job: print(f"Status: {job.status}"),
              })

          if result.status == "completed":
              with open("edited-video.mp4", "wb") as f:
                  f.write(result.data)

  asyncio.run(edit_video())
  ```

  ```javascript JavaScript SDK theme={null}
  import { createDecartClient, models } from "@decartai/sdk";
  import { readFileSync, writeFileSync } from "fs";

  const client = createDecartClient({ apiKey: "your-api-key-here" });

  const videoBuffer = readFileSync("input-video.mp4");
  const videoBlob = new Blob([videoBuffer], { type: "video/mp4" });

  const result = await client.queue.submitAndPoll({
    model: models.video("lucy-latest"),
    prompt: "Change the car to a vintage motorcycle",
    data: videoBlob,
    onStatusChange: (job) => console.log(`Status: ${job.status}`),
  });

  if (result.status === "completed") {
    const buffer = Buffer.from(await result.data.arrayBuffer());
    writeFileSync("edited-video.mp4", buffer);
  }
  ```

  ```python Python (REST) theme={null}
  import requests
  import os
  import time

  headers = {"X-API-KEY": os.getenv("DECART_API_KEY")}

  # Submit job
  with open("input-video.mp4", "rb") as video:
      response = requests.post(
          "https://api.decart.ai/v1/jobs/lucy-latest",
          headers=headers,
          files={"data": video},
          data={"prompt": "Change the car to a vintage motorcycle"}
      )
  job_id = response.json()["job_id"]

  # Poll until completed
  while True:
      status_response = requests.get(f"https://api.decart.ai/v1/jobs/{job_id}", headers=headers)
      status = status_response.json()["status"]
      print(f"Status: {status}")
      if status == "completed":
          break
      elif status == "failed":
          raise Exception("Job failed")
      time.sleep(2)

  # Download result
  result = requests.get(f"https://api.decart.ai/v1/jobs/{job_id}/content", headers=headers)
  with open("edited-video.mp4", "wb") as f:
      f.write(result.content)
  ```

  ```javascript JavaScript (REST) theme={null}
  const headers = { "X-API-KEY": process.env.DECART_API_KEY };

  // Submit job
  const formData = new FormData();
  formData.append("data", videoFile);
  formData.append("prompt", "Change the car to a vintage motorcycle");

  const submitResponse = await fetch("https://api.decart.ai/v1/jobs/lucy-latest", {
    method: "POST",
    headers,
    body: formData,
  });
  const { job_id } = await submitResponse.json();

  // Poll until completed
  while (true) {
    const statusResponse = await fetch(`https://api.decart.ai/v1/jobs/${job_id}`, { headers });
    const { status } = await statusResponse.json();
    console.log(`Status: ${status}`);
    if (status === "completed") break;
    if (status === "failed") throw new Error("Job failed");
    await new Promise((r) => setTimeout(r, 2000));
  }

  // Download result
  const resultResponse = await fetch(`https://api.decart.ai/v1/jobs/${job_id}/content`, { headers });
  const editedVideo = await resultResponse.blob();
  ```
</CodeGroup>

### Parameters

* `data` (**required**) — Input video file to edit.
* `prompt` (**required**) — Text description of the changes to apply. For Lucy 2.1, send an empty string if you want to use only a reference image.
* `reference_image` (**optional**) — An image to guide the edit. Use this to show the model exactly what you want to add or change (e.g., a specific pair of sunglasses, a logo, or a style reference).
* `resolution` (**optional**) — Output resolution: `720p` (default: `720p`).

<Note>
  You can drive edits with text, a visual reference, or a combination of both.
</Note>

### Video Requirements

* **Format:** MP4 (H.264 or VP8 codec)
* **Aspect Ratio:** 16:9 (landscape) or 9:16 (portrait)
* **Duration:** Unlimited with Lucy 2.1. Previous-generation Lucy Clip supports clips up to 5 seconds.
* **File Size:** Maximum 200MB
* **Output Resolution:**
  * `720p`: 720×1280 (portrait) or 1280×720 (landscape)

<Note>
  For complete API documentation including response formats and error codes, see the [API Reference](/api-reference/lucy-21).
</Note>

## Available Models and Options

Decart provides different editing models to balance **precision, creativity, and cost** depending on your use case.

We currently offer:

* **Lucy 2.1** *(Recommended)* — our latest and most advanced editing model. Fastest speed, excellent quality, unlimited duration, supports prompt and optional reference image.
* **Lucy Clip** *(Previous generation)* — older editing model. Limited to 5-second clips.

<Warning>
  **Lucy Clip is a previous-generation model.** We recommend Lucy 2.1 (`lucy-2.1`) for all new video editing projects. It is faster, supports unlimited duration, and costs the same or less.
</Warning>

### Model Comparison

| Model         | Status      | Quality   | Speed    | Reference Image | Duration  | Cost       | Best For                             |
| ------------- | ----------- | --------- | -------- | --------------- | --------- | ---------- | ------------------------------------ |
| **Lucy 2.1**  | Recommended | Excellent | Fastest  | ✅ Supported     | Unlimited | \$0.04/sec | All video editing use cases (latest) |
| **Lucy Clip** | Legacy      | Excellent | Standard | ✅ Supported     | Max 5 sec | \$0.15/sec | —                                    |

## Prompting Guide

Lucy 2.1 responds best when your prompts follow specific patterns for each edit type. Focus only on what needs to change — you don't need to describe the entire scene.

| Edit type                    | Prompt template                                                 |
| ---------------------------- | --------------------------------------------------------------- |
| **Character transformation** | "Substitute the character in the video with \<description>."    |
| **Add**                      | "Add \<description of object> to \<where to add it>."           |
| **Replace**                  | "Change \<object to change> with \<description of new object>." |
| **Change attribute**         | "Change \<object> to \<description of new attribute>."          |
| **Style transfer**           | "Transform to \<style> with \<specific visual details>."        |

### Character Transformation

Swap the person in the video with a different character. When using a reference image, describe the character's appearance in the prompt for best results.

* *"Substitute the character with an older man with pale skin, light blue eyes, a powdered white wig, and a dark formal coat with a white ruffled neckpiece."*
* *"Substitute the character with a young person wearing a pink top with white ribbon ties, loose pink pants, and short brown hair."*

### Adding & Replacing Objects

Add new elements or swap existing ones. Always specify placement for additions.

* *"Add a red conical hat covered in sequins with a white fluffy trim to the person's head."*
* *"Change the person's sweater to a red knit sweater with a white-outlined gold emblem on the chest."*
* *"Replace the car with a futuristic hoverbike, metallic finish."*

### Changing Attributes

Modify a property of an existing object — color, texture, material — without replacing it entirely.

* *"Change the wall's color to light blue, natural consistent paint finish."*
* *"Change the shirt's texture to knitted, woven fabric."*

### Style Transfer

Apply consistent visual styles across all frames.

* *"Transform to anime style with vibrant colors and cel shading."*
* *"Apply film noir aesthetic with high contrast black and white."*

### Prompt Tips

* **Be specific** — "a red knit sweater with a white emblem on the chest" outperforms "a red sweater"
* **Describe the reference image** — when using character transformation, describe what you see in the reference (skin, hair, clothing, features)
* **One edit per prompt** — combining multiple edits can produce unpredictable results
* **Detail improves results** — detailed prompts (20–40 words) describing style, appearance, and context produce significantly better results than short instructions

## Using Reference Images

For more precise edits, **Lucy 2.1** supports an optional `reference_image` parameter. This allows you to provide a visual reference that guides the edit—perfect for when you want to add a specific item (like a particular style of sunglasses) or match a specific look.

<Note>
  Reference images are supported with **Lucy 2.1** (`lucy-2.1`) and the previous-generation **Lucy Clip** (`lucy-clip`).
</Note>

With **Lucy 2.1**, you can use a reference image with an empty prompt — the model will transform the video to match the reference image directly:

<CodeGroup>
  ```bash Curl (Reference Image Only) theme={null}
  # Submit job with reference image and empty prompt
  JOB_ID=$(curl -s -X POST https://api.decart.ai/v1/jobs/lucy-latest \
    -H "X-API-KEY: $DECART_API_KEY" \
    -F "data=@input-video.mp4" \
    -F "prompt=" \
    -F "reference_image=@style-reference.jpg" | jq -r '.job_id')

  # Poll and download as before...
  ```

  ```python Python SDK (Reference Image Only) theme={null}
  import asyncio
  from decart import DecartClient, models

  async def edit_video_with_reference():
      async with DecartClient(api_key="your-api-key-here") as client:
          with open("input-video.mp4", "rb") as video_file:
              with open("style-reference.jpg", "rb") as reference_image:
                  result = await client.queue.submit_and_poll({
                      "model": models.video("lucy-latest"),
                      "prompt": "",
                      "data": video_file,
                      "reference_image": reference_image,
                      "on_status_change": lambda job: print(f"Status: {job.status}"),
                  })

          if result.status == "completed":
              with open("edited-video.mp4", "wb") as f:
                  f.write(result.data)

  asyncio.run(edit_video_with_reference())
  ```

  ```javascript JavaScript SDK (Reference Image Only) theme={null}
  import { createDecartClient, models } from "@decartai/sdk";
  import { readFileSync, writeFileSync } from "fs";

  const client = createDecartClient({ apiKey: "your-api-key-here" });

  const videoBuffer = readFileSync("input-video.mp4");
  const videoBlob = new Blob([videoBuffer], { type: "video/mp4" });

  const imageBuffer = readFileSync("style-reference.jpg");
  const imageBlob = new Blob([imageBuffer], { type: "image/jpeg" });

  const result = await client.queue.submitAndPoll({
    model: models.video("lucy-latest"),
    prompt: "",
    data: videoBlob,
    reference_image: imageBlob,
    onStatusChange: (job) => console.log(`Status: ${job.status}`),
  });

  if (result.status === "completed") {
    const buffer = Buffer.from(await result.data.arrayBuffer());
    writeFileSync("edited-video.mp4", buffer);
  }
  ```
</CodeGroup>

<CodeGroup>
  ```bash Curl theme={null}
  # Submit job with reference image
  JOB_ID=$(curl -s -X POST https://api.decart.ai/v1/jobs/lucy-latest \
    -H "X-API-KEY: $DECART_API_KEY" \
    -F "data=@input-video.mp4" \
    -F "prompt=Add these sunglasses to her face" \
    -F "reference_image=@sunglasses.jpg" | jq -r '.job_id')

  # Poll and download as before...
  ```

  ```python Python SDK theme={null}
  import asyncio
  from decart import DecartClient, models

  async def edit_video_with_reference():
      async with DecartClient(api_key="your-api-key-here") as client:
          with open("input-video.mp4", "rb") as video_file:
              with open("sunglasses.jpg", "rb") as reference_image:
                  result = await client.queue.submit_and_poll({
                      "model": models.video("lucy-latest"),
                      "prompt": "Add these sunglasses to her face",
                      "data": video_file,
                      "reference_image": reference_image,
                      "on_status_change": lambda job: print(f"Status: {job.status}"),
                  })

          if result.status == "completed":
              with open("edited-video.mp4", "wb") as f:
                  f.write(result.data)

  asyncio.run(edit_video_with_reference())
  ```

  ```javascript JavaScript SDK theme={null}
  import { createDecartClient, models } from "@decartai/sdk";
  import { readFileSync, writeFileSync } from "fs";

  const client = createDecartClient({ apiKey: "your-api-key-here" });

  const videoBuffer = readFileSync("input-video.mp4");
  const videoBlob = new Blob([videoBuffer], { type: "video/mp4" });

  const imageBuffer = readFileSync("sunglasses.jpg");
  const imageBlob = new Blob([imageBuffer], { type: "image/jpeg" });

  const result = await client.queue.submitAndPoll({
    model: models.video("lucy-latest"),
    prompt: "Add these sunglasses to her face",
    data: videoBlob,
    reference_image: imageBlob,
    onStatusChange: (job) => console.log(`Status: ${job.status}`),
  });

  if (result.status === "completed") {
    const buffer = Buffer.from(await result.data.arrayBuffer());
    writeFileSync("edited-video.mp4", buffer);
  }
  ```
</CodeGroup>

## Endpoint and Full API Reference

* **Lucy 2.1** *(Recommended)*: [`/v1/jobs/lucy-2.1`](/api-reference/lucy-21) or `/v1/jobs/lucy-latest`
* **Lucy Clip** *(Legacy)*: [`/v1/jobs/lucy-clip`](/api-reference/lucy-edit)

## Next steps

Now that you know the basics of video editing, you might want to check out one of these resources next.

<CardGroup>
  <Card icon="cube" title="Edit a video in the Platform" href="https://platform.decart.ai/models/lucy-edit">
    Try out video editing and other models in the interactive platform.
  </Card>

  <Card icon="code" title="Full API reference" href="/api-reference/lucy-21">
    Check out all the options for video editing in the API reference.
  </Card>

  <Card icon="shirt" title="Virtual Try-On" href="/models/realtime/virtual-try-on">
    Dress people in videos with text prompts or garment reference images.
  </Card>
</CardGroup>
