All Products
Search
Document Center

Alibaba Cloud Model Studio:EMO video generation API reference

Last Updated:Mar 15, 2026

Generate animated face videos from portrait images and voice audio. Submit an image and audio file to receive a video with the face animated to match the speech.

Important

This API applies only to the China (Beijing) region. Use an API key from the China (Beijing) region.

How it works

The EMO API uses a two-step asynchronous workflow:

  1. Create a task -- Submit a portrait image and audio file. Receive a task_id immediately.

  2. Query the result -- Poll the task status with the task_id. When the status reaches SUCCEEDED, download the generated video.

Video generation takes several minutes. Task IDs are valid for 24 hours after creation.

Performance showcase

Sample input Sample output
Portrait: Portrait sample Voice audio: (sample audio) Sample output video Action style strength: style_level set to active.

For more examples, see Performance showcase.

Note

Ensure uploaded images and audio files are legally compliant and you have the necessary permissions for their use.

Prerequisites

  1. Activate the model service, create an API key, and export it as an environment variable.

  2. Process the input image with the EMO image detection API to get face area (face_bbox) and dynamic area (ext_bbox) coordinates. Both are required parameters.

Step 1: Create a task

Submit the portrait image and audio file to create a video generation task. Receive a task_id for Step 2.

Endpoint

POST https://dashscope.aliyuncs.com/api/v1/services/aigc/image2video/video-synthesis
Note

Task IDs are valid for 24 hours after creation.

Request headers

Header Type Required Description
X-DashScope-Async string Required Asynchronous processing mode. Set to enable. HTTP requests support only asynchronous processing. Without this header, requests fail with "current user api does not support synchronous calls".
Authorization string Required Authentication credential in format Bearer {API_KEY} using a Model Studio API key. Example: Bearer sk-xxxx.
Content-Type string Required Request content type. Set to application/json.

Request body

Parameter Type Required Description
model string Required Model name. Set to emo-v1.
input object Required Input data containing the image, audio, and bounding box coordinates. See Input parameters.
parameters object Optional Generation settings. See Parameters object.

Input parameters

Parameter Type Required Description
image_url string Required Portrait image URL. The model crops the image using ext_bbox. The cropped area's aspect ratio determines the output video resolution. See Image requirements.
audio_url string Required Voice audio file URL for EMO model inference. See Audio requirements.
face_bbox array Required Face area bounding box coordinates in format [x1, y1, x2, y2] (top-left and bottom-right corners). Obtain these from the face_bbox field in the EMO image detection API response. Example: [302, 286, 610, 593].
ext_bbox array Required Dynamic area bounding box coordinates in format [x1, y1, x2, y2] (top-left and bottom-right corners). Aspect ratio must be 1:1 or 3:4. Obtain these from the ext_bbox field in the EMO image detection API response. Example: [71, 9, 840, 778].
The coordinate origin (0,0) is at the top-left corner of the image. The x-axis extends right and the y-axis extends downward.

Parameters object

Parameter Type Required Default Description
style_level string Optional normal Controls the character's motion amplitude. Allowed values: normal (moderate motion), calm (calm motion), active (active motion).

Image requirements

  • The aspect ratio of ext_bbox determines the output video dimensions:

    • 1:1 aspect ratio produces a 512 x 512 profile picture video.

    • 3:4 aspect ratio produces a 512 x 704 half-body portrait video.

  • Minimum side length: 400 pixels.

  • Maximum side length: 7,000 pixels.

  • Supported formats: JPG, JPEG, PNG, BMP, and WebP.

  • The image must be an HTTP or HTTPS URL. Local file paths are not supported.

Audio requirements

  • Audio must contain clear human voice. For best results, remove background noise and music.

  • Maximum file size: 15 MB.

  • Maximum duration: 60 seconds.

  • Supported formats: WAV and MP3.

  • The audio must be an HTTP or HTTPS URL. Local file paths are not supported.

Request examples

curl --location 'https://dashscope.aliyuncs.com/api/v1/services/aigc/image2video/video-synthesis' \
--header 'X-DashScope-Async: enable' \
--header "Authorization: Bearer $DASHSCOPE_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
    "model": "emo-v1",
    "input": {
        "image_url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20251225/onmomb/emo.png",
        "audio_url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250825/aejgyj/input_audio.mp3",
        "face_bbox":[302,286,610,593],
        "ext_bbox":[71,9,840,778]
        },
    "parameters": {
        "style_level": "normal"
        }
    }'
import requests
import os

# 1. Get the API key from an environment variable.
api_key = os.getenv("DASHSCOPE_API_KEY")

# 2. Prepare the request.
url = 'https://dashscope.aliyuncs.com/api/v1/services/aigc/image2video/video-synthesis'

headers = {
    'X-DashScope-Async': 'enable',
    'Authorization': f'Bearer {api_key}',
}

payload = {
    "model": "emo-v1",
    "input": {
        "image_url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20251225/onmomb/emo.png",
        "audio_url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250825/aejgyj/input_audio.mp3",
        "face_bbox": [302, 286, 610, 593],
        "ext_bbox": [71, 9, 840, 778]
    },
    "parameters": {
        "style_level": "normal"
    }
}

# 3. Send the POST request.
response = requests.post(url, headers=headers, json=payload)

# 4. Print the response.
print(response.json())
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;
/**
 * Requirements:
 * - Java 8 or later.
 * - The DASHSCOPE_API_KEY environment variable must be set at runtime.
 **/
public class DashScopeApiDemo {

    public static void main(String[] args) throws IOException {
        // 1. Get the API key from an environment variable.
        String apiKey = System.getenv("DASHSCOPE_API_KEY");
        // 2. Prepare the request.
        String urlString = "https://dashscope.aliyuncs.com/api/v1/services/aigc/image2video/video-synthesis";
        String payload = "{"
                + "\"model\": \"emo-v1\","
                + "\"input\": {"
                +     "\"image_url\": \"https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20251225/onmomb/emo.png\","
                +     "\"audio_url\": \"https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250825/aejgyj/input_audio.mp3\","
                +     "\"face_bbox\": [302, 286, 610, 593],"
                +     "\"ext_bbox\": [71, 9, 840, 778]"
                + "},"
                + "\"parameters\": {"
                +     "\"style_level\": \"normal\""
                + "}"
                + "}";
        // 3. Send the POST request.
        URL url = new URL(urlString);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Authorization", "Bearer " + apiKey);
        connection.setRequestProperty("X-DashScope-Async", "enable");
        connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
        connection.setRequestProperty("Accept", "application/json");
        connection.setDoOutput(true);
        try (OutputStream os = connection.getOutputStream()) {
            byte[] input = payload.getBytes(StandardCharsets.UTF_8);
            os.write(input, 0, input.length);
        }
        // 4. Get and print the server response.
        int statusCode = connection.getResponseCode();
        System.out.println("Status Code: " + statusCode);
        InputStream inputStream = (statusCode >= 200 && statusCode < 300)
                ? connection.getInputStream()
                : connection.getErrorStream();
        String responseBody;
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
            responseBody = reader.lines().collect(Collectors.joining("\n"));
        }
        System.out.println("Response Body: " + responseBody);
        connection.disconnect();
    }
}
// The node-fetch package is required.
// npm install node-fetch@2

const fetch = require('node-fetch');
// 1. Get the API key from an environment variable.
const apiKey = process.env.DASHSCOPE_API_KEY;
// 2. Prepare the request.
const url = 'https://dashscope.aliyuncs.com/api/v1/services/aigc/image2video/video-synthesis';

const headers = {
    'X-DashScope-Async': 'enable',
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
};

const payload = {
    "model": "emo-v1",
    "input": {
        "image_url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20251225/onmomb/emo.png",
        "audio_url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250825/aejgyj/input_audio.mp3",
        "face_bbox": [302, 286, 610, 593],
        "ext_bbox": [71, 9, 840, 778]
    },
    "parameters": {
        "style_level": "normal"
    }
};

// 3. Send a POST request and process the response.
fetch(url, {
    method: 'POST',
    headers: headers,
    body: JSON.stringify(payload)
})
.then(response => response.json())
.then(data => {
    // 4. Print the JSON data returned by the server.
    console.log(data);
});

Response parameters

Parameter Type Description
output object Task output information.
output.task_id string ID of the asynchronous task. Use this ID in Step 2 to query the result. Example: a8532587-fa8c-4ef8-82be-xxxxxx.
output.task_status string Task status after submission. Value: PENDING.
request_id string Unique request ID for tracing and troubleshooting.
code string Error code. Returned only when the request fails. See Error codes.
message string Error message. Returned only when the request fails. See Error codes.

Response examples

Sample success response

{
    "output": {
        "task_id": "a8532587-fa8c-4ef8-82be-xxxxxx",
        "task_status": "PENDING"
    },
    "request_id": "7574ee8f-38a3-4b1e-9280-11c33ab46e51"
}

Sample error response

{
    "code": "InvalidParameter",
    "message": "The specified parameter is not valid.",
    "request_id": "4909100c-7b5a-9f92-bfe5-xxxxxx"
}

Step 2: Query the result

Use the task_id from Step 1 to poll the task status and retrieve the generated video.

Endpoint

GET https://dashscope.aliyuncs.com/api/v1/tasks/{task_id}

Replace {task_id} with the task ID from Step 1.

Important notes

  • task_id validity: Task IDs are valid for 24 hours after creation. After expiration, API returns status UNKNOWN.

  • Task status flow: PENDINGRUNNINGSUCCEEDED or FAILED.

  • Polling: Video generation takes several minutes. Query API limit: 20 QPS. Poll every 15 seconds or longer.

  • video_url validity: Video URLs are valid for 24 hours after task success. Download and transfer to permanent storage (e.g., What is OSS?) immediately.

Request headers

Header Type Required Description
Authorization string Required Authentication credential in format Bearer {API_KEY} using a Model Studio API key. Example: Bearer sk-xxxx.

URL path parameters

Parameter Type Required Description
task_id string Required Task ID from Step 1. Example: a8532587-fa8c-4ef8-82be-xxxxxx.

Request examples

curl -X GET \
--header "Authorization: Bearer $DASHSCOPE_API_KEY" \
https://dashscope.aliyuncs.com/api/v1/tasks/{task_id}
import requests
import os

# 1. Get the API key from the environment variable.
api_key = os.getenv("DASHSCOPE_API_KEY")

# 2. Replace this with the actual task ID.
task_id = "a8532587-fa8c-4ef8-82be-xxxxxx"

# 3. Prepare the request.
url = f"https://dashscope.aliyuncs.com/api/v1/tasks/{task_id}"

headers = {
    'Authorization': f'Bearer {api_key}'
}

# 4. Send a GET request.
response = requests.get(url, headers=headers)

# 5. Print the response.
print(response.json())
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;
/**
 * Requirements:
 * - Java 8 or later.
 * - The DASHSCOPE_API_KEY environment variable must be set at runtime.
 **/
public class TaskStatusChecker {

    public static void main(String[] args) throws IOException {
        // 1. Get the API key from the environment variable.
        String apiKey = System.getenv("DASHSCOPE_API_KEY");
        // 2. Replace this with the actual task ID.
        String taskId = "a8532587-fa8c-4ef8-82be-xxxxxx";
        // 3. Prepare the request.
        String urlString = "https://dashscope.aliyuncs.com/api/v1/tasks/" + taskId;
        // 4. Create a connection and send a GET request.
        URL url = new URL(urlString);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setRequestProperty("Authorization", "Bearer " + apiKey);
        // 5. Get and print the server response.
        int statusCode = connection.getResponseCode();
        System.out.println("Status Code: " + statusCode);
        InputStream inputStream = (statusCode >= 200 && statusCode < 300)
                ? connection.getInputStream()
                : connection.getErrorStream();
        String responseBody;
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
            responseBody = reader.lines().collect(Collectors.joining("\n"));
        }
        System.out.println("Response Body: " + responseBody);
        connection.disconnect();
    }
}
// The node-fetch package is required.
// npm install node-fetch@2

const fetch = require('node-fetch');
// 1. Get the API key from the environment variable.
const apiKey = process.env.DASHSCOPE_API_KEY;
// 2. Replace this with the actual task ID.
const taskId = "a8532587-fa8c-4ef8-82be-xxxxxx";
// 3. Prepare the request.
const url = `https://dashscope.aliyuncs.com/api/v1/tasks/${taskId}`;

const headers = {
    'Authorization': `Bearer ${apiKey}`
};

// 4. Send a GET request.
fetch(url, {
    headers: headers
})
.then(response => response.json())
.then(data => {
    // 5. Print the response.
    console.log(data);
});

Response parameters

Parameter Type Description
request_id string Unique request ID for tracing and troubleshooting.
output object Task output information.
output.task_id string ID of the queried task. Example: a8532587-fa8c-4ef8-82be-xxxxxx.
output.task_status string Current task status. See Response examples.
output.submit_time string Time when the task was submitted (UTC+8). Example: 2025-09-11 14:33:38.716.
output.scheduled_time string Time when the task was scheduled to start (UTC+8). Example: 2025-09-11 14:33:53.089.
output.end_time string Time when the task finished (UTC+8). Example: 2025-09-11 14:35:51.541.
output.results object Task execution result. Present when task_status is SUCCEEDED.
output.results.video_url string Generated video URL, valid for 24 hours after task completion. Download and save promptly. Example: http://dashscope-result-sh.oss-cn-shanghai.aliyuncs.com/xxx.mp4?Expires=xxxx.
output.code string Error code. Present when task_status is FAILED. See Error codes.
output.message string Error message. Present when task_status is FAILED. See Error codes.
usage object Resource usage information. Present when task_status is SUCCEEDED.
usage.video_duration float Duration of the generated video, in seconds. Example: 13.93.
usage.video_ratio string Aspect ratio of the generated video. Value: 1:1 or 3:4.

Task status values

Status Description
PENDING Task is queued, waiting to be processed.
RUNNING Task is being processed.
SUCCEEDED Task completed successfully. video_url is available in the response.
FAILED Task failed. Check output.code and output.message for details.
CANCELED Task was canceled.
UNKNOWN Task does not exist or status cannot be determined. Returned when the task_id has expired (after 24 hours).

Response examples

Sample success response

{
    "request_id": "8190395f-ca1b-4703-9656-xxxxxx",
    "output": {
        "task_id": "a8532587-fa8c-4ef8-82be-xxxxxx",
        "task_status": "SUCCEEDED",
        "submit_time": "2025-09-11 14:33:38.716",
        "scheduled_time": "2025-09-11 14:33:53.089",
        "end_time": "2025-09-11 14:35:51.541",
        "results": {
            "video_url": "http://dashscope-result-sh.oss-cn-shanghai.aliyuncs.com/xxx.mp4?Expires=xxxx"
        }
    },
    "usage": {
        "video_duration": 13.93,
        "video_ratio": "1:1"
    }
}

Sample error response

{
    "output": {
        "task_id": "a8532587-fa8c-4ef8-82be-xxxxxx",
        "task_status": "FAILED",
        "code": "InvalidURL",
        "message": "Required URL is missing or invalid, please check the request URL."
    },
    "request_id": "4d687387-580a-4b49-a1f8-4691289e09a3"
}

Billing and rate limits

Pricing

emo-v1 uses pay-as-you-go billing based on generated video duration.

Aspect ratio Resolution Unit price
1:1 512 x 512 USD 0.011469 per second
3:4 512 x 704 USD 0.022937 per second

Cost examples:

  • A 10-second video at 1:1 aspect ratio costs approximately USD 0.11.

  • A 30-second video at 3:4 aspect ratio costs approximately USD 0.69.

Rate limits

Limit type Value
Task submission QPS 5
Concurrent tasks 1 (excess tasks queued)
Task query QPS 20

Error codes

For common error codes and status codes, see Error messages.