MiniMax Reference to Video + Audio (ref2va)
1-3 reference images, a tone/style reference audio, and a prompt in — a generated video clip with its own soundtrack out. Test it live with your own API key, or read how it works.
API key
Enter your API key to submit or inspect tasks.
Create a task
Fields map directly onto POST /aigc/task with task_type: "minimax_ref2va".
Or inspect an existing task
Request log
Every call this page makes to the API, in order, most recent first.
Nothing sent yet.
Overview
MiniMax Reference to Video + Audio (minimax_ref2va) generates a video clip driven by 1-3 reference images and a reference audio track, plus a prompt. The reference audio is a tone/style hint, not the final soundtrack — the model generates its own soundtrack for the result. It's a single call — you get a task_id back immediately and the clip is typically ready in a little over a minute.
Basic configuration
| Setting | Value |
|---|---|
| Base URL | https://api.foxaihub.com/api/v2 |
| Auth header | api-key: YOUR_API_KEY |
| task_type | minimax_ref2va |
Warning: The header is api-key, not api_key. Any account with a balance greater than $0 can submit — there is no separate minimum-balance gate like the Music Video pipeline has.
Endpoints at a glance
| Endpoint | Purpose |
|---|---|
| POST /aigc/task | Submit a reference-images + reference-audio to video task |
| POST /aigc/task/wait | Submit and block until the task finishes (or times out) |
| GET /aigc/task?ids= | Read the status and result of one or more tasks |
Note: This is not lip sync: the reference audio only steers tone and style, and the mouth movements in the result are not synced to it. If you want a character's mouth to follow an audio track exactly, use minimax_ia2v (Lip Sync Video) instead.
Parameters & constraints
All parameters go in the params object of the create call. Every one of them is validated before you are charged — an invalid value returns 400 with no deduction.
| Field | Type | Required | Constraint |
|---|---|---|---|
| reference_images | array of string (URL) | yes | 1-3 publicly downloadable http(s) URLs — base64 is not accepted. The first is the primary reference |
| audio | string (URL or base64) | yes | Public http(s) URL, or a base64 Data URL up to 30MB. A tone/style reference — see below |
| prompt | string | yes | Describes the scene and action; also describes the sound you want generated |
| resolution | string | yes | "768p" or "1080p" |
| aspect_ratio | string | yes | One of "1:1", "4:3", "3:4", "16:9", "9:16" |
| duration | integer (seconds) | yes | 3–15 |
Note: The actual pixel size is looked up server-side from resolution + aspect_ratio. At 768p: 1:1 = 768x768, 4:3 = 1024x768, 3:4 = 768x1024, 16:9 = 1344x768, 9:16 = 768x1344. At 1080p the same five ratios scale to 1088x1088, 1440x1088, 1088x1440, 1920x1088, and 1088x1920.
The reference audio is not the final soundtrack
- audio only steers tone and style (e.g. calm vs energetic, acoustic vs electronic) — the model generates a brand new soundtrack for the result, it does not reuse or extend your file.
- It is not lip sync. Mouth movements in the result are not synchronized to this track. Use minimax_ia2v if you need that.
- We read the first duration seconds out of the reference track, the same cropping rule as minimax_ia2v uses for its (different, final) audio field.
Sending the reference audio: URL or inline upload
If your track is already hosted somewhere public, pass the URL — nothing gets copied and repeat requests against the same URL are free. If it is only on your machine, send it inline instead: put the whole file in params.audio as a base64 Data URL (up to 30MB decoded) and we store it on our CDN, rewrite params.audio to the resulting URL, and queue the task with that. The playground's Upload tab does exactly this. Note that reference_images have no inline form — every URL in the array must be public.
{
"task_type": "minimax_ref2va",
"params": {
"reference_images": ["https://example.com/character.jpg"],
"audio": "data:audio/mpeg;base64,SUQzBAAAAAA...",
"duration": 5
}
}
Why duration must be a whole number of seconds
Generation runs at 24 frames per second, and the frame count is computed as duration x 24 + 1, for both the video and the generated audio track. A fractional duration would misalign the two, so only integers from 3 to 15 are accepted.
API reference
POST /aigc/task
Submit a reference-images + reference-audio to video task. Charged immediately at submit time.
Parameters
| Field | Type | Required | Notes |
|---|---|---|---|
task_type |
string | Yes | Must be "minimax_ref2va" |
params.reference_images |
array of string (URL) | Yes | 1-3 publicly downloadable http(s) URLs |
params.audio |
string (URL or base64) | Yes | Public http(s) URL, or a base64 Data URL up to 30MB — tone/style reference, not the final soundtrack |
params.prompt |
string | Yes | Scene / action / sound description |
params.resolution |
string | Yes | "768p" or "1080p" |
params.aspect_ratio |
string | Yes | "1:1" / "4:3" / "3:4" / "16:9" / "9:16" |
params.duration |
integer | Yes | 3-15 seconds |
Request Body
{
"task_type": "minimax_ref2va",
"params": {
"reference_images": [
"https://example.com/character-front.jpg",
"https://example.com/character-side.jpg"
],
"audio": "https://common.foxai.me/sample_music/jp2.mp3",
"prompt": "the character walks forward confidently, cinematic lighting",
"resolution": "768p",
"aspect_ratio": "9:16",
"duration": 5
}
}
Response
{ "success": true, "task_id": "a42e2c77-ded8-48aa-8aa4-dfd9daa43801" }
Errors
| Status | When | Body |
|---|---|---|
400 |
A param fails validation (bad resolution/aspect_ratio, duration out of range, empty or >3 reference_images, audio that is neither a URL nor decodable base64) | {"success":false,"error":"Invalid params for minimax_ref2va: reference_images: Array must contain at most 3 element(s)"} |
400 |
task_type is unknown or disabled | {"success":false,"error":"Unsupported task type: minimax_ref2va"} |
401 |
Missing/unknown api-key, or balance is 0 | {"message":"Unauthorized"} |
402 |
The deduction itself failed (insufficient balance) | {"success":false,"error":"Insufficient balance"} |
413 |
The request body is too large — an inline audio upload over 30MB | {"success":false,"error":"Request body exceeds 42008576 bytes"} |
500 |
Pricing configuration for this task_type is invalid | {"success":false,"error":"Invalid price configuration for task type: minimax_ref2va"} |
POST /aigc/task/wait
Same as POST /aigc/task, but blocks the HTTP response until the task reaches a terminal state or wait_timeout elapses. Convenient for scripts that don't want to poll.
Parameters
| Field | Type | Required | Notes |
|---|---|---|---|
task_type |
string | Yes | "minimax_ref2va" |
params |
object | Yes | Same shape as above |
wait_timeout |
integer (seconds) | No | 1-600, default 60 |
Request Body
{
"task_type": "minimax_ref2va",
"params": {
"reference_images": ["https://example.com/character-front.jpg"],
"audio": "https://common.foxai.me/sample_music/jp2.mp3",
"prompt": "the character walks forward confidently, cinematic lighting",
"resolution": "768p",
"aspect_ratio": "9:16",
"duration": 5
},
"wait_timeout": 120
}
Response
The full task object (same shape as GET /aigc/task) once it reaches completed or failed.
Errors
| Status | When | Body |
|---|---|---|
408 |
The task is still running when wait_timeout elapses | {"success":false,"task_id":"...","status":"processing","message":"Task wait timeout after 60s"} |
400 / 401 / 402 / 500 |
Same as POST /aigc/task | See above |
GET /aigc/task?ids=
Read one or more tasks by id. Free. Response is a bare array, not an object.
Parameters
| Field | Type | Required | Notes |
|---|---|---|---|
ids |
string | Yes | Comma-separated task ids, up to 25 at once |
Response
[ { "task_id": "...", "task_type": "minimax_ref2va", "status": "completed", "params": {...}, "data": ["https://cdn.../result.mp4"], "created_at": "...", "queue_time_sec": 4, "generation_time_sec": 58 } ]
Errors
| Status | When | Body |
|---|---|---|
400 |
ids is missing, or more than 25 ids were requested | {"error":"Task IDs required"} |
401 |
Missing or unknown api-key | {"message":"Unauthorized"} |
Webhook
There are two ways to track video task progress: poll GET /aigc/task?ids= (or use POST /aigc/task/wait for short scripts), or configure a webhook. We recommend webhooks in production — your server is pushed whenever a task completes or fails instead of holding connections open or polling constantly.
Note: A webhook is configured in your Dashboard (one URL per account), not per task — configure it once and all AIGC tasks (including minimax_ref2va) will be pushed to your endpoint upon completion or failure.
Delivery format
Every delivery is a POST with a standard envelope:
{
"event": "task.completed",
"type": "minimax_ref2va",
"delivery_id": "9f2c1a3e-abcd-4d11-8f00-0123456789ab",
"created_at": "2026-09-22T09:31:02.000Z",
"data": {
"task_id": "a42e2c77-ded8-48aa-8aa4-dfd9daa43801",
"task_type": "minimax_ref2va",
"status": "completed",
"params": {
"reference_images": ["https://example.com/character.jpg"],
"audio": "https://example.com/reference.mp3",
"prompt": "the character walks forward confidently, cinematic lighting",
"resolution": "768p",
"aspect_ratio": "9:16",
"duration": 5
},
"data": ["https://cdn.../result.mp4"],
"created_at": "2026-09-22T09:30:10.000Z",
"queue_time_sec": 4,
"generation_time_sec": 58
}
}
| Header | Value |
|---|---|
| Content-Type | application/json |
| User-Agent | FoxAI-Webhook/1 |
| X-Webhook-Event | Same as event in the body (task.completed or task.failed) |
| X-Webhook-Type | Same as type in the body |
| X-Webhook-Delivery | Same as delivery_id in the body |
| X-Webhook-Timestamp | Unix seconds at delivery time |
Result type
Since one URL receives every product on your account, event tells you what happened and type tells you which kind of result it is. type always matches the task_type you passed when creating the task, so you can dispatch on it directly:
| type | Result |
|---|---|
| minimax_ref2va | Reference-to-video-plus-audio task reached a terminal state |
| minimax_t2va | Text-to-video-plus-audio task reached a terminal state |
| minimax_i2v | Image-to-video task reached a terminal state |
| minimax_ia2v | Lip-sync (image + audio to video) task reached a terminal state |
| mv | Music video pipeline event |
| ping | Test delivery triggered from the Dashboard |
Events
| Webhook event | Trigger condition | data contents |
|---|---|---|
| task.completed | Reference-to-video task successfully finished | Full task object with generated video URL in data array |
| task.failed | Task failed (charge refunded automatically) | Task object with error details |
Retry policy
- 10 second timeout per attempt.
- Retries at 5s, 10s, 20s — up to 4 attempts total, wrapping up within ~35 seconds.
- Only retried on network errors, timeouts, HTTP 408, 429 and 5xx. Non-retryable 4xx codes are not retried.
- The same delivery keeps the same X-Webhook-Delivery (delivery_id) across retries — use it to deduplicate.
Security
Warning: Add a long random path segment or token query parameter to your webhook URL. Always treat an incoming webhook as a notification signal and confirm with GET /aigc/task?ids= when processing critical business logic.
Limits & lifecycle
Task lifecycle
A task only ever has four states, and it only moves forward:
pending -> processing -> completed
-> failed
| Status | Meaning |
|---|---|
| pending | Accepted, waiting for a GPU worker to pick it up |
| processing | A worker is running the generation |
| completed | data holds the result — an array with the video URL as its first element |
| failed | Something went wrong (including a bad reference URL); the charge was refunded automatically |
There is no fixed SLA — poll GET /aigc/task?ids= or use POST /aigc/task/wait rather than assuming a fixed time.
Queue time and generation time
The task object carries two timing fields, both in seconds. queue_time_sec is the time from creation (created_at) until the task was first picked up by a worker (entered processing) — how long it waited in the queue. generation_time_sec is the time from that first pickup until it reached completed or failed — how long the actual generation took. Both are null before the corresponding milestone happens.
Note: minimax_ref2va actually runs as a two-stage pipeline internally (a draft stage produces a latent and a generated soundtrack, then a refine stage turns them into the final clip, passing through an internal streaming state that is never exposed to you). generation_time_sec spans the whole thing — first pickup to final completed/failed.
Retries and timeouts
A worker that claims a task but stops responding is reclaimed and retried, up to 3 attempts total. If every attempt is exhausted the task is marked failed and the charge is refunded — you don't need to build your own timeout-and-refund logic.
Task visibility
Warning: GET /aigc/task does not check ownership — anyone who has a task_id can read its status and result with any valid api-key. Treat a task_id as semi-sensitive if the prompt, references, or result is private, and don't expose it in a public URL.
Webhooks instead of polling
See the Webhook section above for the full configuration endpoints, delivery format and retry policy.
Client database schema
If you are storing task states in your own backend (e.g. MySQL / PostgreSQL), here is the recommended table schema:
Tasks table
CREATE TABLE aigc_tasks (
task_id CHAR(36) NOT NULL PRIMARY KEY,
task_type VARCHAR(32) NOT NULL,
status VARCHAR(20) NOT NULL,
params JSON NOT NULL,
data JSON NULL,
created_at DATETIME(3) NULL,
synced_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
CONSTRAINT chk_aigc_tasks_status CHECK (status IN ('pending', 'processing', 'completed', 'failed'))
) ENGINE=InnoDB;
CREATE INDEX idx_aigc_tasks_status ON aigc_tasks (status);
CREATE INDEX idx_aigc_tasks_task_type ON aigc_tasks (task_type);
Webhook deduplication table
Pair this table with INSERT IGNORE or ON DUPLICATE KEY UPDATE so retried webhook deliveries are never processed twice:
CREATE TABLE webhook_deliveries (
delivery_id CHAR(36) NOT NULL PRIMARY KEY,
task_id CHAR(36) NULL,
event VARCHAR(64) NOT NULL,
payload JSON NOT NULL,
received_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
) ENGINE=InnoDB;
CREATE INDEX idx_webhook_deliveries_task_id ON webhook_deliveries (task_id);
Sync strategy
- Insert a row into aigc_tasks as soon as POST /aigc/task returns task_id.
- When a webhook arrives or polling returns updated data, upsert aigc_tasks using task_id as the primary key.
- Extract the resulting video URL from data[0] once status becomes completed.
Billing
minimax_ref2va uses the exact same pricing rule shape as the other MiniMax video models — billed by resolution tier and per second, deducted immediately when you submit. There is no separate reservation/settlement step. If the task fails or times out, the full amount is refunded automatically. The number of reference images you send does not change the price.
Formula
price = unit_price_by_resolution[resolution] x duration
| resolution | Per-second price | Meaning |
|---|---|---|
| 768p | $0.03 | Per-second price at 768p — also the practical minimum charge (duration's minimum is 3s, i.e. $0.09) |
| 1080p | $0.06 | Per-second price at 1080p, independent of aspect_ratio |
Worked examples
| resolution | aspect_ratio | Duration | Calculation | Price |
|---|---|---|---|---|
| 768p | 9:16 (portrait, typical) | 5s | $0.03 x 5 | $0.15 |
| 768p | 16:9 (landscape) | 3s (shortest) | $0.03 x 3 | $0.09 |
| 1080p | 9:16 (portrait) | 15s (longest) | $0.06 x 15 | $0.9 |
Warning: Duration is what you're billed for, not the length of the reference audio you sent. That reference is only a tone/style hint — the actual soundtrack in the result is generated fresh, not extracted from it.
What happens on failure
- The charge happens before the worker starts, at submit time.
- If the task ends in failed — including because a reference image or audio URL couldn't be downloaded — the full amount is refunded automatically.
- A worker that stops responding is retried up to 3 times; if every attempt is exhausted the task is marked failed and refunded the same way.