# Image to Video API — MiniMax Hailuo, Batch, Pay per Second (`sherwood/video-generator-batch`) Actor

Turn images or text prompts into short videos with MiniMax Hailuo and get, for each clip, a dataset item with the video URL and its exact duration. Image to video, text to video, optional last-frame keyframe, batch input, no API key, pay per second of delivered video.

- **URL**: https://apify.com/sherwood/video-generator-batch.md
- **Developed by:** [Sherwood](https://apify.com/sherwood) (community)
- **Categories:** AI, Automation, Developer tools
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $50.00 / 1,000 video second delivereds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Image to Video API — MiniMax Hailuo, batch, pay per second

Turn images or text prompts into short mp4 videos and get, for each clip, a dataset item with the video URL and its exact duration — from $0.05 to $0.06 per second of delivered video depending on your Apify plan (a 5-second clip costs $0.25 to $0.30). Image to video, text to video, optional last-frame keyframe, batch input, no video-model API key to manage, failed clips are free.

### What it does

- **Image to video**: send image URLs, get one animated clip per image. Without a prompt, a neutral motion prompt is used.
- **Text to video**: send prompts alone, get one 16:9 clip per prompt.
- **Both**: `prompts` and `imageUrls` are paired by index; a list of one is reused for every clip.
- **Keyframes**: `endImageUrls` pins the last frame of each clip — first-to-last transitions, or a clip that ends on a given image.
- **Batch by design**: one call for the whole list, one dataset item per clip, in input order.

Images are accepted as public URLs, Google Drive or Dropbox share links, Drive file IDs, base64 or data URIs, files uploaded from your computer, or the dataset of another Actor (`datasetId`) — for example the output of an image generator or a product scraper.

### Input

Every field is optional; with no input the Actor generates one sample clip so you can see the output shape.

```json
{
  "imageUrls": ["https://example.com/product.jpg"],
  "prompts": ["Slow 360 rotation of the product, studio lighting"],
  "duration": 5,
  "resolution": "768P"
}
```

| Field | Type | Notes |
|---|---|---|
| `prompts` | array or string | What happens in each clip. Aliases: `prompt`, `texts`. Newline-separated strings are split. |
| `imageUrls` | array or string | First frame of each clip. Aliases: `imageUrl`, `urls`, `images`, `startUrls`, `imageFiles` (upload). |
| `endImageUrls` | array or string | Last frame of each clip (optional). Alias: `endImageUrl`. |
| `datasetId` | string | Animate the image URLs found in another Actor's dataset; `urlField` picks the field, common ones are auto-detected. |
| `duration` | integer | 1 to 15 seconds per clip, default 5. |
| `resolution` | `768P` / `1080P` / `480P` | All three cost the same per second. |
| `promptExpansion` | `balanced` / `disabled` / `quality` | How much the model rewrites your prompt first. |
| `seed` | integer | Fix it to reproduce a run. |
| `maxVideos` | integer | Hard cap per run, default 20. |

### Output

One dataset item per clip:

```json
{
  "index": 0,
  "prompt": "Slow 360 rotation of the product, studio lighting",
  "imageUrl": "https://example.com/product.jpg",
  "outputUrl": "https://api.apify.com/v2/key-value-stores/.../records/video-0000.mp4",
  "durationSeconds": 5.184,
  "billedSeconds": 5,
  "resolution": "768P",
  "fileSize": 7300000,
  "model": "minimax/h3-max-turbo/image-to-video",
  "format": "mp4",
  "status": "ok",
  "error": null
}
```

`durationSeconds` is read from the delivered file, not assumed. A clip that fails — dead image link, content refused by the safety checker, upstream error — comes back as an item with `"status": "error"` and the reason, costs nothing, and never silently disappears: you always get as many answers as inputs.

### Pricing at the time of writing

- **`video-second`** — one event per second of **delivered** video, rounded to the nearest second. The model can produce slightly more than requested (~5.2 s for 5 s): you are billed on what you receive.
- Per plan: $0.05 (Free), $0.06 (Starter), $0.055 (Scale), $0.05 (Business) per second.
- Failed clips: free. No subscription, no minimum. All resolutions, including 1080P, cost the same.

A 5-second product clip costs $0.25 to $0.30. Set `maxTotalChargeUsd` on the run and the Actor stops cleanly at the limit, telling you which clips remain instead of failing.

### Call it by API

```bash
curl -s -X POST \
  "https://api.apify.com/v2/acts/sherwood~video-generator-batch/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"prompts": ["A paper plane gliding over pastel mountains, flat illustration"]}'
```

Or with the Apify clients:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("sherwood/video-generator-batch").call(run_input={
    "imageUrls": ["https://example.com/product.jpg"],
    "prompts": ["Slow 360 rotation of the product, studio lighting"],
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["status"], item.get("outputUrl") or item.get("error"))
```

### From n8n or an AI agent

- **n8n**: use the official Apify node with Actor `sherwood~video-generator-batch`; the input above goes in the custom body, the results come back as items.
- **MCP**: add the [Apify MCP server](https://mcp.apify.com) to your agent and it can call this Actor like any tool — nothing in the input is required, so "animate these three images" maps onto one call.
- **Chaining**: pass the `datasetId` of a `sherwood/image-generator-batch` or `sherwood/image-upscaler-batch` run to animate its outputs directly.

The Actor is eligible for agentic payments (x402, Skyfire, MPP): an AI agent can run it and pay per request without an Apify account.

### Limits, honestly

- Generation runs on **MiniMax Hailuo (h3-max-turbo) via fal.ai** — this is an AI model, named here on purpose. Its safety checker is always on; this Actor is not a way around model content rules.
- Clips top out at 15 seconds and 1080P. No audio track.
- Input images must be at least 256×256 pixels (smaller ones come back as a free error item; upscale them first, for example with `sherwood/image-upscaler-batch`).
- Output files live in the run's key-value store and follow your Apify account's data retention; copy them out if you need them long-term.
- `seed` applies to the whole run, not per clip.
- If your brief needs a specific aesthetic from another video model, this is not that.

### Related Actors

- [AI Image Generator (FLUX)](https://apify.com/sherwood/image-generator-batch) — generate the images to animate, then pass its `datasetId` here.
- [AI Image Upscaler (SeedVR2)](https://apify.com/sherwood/image-upscaler-batch) — bring small images above the 256×256 floor and sharpen them before animation.
- [Instagram Scraper](https://apify.com/apify/instagram-scraper) and [Google Maps Scraper](https://apify.com/compass/crawler-google-places) — two common sources of image URLs to animate through `datasetId`.

### FAQ

**What is Hailuo AI?**
Hailuo is MiniMax's video generation model family. This Actor runs MiniMax Hailuo (h3-max-turbo) for both image-to-video and text-to-video, and says so openly — you know exactly which model renders your clips.

**How do I turn a photo into a video?**
Put its URL in `imageUrls` (a Drive or Dropbox link, a base64 string or a console upload also works) and optionally describe the motion in `prompts` ("slow zoom on the face", "steam rising from the cup"). One call, one mp4 per photo.

**How much does image-to-video cost?**
$0.05 to $0.06 per second of delivered video depending on your plan — a 5-second clip is $0.25 to $0.30. Failed clips are free, every resolution costs the same, and `maxTotalChargeUsd` caps any run.

**Do I need a MiniMax or fal API key?**
No. No model account, no key to store: the Actor manages the model calls and bills per delivered second through Apify. Direct model APIs also bill the failures; this one does not.

**Is there a free image-to-video API?**
Apify's free plan includes $5 of platform credit each month — enough for roughly 100 seconds of video — with no card required. Good for testing motion prompts before a batch.

**Can I animate product photos in bulk?**
Yes: send the whole list in `imageUrls`, or point `datasetId` at a scraper's or generator's output. Prompts and images are paired by index, and a single prompt is reused for every image — "slow 360 rotation, studio lighting" across a whole catalog is one call.

# Actor input Schema

## `prompts` (type: `array`):

What should happen in each clip, in English for best results. Alone: one text-to-video clip per prompt. With imageUrls: paired by index (a single prompt is reused for every image). One dataset item is returned per clip, with an index matching the input order. Aliases merged into this list: prompt, texts.

## `imageUrls` (type: `array`):

Images to animate, one clip per image, at least 256x256 pixels: public http(s) URLs, Google Drive or Dropbox share links, Drive file IDs, base64 images or data URIs. A newline- or comma-separated string works too. Without a matching prompt, a neutral motion prompt is used. Aliases merged into this list: imageUrl, urls, images, startUrls, imageFiles.

## `endImageUrls` (type: `array`):

Pin the LAST frame of each clip (same accepted sources as imageUrls, paired by index, a single value is reused for every clip). With imageUrls this makes a first-to-last keyframe transition; alone it generates a clip that ends on this image. Alias: endImageUrl.

## `prompt` (type: `string`):

A single prompt, or several prompts in one newline-separated string (one prompt per line). Merged with prompts.

## `texts` (type: `array`):

Alias of prompts.

## `imageUrl` (type: `string`):

A single image, or several in one newline- or comma-separated string. Merged with imageUrls.

## `urls` (type: `array`):

Alias of imageUrls.

## `images` (type: `array`):

Alias of imageUrls.

## `startUrls` (type: `array`):

Alias of imageUrls.

## `imageFiles` (type: `array`):

Images uploaded from your computer, animated like imageUrls.

## `datasetId` (type: `string`):

Animate the image URLs found in the items of an Apify dataset, for example the output of an image generator or a product scraper. Common image fields are detected automatically; set urlField to pick one.

## `urlField` (type: `string`):

Field path(s) holding the image URL in each dataset item, for example images\[].url or outputUrl. Comma-separated paths are tried in order. Leave empty to auto-detect.

## `duration` (type: `integer`):

Length of each clip, 1 to 15 seconds. You are charged per second of delivered video (the model can produce slightly more than requested; you pay the delivered duration, rounded to the nearest second).

## `resolution` (type: `string`):

Output resolution. All three cost the same per second.

## `promptExpansion` (type: `string`):

How much the model rewrites your prompt before generating. balanced is fast and usually better; disabled uses your prompt verbatim; quality spends up to ~30 s writing a richer prompt.

## `seed` (type: `integer`):

Fix the seed to make a clip reproducible. Applied to every clip of the run. Leave empty for a random result each run.

## `maxVideos` (type: `integer`):

Stop after this many clips. Protects against oversized lists. Default 20.

## Actor input object example

```json
{
  "prompts": [
    "A paper plane gliding over pastel mountains, minimal flat illustration style, smooth camera pan"
  ],
  "duration": 5,
  "resolution": "768P",
  "promptExpansion": "balanced",
  "maxVideos": 20
}
```

# Actor output Schema

## `results` (type: `string`):

One item per clip: prompt, imageUrl, outputUrl, durationSeconds, billedSeconds, status and error. Sort by index to match the input order.

## `files` (type: `string`):

The generated mp4 files referenced by outputUrl.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "prompts": [
        "A paper plane gliding over pastel mountains, minimal flat illustration style, smooth camera pan"
    ],
    "duration": 5,
    "resolution": "768P",
    "promptExpansion": "balanced",
    "maxVideos": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("sherwood/video-generator-batch").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "prompts": ["A paper plane gliding over pastel mountains, minimal flat illustration style, smooth camera pan"],
    "duration": 5,
    "resolution": "768P",
    "promptExpansion": "balanced",
    "maxVideos": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("sherwood/video-generator-batch").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "prompts": [
    "A paper plane gliding over pastel mountains, minimal flat illustration style, smooth camera pan"
  ],
  "duration": 5,
  "resolution": "768P",
  "promptExpansion": "balanced",
  "maxVideos": 20
}' |
apify call sherwood/video-generator-batch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sherwood/video-generator-batch"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/rRb3zfKBXlT3hY7FP/builds/A4mTDrhVOqa54qkf3/openapi.json
