AI Video Generation v3.0

AI Video Generation v3.0

Description

Generate videos from text descriptions, or from an input image combined with a text description. Both text-to-video and image-to-video requests are supported.

Version

1.0

Input Requirements

Text-to-video does not require an image. For image-to-video, provide an image URL through init_images.

Request URL

Production host: https://openapi.meitu.com

Task submission endpoint:

https://openapi.meitu.com/api/v1/sdk/sync/push

Task name (task): /v1/v3_mvv_model/ai_video/453181

Task type (task_type): formula

HTTP Method

POST

Content-Type: application/json

Authentication

Use an AK/SK pair with access to this capability and sign requests using the signing SDK. See API Request Signing.

Request Parameters

RequiredParameterTypeDescription
YestaskstringFixed value: /v1/v3_mvv_model/ai_video/453181.
Yestask_typestringFixed value: formula.
Noinit_imagesobject[]Input images. Omit for text-to-video; provide for image-to-video.
YesparamsstringJSON-serialized algorithm parameter object.
Nosync_timeoutintegerSynchronous waiting time in seconds. The gateway default is 30.

init_images Element

RequiredParameterTypeDescription
YesurlstringAccessible input image URL.
YesprofileobjectImage configuration.

profile

RequiredParameterTypeDescription
YesversionstringFixed value: v1.
Yesmedia_profilesobjectImage transfer properties. This API's example uses an empty object, {}.

params

The decoded object directly contains the following field. Do not add a parameter wrapper:

RequiredParameterTypeDescription
Yesuser_promptstringText description for video generation.

Request Examples

Replace the text description and image URL. The HTTP body is a JSON object; only the value of params is a JSON string.

Text-to-Video

{
  "task": "/v1/v3_mvv_model/ai_video/453181",
  "task_type": "formula",
  "params": "{\"user_prompt\":\"A gentle breeze moves through the trees.\"}",
  "sync_timeout": 30
}

Image-to-Video

{
  "task": "/v1/v3_mvv_model/ai_video/453181",
  "task_type": "formula",
  "init_images": [
    {
      "url": "https://example.com/input.jpg",
      "profile": {
        "version": "v1",
        "media_profiles": {}
      }
    }
  ],
  "params": "{\"user_prompt\":\"A gentle breeze moves through the trees.\"}",
  "sync_timeout": 30
}

Decoded params:

{
  "user_prompt": "A gentle breeze moves through the trees."
}

Response Fields

code = 0 indicates normal request processing; also check data.status. When the status is 10, read the result URLs from data.result.urls. Download and save the results promptly.

FieldTypeDescription
codeintegerBusiness status code. 0 indicates normal request processing.
messagestringResponse message, useful for diagnosing failures.
dataobject / nullTask details; may be null when the request fails.

data

FieldTypeDescription
statusinteger-1: not found; 0: created; 1: running; 2: failed; 9: synchronous wait timed out, query required; 10: succeeded.
msgstringTask message.
resultobjectTask result or identifier.
progressnumberTask progress, such as 0.1, 0.85, or 1.

result

FieldTypeDescription
idstringGateway task ID used to query the result.
urlsstring[]Result URLs returned on success.

Response Examples

The success and error structures below follow the original API documentation, with task IDs and URLs replaced by placeholders. No live call was made. The original result URLs end in .jpg; neither the video container format nor a fixed output count is specified. These URLs do not guarantee a particular format or output count.

Success Example

HTTP 200, Content-Type: application/json.

{
  "code": 0,
  "data": {
    "status": 10,
    "result": {
      "id": "example-task-id",
      "urls": [
        "https://example.com/result-1",
        "https://example.com/result-2"
      ]
    },
    "progress": 1
  }
}

Query Required Example

The following illustrates a status = 9 response. A synchronous wait timeout does not mean the task failed. Use data.result.id with Task Query instead of resubmitting.

{
  "code": 0,
  "data": {
    "status": 9,
    "result": {
      "id": "example-task-id"
    },
    "progress": 0
  }
}

Error Example

The source error example uses HTTP 400. Other errors may return different status codes and messages.

{
  "code": 20008,
  "message": "UNSUITABLE_IMAGE",
  "data": null
}

Common Error Codes

CodeMessageDescription
20001PROCESS_ERRORProcessing error.
20008UNSUITABLE_IMAGEThe image does not meet processing requirements; see the error example above.

See API Error Codes for other errors.

SDK Examples

All examples use the image-to-video request above and embed the full request body; no separate JSON file is needed. Set up the SDK for your language, then replace the AK, SK, image URL, and text description.

For text-to-video, omit init_images. Each example submits once and prints the response. Sign and send the same final request body; query the task if the returned status is 9.

Python

Python Signing SDK

import json

import requests
from sign_sdk import sign

def main():
    key = "YOUR_ACCESS_KEY"
    secret = "YOUR_SECRET_KEY"
    url = "https://openapi.meitu.com/api/v1/sdk/sync/push"
    inner_params = {
        "user_prompt": "A gentle breeze moves through the trees."
    }
    payload = {
        "task": "/v1/v3_mvv_model/ai_video/453181",
        "task_type": "formula",
        "init_images": [
            {
                "url": "https://example.com/input.jpg",
                "profile": {
                    "version": "v1",
                    "media_profiles": {}
                }
            }
        ],
        "params": json.dumps(inner_params, ensure_ascii=True),
        "sync_timeout": 30
    }
    body = json.dumps(payload, ensure_ascii=True)
    headers = {
        "Content-Type": "application/json",
        sign.HeaderHost: "openapi.meitu.com",
    }
    signer = sign.Signer(key, secret)
    signed_request = signer.sign(url, "POST", headers, body)
    with requests.Session() as session:
        response = session.send(
            signed_request, timeout=(10, 60), verify=True, allow_redirects=False
        )
        print("Status:", response.status_code)
        print("Response:", response.text)

if __name__ == "__main__":
    main()

Go

Go Signing SDK

package main

import (
    "fmt"
    "io"
    "net/http"
    "time"

    "github.com/formula/api/signer"
)

func main() {
    body := `{
  "task": "/v1/v3_mvv_model/ai_video/453181",
  "task_type": "formula",
  "init_images": [
    {
      "url": "https://example.com/input.jpg",
      "profile": {
        "version": "v1",
        "media_profiles": {}
      }
    }
  ],
  "params": "{\"user_prompt\":\"A gentle breeze moves through the trees.\"}",
  "sync_timeout": 30
}`
    url := "https://openapi.meitu.com/api/v1/sdk/sync/push"
    headers := make(http.Header)
    headers.Set("Content-Type", "application/json")
    headers.Set(signer.HeaderHost, "openapi.meitu.com")
    signObj := signer.NewSigner("YOUR_ACCESS_KEY", "YOUR_SECRET_KEY")
    req, err := signObj.Sign(url, http.MethodPost, headers, body)
    if err != nil {
        fmt.Println("Sign request failed:", err)
        return
    }
    client := &http.Client{
        Timeout: 60 * time.Second,
        CheckRedirect: func(req *http.Request, via []*http.Request) error {
            return http.ErrUseLastResponse
        },
    }
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Send request failed:", err)
        return
    }
    defer resp.Body.Close()
    responseBody, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("Read response failed:", err)
        return
    }
    fmt.Println("Status:", resp.StatusCode)
    fmt.Println("Response:", string(responseBody))
}

PHP

PHP Signing SDK

<?php
require_once __DIR__ . '/signer.php';

$innerParams = json_encode([
    'user_prompt' => 'A gentle breeze moves through the trees.'
], JSON_UNESCAPED_SLASHES);
$body = json_encode([
    'task' => '/v1/v3_mvv_model/ai_video/453181',
    'task_type' => 'formula',
    'init_images' => [
        [
            'url' => 'https://example.com/input.jpg',
            'profile' => [
                'version' => 'v1',
                'media_profiles' => (object) []
            ]
        ]
    ],
    'params' => $innerParams,
    'sync_timeout' => 30
], JSON_UNESCAPED_SLASHES);
$url = 'https://openapi.meitu.com/api/v1/sdk/sync/push';
$headers = [
    'Content-Type' => 'application/json',
    'Host' => 'openapi.meitu.com',
];
$signer = new Signer('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY');
$curl = $signer->sign($url, 'POST', $headers, $body);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
$response = curl_exec($curl);
if ($response === false) {
    echo 'Error: ' . curl_error($curl) . PHP_EOL;
} else {
    echo 'Status: ' . curl_getinfo($curl, CURLINFO_HTTP_CODE) . PHP_EOL;
    echo 'Response: ' . $response . PHP_EOL;
}
curl_close($curl);

Java

Java Signing SDK

import com.meitu.openai.common.Signer;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) throws Exception {
        String body =
                "{\n" +
                "  \"task\": \"/v1/v3_mvv_model/ai_video/453181\",\n" +
                "  \"task_type\": \"formula\",\n" +
                "  \"init_images\": [\n" +
                "    {\n" +
                "      \"url\": \"https://example.com/input.jpg\",\n" +
                "      \"profile\": {\n" +
                "        \"version\": \"v1\",\n" +
                "        \"media_profiles\": {}\n" +
                "      }\n" +
                "    }\n" +
                "  ],\n" +
                "  \"params\": \"{\\\"user_prompt\\\":\\\"A gentle breeze moves through the trees.\\\"}\",\n" +
                "  \"sync_timeout\": 30\n" +
                "}";
        String url = "https://openapi.meitu.com/api/v1/sdk/sync/push";
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put(Signer.HeaderHost, "openapi.meitu.com");
        Signer signer = new Signer("YOUR_ACCESS_KEY", "YOUR_SECRET_KEY");
        Map<String, String> signedHeaders = signer.sign(url, "POST", headers, body);

        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        try {
            connection.setRequestMethod("POST");
            connection.setConnectTimeout(10000);
            connection.setReadTimeout(60000);
            connection.setInstanceFollowRedirects(false);
            connection.setDoOutput(true);
            for (Map.Entry<String, String> entry : signedHeaders.entrySet()) {
                connection.setRequestProperty(entry.getKey(), entry.getValue());
            }
            byte[] bodyBytes = body.getBytes(StandardCharsets.UTF_8);
            connection.setFixedLengthStreamingMode(bodyBytes.length);
            try (OutputStream output = connection.getOutputStream()) {
                output.write(bodyBytes);
            }
            int status = connection.getResponseCode();
            System.out.println("Status: " + status);
            InputStream responseStream = status >= 400
                    ? connection.getErrorStream() : connection.getInputStream();
            if (responseStream != null) {
                try (InputStream input = responseStream;
                     ByteArrayOutputStream output = new ByteArrayOutputStream()) {
                    byte[] buffer = new byte[4096];
                    int length;
                    while ((length = input.read(buffer)) != -1) {
                        output.write(buffer, 0, length);
                    }
                    System.out.println("Response: " + output.toString("UTF-8"));
                }
            }
        } finally {
            connection.disconnect();
        }
    }
}