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): formula

Request Method

POST

Content-Type: application/json

Authentication

Open Platform API Signature

Request Parameters

RequiredParameterTypeDescription
YesparamsstringAlgorithm parameters as a JSON string; the source document does not define any specific algorithm fields
Yesinit_imagesobject[]List of image files
YestaskstringFixed value: /v1/double_ponytail_video/double_ponytail/405322
Yestask_typestringFixed value: formula
Nosync_timeoutintDefaults to 30; synchronous timeout

The init_images image parameters are defined as follows:

RequiredParameterTypeDescription
YesurlstringImage URL or base64 data
YesprofileobjectAttribute information

The profile attributes are defined as follows:

RequiredParameterTypeDescription
Yesmedia_profilesobjectImage-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:

RequiredParameterTypeDescription
Yesmedia_data_typestringurl 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:

RequiredFieldTypeDescription
YesparameterobjectCore 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.
FieldTypeDescription
request_idstringRequest identifier
trace_idstringTrace identifier
codeintBusiness status code; 0 means that the request was accepted successfully
error_codeintError code; 0 on success
messagestringBusiness message
tipsanyAdditional information
dataobjectTask status and algorithm result

The data fields are defined as follows:

FieldTypeDescription
statusintStatus code: -1, task not found; 0, task created; 1, processing; 2, failed; 9, timed out—use the query API; 10, succeeded
msgstringMultimedia file attribute information
resultobjectAlgorithm result
progressnumberTask progress, for example 0.1, 0.85, or 1

The result fields are defined as follows:

FieldTypeDescription
idstringTask ID
urlsstring[]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

ErrorCodeError MessageDescription
20001PROCESS_ERRORProcessing error
20008UNSUITABLE_IMAGEError 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);
        }
    }
}