alibaba/happy-horse/video-edit

HappyHorse video editing supports advanced video editing through natural language instructions. It allows for local or global editing of video elements using up to 5 reference images.
Inference
Commercial use
Partner

Input

Additional Settings

Customize your input with more control.

Result

Idle

What would you like to do next?

For every second of 720p video you generated, you will be charged $0.28/second ($0.14 per input second and 0.14 per output second). For 1080p video you will be charged $0.56/second.

Logs

Run Happy Horse 1.0: AI Video Editor API

Edit an existing video using natural language instructions. Supports both local edits (targeted changes to specific elements) and global edits (style, color, atmosphere) with optional reference images to guide the result.

Model ID: `alibaba/happy-horse/video-edit`
Provider: fal.ai
Commercial rights: Full commercial rights on all outputs


About the model

The video-edit endpoint exposes Happy Horse's Video-to-Video (V2V) capability: the model takes a source clip and a text prompt, then modifies the video while preserving its original structure, composition, and motion.

Two editing modes are supported:

  • Global edits: apply a change across the entire clip: recoloring the sky, shifting the visual style, changing the season or time of day, altering the mood or lighting
  • Local edits: target a specific region or element: swapping an object, changing a character's outfit, replacing a background, making surgical fixes to a single area

You can supply up to 5 reference images alongside the prompt, referencing them in the prompt as `@Image1`, `@Image2`, etc. — for example, to specify what a replaced subject should look like, or to lock in a visual style from another image.


Specifications

PropertyValue
Input formatsMP4, MOV (H.264 recommended)
Input duration3–60 seconds
Output durationMatches input, capped at 15 seconds (longer inputs truncated to first 15 s)
Input resolutionLonger side ≤ 2160px, shorter side ≥ 320px
Input aspect ratioBetween 1:2.5 and 2.5:1
Input frame rate> 8 fps
Input max file size100 MB
Output resolution720p, 1080p (aspect ratio preserved from source)
Reference imagesUp to 5, min 300px, max 10 MB each
Prompt lengthUp to 2,500 characters

Pricing

ResolutionPrice
720p$0.14 / second
1080p$0.28 / second

Pricing is based on the output video duration, not the input.


Prompting tips

Global edits: describe the overall change you want applied to the whole clip.

`"Recolor the sky to a deep purple sunset."`
`"Transform the scene to look like it was shot in winter — snow on the ground, frosted breath."`
`"Apply a cinematic noir grade: high contrast, desaturated, blue shadows."`

Local edits: be specific about what to change and where.

`"Replace the jacket the person is wearing with a red leather jacket."`
`"Swap the coffee cup on the table with a glass of wine."`

Reference image edits: use `@Image1`, `@Image2`, etc. to refer to uploaded reference images.

`"Replace the character's face with @Image1, preserving all motion and expression."`
`"Apply the visual style of @Image1 to the scene lighting and color palette."`


Quickstart

Install

JavaScript:

bash
npm install @fal-ai/client

Python:

bash
pip install fal-client
Set your API key
bash
export FAL_KEY="YOUR_API_KEY"
Submit a request

JavaScript:

js
import { fal } from "@fal-ai/client";

const result = await fal.subscribe("alibaba/happy-horse/video-edit", {
  input: {
    video_url: "https://example.com/your-video.mp4",
    prompt: "Recolor the sky to a deep purple sunset.",
    resolution: "1080p",
    audio_setting: "auto",
  },
  logs: true,
  onQueueUpdate: (update) => {
    if (update.status === "IN_PROGRESS") {
      update.logs.map((log) => log.message).forEach(console.log);
    }
  },
});

console.log(result.data.video.url);

Python:

python
import fal_client

def on_queue_update(update):
    if isinstance(update, fal_client.InProgress):
        for log in update.logs:
            print(log["message"])

result = fal_client.subscribe(
    "alibaba/happy-horse/video-edit",
    arguments={
        "video_url": "https://example.com/your-video.mp4",
        "prompt": "Recolor the sky to a deep purple sunset.",
        "resolution": "1080p",
        "audio_setting": "auto",
    },
    with_logs=True,
    on_queue_update=on_queue_update,
)

print(result["video"]["url"])
With reference images

JavaScript:

js
import { fal } from "@fal-ai/client";

const result = await fal.subscribe("alibaba/happy-horse/video-edit", {
  input: {
    video_url: "https://example.com/your-video.mp4",
    prompt: "Replace the character's outfit with the style shown in @Image1.",
    reference_image_urls: [
      "https://example.com/outfit-reference.jpg",
    ],
    resolution: "1080p",
    audio_setting: "origin",
  },
  logs: true,
  onQueueUpdate: (update) => {
    if (update.status === "IN_PROGRESS") {
      update.logs.map((log) => log.message).forEach(console.log);
    }
  },
});

console.log(result.data.video.url);

Python:

python
import fal_client

def on_queue_update(update):
    if isinstance(update, fal_client.InProgress):
        for log in update.logs:
            print(log["message"])

result = fal_client.subscribe(
    "alibaba/happy-horse/video-edit",
    arguments={
        "video_url": "https://example.com/your-video.mp4",
        "prompt": "Replace the character's outfit with the style shown in @Image1.",
        "reference_image_urls": [
            "https://example.com/outfit-reference.jpg",
        ],
        "resolution": "1080p",
        "audio_setting": "origin",
    },
    with_logs=True,
    on_queue_update=on_queue_update,
)

print(result["video"]["url"])

Note: Reference images must be publicly accessible URLs. Use `fal.storage.upload()` (JS) or `fal_client.upload_file()` (Python) to upload local files first.


Input parameters

ParameterTypeDefaultDescription
`video_url`stringrequiredSource video to edit. MP4 or MOV, H.264 recommended. Max 100 MB, 3–60 s, frame rate > 8 fps.
`prompt`stringrequiredText description of the desired edit. Reference images with `@Image1``@Image5`. Max 2,500 characters.
`reference_image_urls`list<string>Up to 5 images to guide the edit. JPEG, PNG, or WEBP. Min 300px, max 10 MB each, aspect ratio 1:2.5–2.5:1.
`resolution``"720p"` | `"1080p"``"1080p"`Output video resolution.
`audio_setting``"auto"` | `"origin"``"auto"``"auto"`: model decides whether to regenerate audio. `"origin"`: preserve the original audio track from the input.
`seed`integer (0–2,147,483,647)Set for reproducible outputs.
`enable_safety_checker`boolean`true`Content moderation on input and output.

Output

json
{
  "video": {
    "url": "https://...",
    "content_type": "video/mp4",
    "file_name": "output.mp4",
    "file_size": 4404019,
    "width": 1920,
    "height": 1080,
    "fps": 24,
    "duration": 5.0,
    "num_frames": 120
  },
  "seed": 1234567
}

The output preserves the source aspect ratio. Duration matches the input, capped at 15 seconds.


Queue API (long-running requests)

Video editing can take longer than generation. Use the queue API to avoid blocking.

JavaScript:

js
import { fal } from "@fal-ai/client";

// Submit
const { request_id } = await fal.queue.submit("alibaba/happy-horse/video-edit", {
  input: {
    video_url: "https://example.com/your-video.mp4",
    prompt: "Transform the scene to winter: snow on the ground, frosted breath, cold blue light.",
    resolution: "1080p",
    audio_setting: "origin",
  },
  webhookUrl: "https://your-server.com/webhook",
});

// Poll status
const status = await fal.queue.status("alibaba/happy-horse/video-edit", {
  requestId: request_id,
  logs: true,
});

// Fetch result once complete
const result = await fal.queue.result("alibaba/happy-horse/video-edit", {
  requestId: request_id,
});

console.log(result.data.video.url);

Python:

python
import fal_client

# Submit
handler = fal_client.submit(
    "alibaba/happy-horse/video-edit",
    arguments={
        "video_url": "https://example.com/your-video.mp4",
        "prompt": "Transform the scene to winter: snow on the ground, frosted breath, cold blue light.",
        "resolution": "1080p",
        "audio_setting": "origin",
    },
    webhook_url="https://your-server.com/webhook",
)

request_id = handler.request_id

# Poll status
status = fal_client.status("alibaba/happy-horse/video-edit", request_id, with_logs=True)

# Fetch result once complete
result = fal_client.result("alibaba/happy-horse/video-edit", request_id)

print(result["video"]["url"])

Uploading files

If your source video or reference images aren't already hosted, upload them before submitting.

JavaScript:

js
import { fal } from "@fal-ai/client";

const videoFile = new File([videoBuffer], "source.mp4", { type: "video/mp4" });
const videoUrl = await fal.storage.upload(videoFile);

const imageFile = new File([imageBuffer], "reference.jpg", { type: "image/jpeg" });
const imageUrl = await fal.storage.upload(imageFile);

Python:

python
import fal_client

video_url = fal_client.upload_file("path/to/source.mp4")
image_url = fal_client.upload_file("path/to/reference.jpg")

Client-side usage

Security: Never expose your `FAL_KEY` in browser or mobile code. Route requests through a server-side proxy: set `FAL_KEY` as a server environment variable and have your frontend call your own backend endpoint, which forwards the request to fal.


ModelUse case
`alibaba/happy-horse/text-to-video`Generate video from a text prompt
`alibaba/happy-horse/image-to-video`Animate a still image as the first frame
`alibaba/happy-horse/reference-to-video`Generate video with subject consistency from 1–9 reference images