alibaba/happy-horse/image-to-video
Input
Hint: Drag and drop image files from your computer, images from web pages, paste from clipboard (Ctrl/Cmd+V), or provide a URL. Accepted file types: jpg, jpeg, png, webp, gif, avif

Customize your input with more control.
Result
What would you like to do next?
For every second of 720p video you generated, you will be charged $0.14/second. For 1080p video you will be charged $0.28/second.
Logs
Run Happy Horse 1.0: Image to Video API
Animate any still image into a 1080p video with synchronized native audio, Foley sounds, and multilingual lip-sync. No GPU management required.
Model ID: `alibaba/happy-horse/image-to-video`
Provider: fal.ai
Commercial rights: Full commercial rights on all outputs
Specifications
| Property | Value |
|---|---|
| Resolution | 720p, 1080p |
| Duration | 3–15 seconds |
| Aspect ratios | 16:9, 9:16, 1:1, 4:3, 3:4 |
| Input image min size | 400px on shortest side (720p+ recommended) |
| Input image max size | 10 MB |
| Input formats | JPEG, JPG, PNG, BMP, WEBP |
| Prompt length | Up to 2,500 characters |
| Lip-sync languages | English, Mandarin, Cantonese, Japanese, Korean, German, French |
Pricing
| Resolution | Price |
|---|---|
| 720p | $0.14 / second |
| 1080p | $0.28 / second |
A 10-second clip at 1080p costs $2.80.
Quickstart
Install
JavaScript:
bashnpm install @fal-ai/client
Python:
bashpip install fal-client
Set your API key
bashexport FAL_KEY="YOUR_API_KEY"
Submit a request
JavaScript:
jsimport { fal } from "@fal-ai/client"; const result = await fal.subscribe("alibaba/happy-horse/image-to-video", { input: { image_url: "https://example.com/your-image.jpg", prompt: "Bring the scene to life with natural motion and sound.", resolution: "1080p", duration: 5, }, 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:
pythonimport 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/image-to-video", arguments={ "image_url": "https://example.com/your-image.jpg", "prompt": "Bring the scene to life with natural motion and sound.", "resolution": "1080p", "duration": 5, }, with_logs=True, on_queue_update=on_queue_update, ) print(result["video"]["url"])
Note: The
`image_url`is used as the first frame. Use a publicly accessible URL, or upload via the client storage helpers below.
Input parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
`image_url` | string | required | First-frame image URL. Min 400px shortest side, max 10 MB. JPEG, PNG, BMP, or WEBP. |
`prompt` | string | — | Text description guiding the animation. Max 2,500 characters. |
`resolution` | `"720p"` | `"1080p"` | `"1080p"` | Output video resolution. |
`duration` | integer (3–15) | `5` | Clip length in seconds. |
`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 }
Queue API (long-running requests)
For clips longer than a few seconds, use the queue API to avoid blocking.
JavaScript:
jsimport { fal } from "@fal-ai/client"; // Submit const { request_id } = await fal.queue.submit("alibaba/happy-horse/image-to-video", { input: { image_url: "https://example.com/your-image.jpg", duration: 15, resolution: "1080p", }, webhookUrl: "https://your-server.com/webhook", }); // Poll status const status = await fal.queue.status("alibaba/happy-horse/image-to-video", { requestId: request_id, logs: true, }); // Fetch result once complete const result = await fal.queue.result("alibaba/happy-horse/image-to-video", { requestId: request_id, }); console.log(result.data.video.url);
Python:
pythonimport fal_client # Submit handler = fal_client.submit( "alibaba/happy-horse/image-to-video", arguments={ "image_url": "https://example.com/your-image.jpg", "duration": 15, "resolution": "1080p", }, webhook_url="https://your-server.com/webhook", ) request_id = handler.request_id # Poll status status = fal_client.status("alibaba/happy-horse/image-to-video", request_id, with_logs=True) # Fetch result once complete result = fal_client.result("alibaba/happy-horse/image-to-video", request_id) print(result["video"]["url"])
Uploading files
If your image isn't already hosted, upload it via the client before submitting.
JavaScript:
jsimport { fal } from "@fal-ai/client"; const file = new File([imageBuffer], "frame.jpg", { type: "image/jpeg" }); const url = await fal.storage.upload(file); // Use `url` as image_url in your request
Python:
pythonimport fal_client url = fal_client.upload_file("path/to/your/image.jpg") # Use `url` as image_url in your request
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.