Twin Ponytail Effect
Description
This API generates an AI twin ponytail effect video in the cloud.
Version
1.0
Image Requirements
- JPG and PNG formats are supported.
API Endpoint
Production environment: https://openapi.meitu.com
Task submission endpoint: https://openapi.meitu.com/api/v1/sdk/sync/push
Task name (task): /v1/double_ponytail_video/double_ponytail/405322
Task type (task_type): formulaRequest Method
POST
Content-Type: application/json
Authentication
Request Parameters
| Required | Parameter | Type | Description |
|---|---|---|---|
| Yes | params | string | Algorithm parameters as a JSON string; the source document does not define any specific algorithm fields |
| Yes | init_images | object[] | List of image files |
| Yes | task | string | Fixed value: /v1/double_ponytail_video/double_ponytail/405322 |
| Yes | task_type | string | Fixed value: formula |
| No | sync_timeout | int | Defaults to 30; synchronous timeout |
The init_images image parameters are defined as follows:
| Required | Parameter | Type | Description |
|---|---|---|---|
| Yes | url | string | Image URL or base64 data |
| Yes | profile | object | Attribute information |
The profile attributes are defined as follows:
| Required | Parameter | Type | Description |
|---|---|---|---|
| Yes | media_profiles | object | Image-related attribute information; the source document does not define profile.version, so do not add it to the request |
The media_profiles attributes are defined as follows:
| Required | Parameter | Type | Description |
|---|---|---|---|
| Yes | media_data_type | string | url means the url field contains an image URL; jpg means the url field contains a base64-encoded JPG image |
params is a JSON string with the following structure:
| Required | Field | Type | Description |
|---|---|---|---|
| Yes | parameter | object | Core algorithm parameter object; the source document does not define any nested fields, so pass an empty object |
Request Example
{
"task": "/v1/double_ponytail_video/double_ponytail/405322",
"task_type": "formula",
"init_images": [
{
"url": "https://example.com/input.jpg",
"profile": {
"media_profiles": {
"media_data_type": "url"
}
}
}
],
"params": "{\"parameter\":{}}",
"sync_timeout": 30
}Response Fields
Note: Generated result images are periodically deleted after 24 hours. Download and save them promptly.| Field | Type | Description |
|---|---|---|
| request_id | string | Request identifier |
| trace_id | string | Trace identifier |
| code | int | Business status code; 0 means that the request was accepted successfully |
| error_code | int | Error code; 0 on success |
| message | string | Business message |
| tips | any | Additional information |
| data | object | Task status and algorithm result |
The data fields are defined as follows:
| Field | Type | Description |
|---|---|---|
| status | int | Status code: -1, task not found; 0, task created; 1, processing; 2, failed; 9, timed out—use the query API; 10, succeeded |
| msg | string | Multimedia file attribute information |
| result | object | Algorithm result |
| progress | number | Task progress, for example 0.1, 0.85, or 1 |
The result fields are defined as follows:
| Field | Type | Description |
|---|---|---|
| id | string | Task ID |
| urls | string[] | List of result URLs |
Response Examples
Successful Response Example
{
"request_id": "req_1234567890",
"trace_id": "trace_1234567890",
"code": 0,
"error_code": 0,
"message": "success",
"tips": null,
"data": {
"status": 10,
"result": {
"id": "50309bd5-a827-4125-bc96-62039c93770b",
"urls": [
"https://obs.mtlab.meitu.com/mtopen/rF5GIhp5ReLKgLV91CKj5BO1q2FTLMmc/MTY5Mjg1MzIwMA==/1c39ef92-04f1-40b4-5b7e-8fcfca0c11ea.png"
]
},
"progress": 1
}
}Response Requiring a Query
Use the query API to retrieve the task result.
{
"request_id": "req_1234567890",
"trace_id": "trace_1234567890",
"code": 0,
"error_code": 0,
"message": "success",
"tips": null,
"data": {
"status": 9,
"result": {
"id": "task_1234567890"
},
"progress": 0
}
}Failed Response Example
The error code and message in the source failure example are 20008 / UNSUITABLE_IMAGE, and data is null. The following example uses the standardized gateway response structure and places the same algorithm error facts in data.result without changing their original meaning. The source document does not provide elapsed time, a timestamp, or a task ID, so the corresponding fields use 0 or an empty string.
{
"request_id": "req_1234567890",
"trace_id": "trace_1234567890",
"code": 20008,
"error_code": 20008,
"message": "UNSUITABLE_IMAGE",
"tips": null,
"data": {
"status": 2,
"result": {
"ErrorCode": 20008,
"ErrorMsg": "UNSUITABLE_IMAGE",
"Data": null
},
"progress": 0,
"predict_elapsed": 0,
"create_time": 0,
"task_id": "",
"custom_task_id": "",
"trace_id": "trace_1234567890",
"client_info": "",
"init_images": null
}
}API-Specific Error Codes and Messages
| ErrorCode | Error Message | Description |
|---|---|---|
| 20001 | PROCESS_ERROR | Processing error |
| 20008 | UNSUITABLE_IMAGE | Error message from the original failed request example; the source document provides no further description |
Common Error Codes and Messages
See API Error Codes.
SDK Examples
Python
import json
import requests
from sign_sdk import sign
def api_call_example():
key = "your_api_key"
secret = "your_api_secret"
url = "https://openapi.meitu.com/api/v1/sdk/sync/push"
method = "POST"
headers = {
"Content-Type": "application/json",
sign.HeaderHost: "openapi.meitu.com",
}
payload = {
"task": "/v1/double_ponytail_video/double_ponytail/405322",
"task_type": "formula",
"init_images": [{
"url": "https://example.com/input.jpg",
"profile": {
"media_profiles": {"media_data_type": "url"},
},
}],
"params": json.dumps({"parameter": {}}, ensure_ascii=False),
"sync_timeout": 30,
}
body = json.dumps(payload, ensure_ascii=False)
signer = sign.Signer(key, secret)
signed_request = signer.sign(url, method, headers, body)
response = requests.Session().send(signed_request)
print(f"Status: {response.status_code}")
print(f"Response: {response.text}")
if __name__ == "__main__":
api_call_example()Go
package main
import (
"fmt"
"io"
"net/http"
"github.com/mtlab/api/signer"
)
func main() {
signObj := signer.NewSigner("your_api_key", "your_api_secret")
url := "https://openapi.meitu.com/api/v1/sdk/sync/push"
method := http.MethodPost
headers := make(http.Header)
headers.Set(signer.HeaderHost, "openapi.meitu.com")
headers.Set("Content-Type", "application/json")
body := `{
"task": "/v1/double_ponytail_video/double_ponytail/405322",
"task_type": "formula",
"init_images": [{
"url": "https://example.com/input.jpg",
"profile": {
"media_profiles": {"media_data_type": "url"}
}
}],
"params": "{\"parameter\":{}}",
"sync_timeout": 30
}`
req, err := signObj.Sign(url, method, headers, body)
if err != nil {
fmt.Println("Failed to sign request:", err)
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Println("Failed to send request:", err)
return
}
defer resp.Body.Close()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Read response failed:", err)
return
}
fmt.Println("Response:", resp.StatusCode, string(responseBody))
}PHP
<?php
require 'signer.php';
$signer = new Signer('your_api_key', 'your_api_secret');
$url = 'https://openapi.meitu.com/api/v1/sdk/sync/push';
$method = 'POST';
$headers = ['Content-Type' => 'application/json'];
$innerParams = json_encode([
'parameter' => new stdClass(),
]);
$body = json_encode([
'task' => '/v1/double_ponytail_video/double_ponytail/405322',
'task_type' => 'formula',
'init_images' => [[
'url' => 'https://example.com/input.jpg',
'profile' => [
'media_profiles' => ['media_data_type' => 'url'],
],
]],
'params' => $innerParams,
'sync_timeout' => 30,
]);
$curl = $signer->sign($url, $method, $headers, $body);
$response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($status === 0) {
echo 'Error: ' . curl_error($curl);
} else {
echo "Status: {$status}\n";
echo "Response: {$response}\n";
}
curl_close($curl);
?>Java
package com.meitu.openai.common;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
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 {
Signer signer = new Signer("your_api_key", "your_api_secret");
String url = "https://openapi.meitu.com/api/v1/sdk/sync/push";
String method = "POST";
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put(Signer.HeaderHost, "openapi.meitu.com");
String body = "{\n" +
" \"task\": \"/v1/double_ponytail_video/double_ponytail/405322\",\n" +
" \"task_type\": \"formula\",\n" +
" \"init_images\": [{\n" +
" \"url\": \"https://example.com/input.jpg\",\n" +
" \"profile\": {\n" +
" \"media_profiles\": {\"media_data_type\": \"url\"}\n" +
" }\n" +
" }],\n" +
" \"params\": \"{\\\"parameter\\\":{}}\",\n" +
" \"sync_timeout\": 30\n" +
"}";
Map<String, String> signedHeaders = signer.sign(url, method, headers, body);
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod(method);
for (Map.Entry<String, String> entry : signedHeaders.entrySet()) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
connection.setDoOutput(true);
connection.getOutputStream().write(body.getBytes(StandardCharsets.UTF_8));
int status = connection.getResponseCode();
InputStream stream = status >= 400
? connection.getErrorStream()
: connection.getInputStream();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
System.out.println("Response: " + status + " " + response);
}
}
}