Skip to content

EMO-EMO video generation API reference

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 inputSample output
Portrait: 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

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

Note

Task IDs are valid for 24 hours after creation.

Request headers

HeaderTypeRequiredDescription
X-DashScope-AsyncstringRequiredAsynchronous 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".
AuthorizationstringRequiredAuthentication credential in format Bearer {API_KEY} using a Model Studio API key. Example: Bearer sk-xxxx.
Content-TypestringRequiredRequest content type. Set to application/json.

Request body

ParameterTypeRequiredDescription
modelstringRequiredModel name. Set to emo-v1.
inputobjectRequiredInput data containing the image, audio, and bounding box coordinates. See Input parameters .
parametersobjectOptionalGeneration settings. See Parameters object .

Input parameters

ParameterTypeRequiredDescription
image_urlstringRequiredPortrait 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_urlstringRequiredVoice audio file URL for EMO model inference. See Audio requirements .
face_bboxarrayRequiredFace 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_bboxarrayRequiredDynamic 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

ParameterTypeRequiredDefaultDescription
style_levelstringOptionalnormalControls 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

HELPCODEESCAPE-curl
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"
        }
    }'

Python

HELPCODEESCAPE-python
import requests
import os


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())

Java

HELPCODEESCAPE-java
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();
    }
}

Node.js

HELPCODEESCAPE-nodejs
// 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

ParameterTypeDescription
outputobjectTask output information.
output.task_idstringID of the asynchronous task. Use this ID in Step 2 to query the result. Example: a8532587-fa8c-4ef8-82be-xxxxxx.
output.task_statusstringTask status after submission. Value: PENDING.
request_idstringUnique request ID for tracing and troubleshooting.
codestringError code. Returned only when the request fails. See Error codes .
messagestringError message. Returned only when the request fails. See Error codes .

Response examples

Sample success response

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

Sample error response

HELPCODEESCAPE-json
{
    "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

HELPCODEESCAPE-http
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

HeaderTypeRequiredDescription
AuthorizationstringRequiredAuthentication credential in format Bearer {API_KEY} using a Model Studio API key. Example: Bearer sk-xxxx.

URL path parameters

ParameterTypeRequiredDescription
task_idstringRequiredTask ID from Step 1. Example: a8532587-fa8c-4ef8-82be-xxxxxx.

Request examples

curl

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

Python

HELPCODEESCAPE-python
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())

Java

HELPCODEESCAPE-java
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();
    }
}

Node.js

HELPCODEESCAPE-nodejs
// 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

ParameterTypeDescription
request_idstringUnique request ID for tracing and troubleshooting.
outputobjectTask output information.
output.task_idstringID of the queried task. Example: a8532587-fa8c-4ef8-82be-xxxxxx.
output.task_statusstringCurrent task status. See Response examples .
output.submit_timestringTime when the task was submitted (UTC+8). Example: 2025-09-11 14:33:38.716.
output.scheduled_timestringTime when the task was scheduled to start (UTC+8). Example: 2025-09-11 14:33:53.089.
output.end_timestringTime when the task finished (UTC+8). Example: 2025-09-11 14:35:51.541.
output.resultsobjectTask execution result. Present when task_status is SUCCEEDED.
output.results.video_urlstringGenerated 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.codestringError code. Present when task_status is FAILED. See Error codes .
output.messagestringError message. Present when task_status is FAILED. See Error codes .
usageobjectResource usage information. Present when task_status is SUCCEEDED.
usage.video_durationfloatDuration of the generated video, in seconds. Example: 13.93.
usage.video_ratiostringAspect ratio of the generated video. Value: 1:1 or 3:4.

Task status values

StatusDescription
PENDINGTask is queued, waiting to be processed.
RUNNINGTask is being processed.
SUCCEEDEDTask completed successfully. video_url is available in the response.
FAILEDTask failed. Check output.code and output.message for details.
CANCELEDTask was canceled.
UNKNOWNTask does not exist or status cannot be determined. Returned when the task_id has expired (after 24 hours).

Response examples

Sample success response

HELPCODEESCAPE-json
{
    "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

HELPCODEESCAPE-json
{
    "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 ratioResolutionUnit price
1:1512 x 512USD 0.011469 per second
3:4512 x 704USD 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 typeValue
Task submission QPS5
Concurrent tasks1 (excess tasks queued)
Task query QPS20

Error codes

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

Mirror of Alibaba Cloud Model Studio docs for reference and RAG. Not affiliated with Alibaba Cloud.