Human & Pet Stylization API Integration Guide

Version: V1 | Last updated: November 2, 2026

Human & Pet Stylization (style_human_pet) generates a stylized image from one input image and an optional prompt. The default prompt asks the algorithm to change the background to an anime style while preserving the people and pets. Generated output depends on the image and the algorithm.

This guide covers production gateway authentication, request fields, result queries, and Python, Go, PHP, and Java examples. Use the Listing Code style_human_pet as task; do not supply an Effect ID or Effect Key. Media addresses and task IDs in examples are placeholders. Response examples illustrate the protocol and are not recorded inference results for this capability.

Contents

  1. Getting Started
  2. Submit a Task
  3. Response Format
  4. Query a Task
  5. Language Examples
  6. Request Examples
  7. Related Documentation

Getting Started

Get Your AK and SK

  1. Sign in to the MeituHub Console and open Account Overview.

  2. In the API Keys section, click Copy next to each of the following fields to obtain your AK and SK:

    • MEITU_OPENAPI_ACCESS_KEY: Access Key (AK).
    • MEITU_OPENAPI_SECRET_KEY: Secret Key (SK).

Use the SK only for server-side request signing. Do not include it in browser code, mobile apps, public repositories, or logs.

Request Signing

Both submission and query requests require AK/SK signing. Use the official signing SDK to sign the full URL, HTTP method, headers, and request body, then send the request generated by the SDK. Do not modify the body after signing.

For signing details, see API Request Signing.

Submit a Task

POST https://openapi.meitu.com/api/v1/sdk/sync/push
Content-Type: application/json

Request Fields

params.parameter.* describes fields inside the decoded params string. Serialize the complete object containing parameter; the outer params field must be a string, not an object.

FieldTypeRequiredValue or defaultDescription
taskstringYesstyle_human_petPublished Listing Code.
task_typestringYesformulaFixed value.
init_imagesobject[]YesOne imageThe input image to stylize.
paramsstringYesSee belowA serialized JSON object containing parameter.
params.parameter.promptstringNo将图像背景改为动漫风,人物和宠物保持不变Stylization instructions. Omission uses the recipe default. For blank input, the business server should insert the default prompt.
params.parameter.rsp_media_typestringFixed parameterurlReturn result URLs; populate this on the business server.
params.parameter.num_inference_stepsintegerFixed parameter15Inference steps; not an end-user setting.
params.parameter.true_cfg_scalenumberFixed parameter4.5Guidance scale; not an end-user setting.
sync_timeoutintegerNo30 in these examplesSynchronous wait in seconds. Query the task if it has not finished.

Media Input

Use this structure for init_images[0]:

{
  "url": "https://example.com/input.jpg",
  "profile": {
    "version": "v1",
    "media_profiles": {
      "media_data_type": "url",
      "img_name": "main_img"
    }
  }
}
FieldTypeRequiredDescription
urlstringYesImage URL accessible to the gateway throughout task execution.
profile.versionstringYesFixed to v1.
profile.media_profiles.media_data_typestringYesFixed to url.
profile.media_profiles.img_namestringYesFixed to main_img.

This integration accepts one image. Only the listed media metadata is needed; do not add media_profiles.prompt. Put all stylization instructions in parameter.prompt instead.

Algorithm Parameters

Serialize this complete object into the request's params string:

{
  "parameter": {
    "rsp_media_type": "url",
    "prompt": "将图像背景改为动漫风,人物和宠物保持不变",
    "num_inference_steps": 15,
    "true_cfg_scale": 4.5
  }
}

The business server supplies the three fixed algorithm parameters and the media profile. The prompt is optional. Image dimensions and internal debugging parameters are not part of this integration.

Response Format

Response Fields

Gateway responses may include an envelope containing code, error_code, message, and data. When the envelope is present, check the outer business codes first, then read the task object from data. If an SDK returns the task object directly, read status, task_id, result, and related fields at the top level.

FieldTypeDescription
codeinteger, optionalGateway business code. 0 indicates normal request processing. For nonzero values, inspect the error details.
error_codeinteger, optionalGateway error code. 0 indicates no corresponding gateway error.
messagestring, optionalGateway message or error details.
request_id / trace_idstring, optionalRequest tracing identifiers. Retain them for troubleshooting.
dataobject, optionalTask object. Absent when the task object is returned directly.

The following paths are relative to the task object:

FieldTypeDescription
statusintegerTask status. See the status table below.
task_idstringTask ID used for subsequent queries.
progressnumber, optionalTask progress, usually from 0 to 1.
resultobject / nullTask result. May be empty before completion or on failure.
result.idstring, optionalTask ID associated with the result.
result.media_info_listobject[], optionalOutput image list.
result.media_info_list[].media_datastringOutput image URL.
result.media_info_list[].media_profilesobject, optionalMedia metadata. For URL results, media_data_type is url.
result.media_info_list[].media_extraobject / null, optionalAdditional media metadata.
result.parametersJSON value, optionalAdditional capability-specific business data.
result.code / result.error_codeinteger, optionalBusiness error codes in the result. Inspect the error details for nonzero values.
result.msg / result.error_msgstring, optionalResult message or error details.

Task Status

statusMeaningAction
-1Task not foundCheck the task ID, calling account, and task retention period.
0ProcessingContinue querying.
1Submitted, waiting for schedulingSave the task ID and continue querying.
2FailedHandle the gateway and result error details.
9Synchronous wait timed outSave the task ID and continue querying.
10SucceededRead result.media_info_list.

HTTP 200 only indicates that the HTTP request completed. Determine task success using the outer business codes, task status, and result errors. Do not treat progress=1 or the presence of a task_id alone as success.

Success Example

This example shows the response structure with a gateway envelope. The task ID and media URL are placeholders:

{
  "code": 0,
  "error_code": 0,
  "message": "success",
  "data": {
    "progress": 1,
    "result": {
      "id": "example-task-id",
      "media_info_list": [
        {
          "media_data": "https://example.com/result.png",
          "media_extra": {},
          "media_profiles": {
            "media_data_type": "url"
          }
        }
      ],
      "parameters": {}
    },
    "status": 10,
    "task_id": "example-task-id"
  }
}

With a data envelope, the first output image URL is data.result.media_info_list[0].media_data. For a directly returned task object, it is result.media_info_list[0].media_data. Process every item in the returned list and download the result files promptly.

Synchronous Timeout Example

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

status=9 does not mean the task failed. Query the result using the returned task_id.

Failure Example

{
  "code": 0,
  "error_code": 0,
  "message": "success",
  "data": {
    "progress": 0,
    "result": null,
    "status": 2,
    "task_id": "example-task-id"
  }
}

A task can fail with status=2 even when the outer business codes are 0. Authentication failures, rate limits, and invalid parameters may instead return nonzero business codes or a non-2xx HTTP status without a task ID. Retain the error response and request tracing identifiers. For general error codes, see API Error Codes.

Query a Task

GET https://openapi.meitu.com/api/v1/sdk/status?task_id=example-task-id
ParameterLocationTypeRequiredDescription
task_idQuerystringYesTask ID returned by submission.

Use AK/SK credentials from the same account used for submission. Sign the full URL including task_id and the GET method, with an empty request body. The returned fields and status meanings are described in Response Format.

Increase query intervals gradually, for example 2, 5, then 10 seconds, and set an application-level waiting limit. If that limit is reached, retain the task ID and query again later. Task information and media links may expire, so query and save results promptly.

If a submission request times out before you receive a task ID, verify whether the task was created before submitting again.

Language Examples

The four examples use the same request.json file. Copy the complete request body from Request Examples, replace the media URLs and other placeholders, and save it as request.json.

SDK Setup

LanguageOfficial DocumentationDependencies
PythonPython SDKsign_sdk, requests
GoGo SDKgithub.com/mtlab/api/signer
PHPPHP SDKOfficial signer.php, cURL extension, PHP 7.3+
JavaJava SDKOfficial signing SDK, JDK 11+

Download the Python signing package from the SDK download link. Add the extracted sign_sdk package to your import path and install requests:

python -m pip install requests

Run Configuration

To submit a task:

export MEITU_OPENAPI_ACTION='push'
export MEITU_REQUEST_FILE='request.json'

To query a task, use this configuration instead:

export MEITU_OPENAPI_ACTION='status'
export MEITU_TASK_ID='example-task-id'

Each run performs the selected operation once and prints the full HTTP response. The examples do not automatically poll or retry submissions. After receiving a response, check the business codes and task status as described in Response Format.

Python

Save as client.py and run python client.py:

import json
import os
from pathlib import Path
from urllib.parse import urlencode

import requests
from sign_sdk import sign

HOST = "openapi.meitu.com"
ACTION = os.environ.get("MEITU_OPENAPI_ACTION", "push")
ak = os.environ["MEITU_OPENAPI_ACCESS_KEY"]
sk = os.environ["MEITU_OPENAPI_SECRET_KEY"]
if not ak or not sk:
    raise ValueError("Missing AK/SK")

if ACTION == "push":
    payload = json.loads(Path(os.environ.get("MEITU_REQUEST_FILE", "request.json")).read_text(encoding="utf-8"))
    if not isinstance(payload.get("params"), str):
        raise ValueError("params must be a JSON string")
    json.loads(payload["params"])
    method = "POST"
    url = f"https://{HOST}/api/v1/sdk/sync/push"
    body = json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
elif ACTION == "status":
    task_id = os.environ["MEITU_TASK_ID"]
    if not task_id:
        raise ValueError("Missing task_id")
    method = "GET"
    url = f"https://{HOST}/api/v1/sdk/status?" + urlencode({"task_id": task_id})
    body = ""
else:
    raise ValueError("MEITU_OPENAPI_ACTION must be push or status")

headers = {"Content-Type": "application/json", sign.HeaderHost: HOST}
signed_request = sign.Signer(ak, sk).sign(url, method, headers, body)
with requests.Session() as session:
    response = session.send(signed_request, timeout=(10, 100), verify=True, allow_redirects=False)
    print("HTTP", response.status_code)
    print(response.text)
    response.raise_for_status()

Go

Save as main.go and run go run main.go in a Go module with the signing SDK dependency configured:

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"time"

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

func main() {
	if err := run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func run() error {
	ak, sk := os.Getenv("MEITU_OPENAPI_ACCESS_KEY"), os.Getenv("MEITU_OPENAPI_SECRET_KEY")
	if ak == "" || sk == "" {
		return fmt.Errorf("missing AK/SK")
	}
	method, endpoint, body := http.MethodPost, "https://openapi.meitu.com/api/v1/sdk/sync/push", ""
	switch os.Getenv("MEITU_OPENAPI_ACTION") {
	case "", "push":
		filename := os.Getenv("MEITU_REQUEST_FILE")
		if filename == "" {
			filename = "request.json"
		}
		raw, err := os.ReadFile(filename)
		if err != nil {
			return err
		}
		var payload map[string]interface{}
		if err = json.Unmarshal(raw, &payload); err != nil {
			return err
		}
		params, ok := payload["params"].(string)
		if !ok || !json.Valid([]byte(params)) {
			return fmt.Errorf("params must be a JSON string")
		}
		body = string(raw)
	case "status":
		taskID := os.Getenv("MEITU_TASK_ID")
		if taskID == "" {
			return fmt.Errorf("missing task_id")
		}
		method = http.MethodGet
		endpoint = "https://openapi.meitu.com/api/v1/sdk/status?" + url.Values{"task_id": {taskID}}.Encode()
	default:
		return fmt.Errorf("MEITU_OPENAPI_ACTION must be push or status")
	}
	headers := make(http.Header)
	headers.Set("Content-Type", "application/json")
	headers.Set(signer.HeaderHost, "openapi.meitu.com")
	req, err := signer.NewSigner(ak, sk).Sign(endpoint, method, headers, body)
	if err != nil {
		return err
	}
	client := &http.Client{Timeout: 100 * time.Second, CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	raw, err := io.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	fmt.Println("HTTP", resp.StatusCode)
	fmt.Println(string(raw))
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return fmt.Errorf("HTTP request failed")
	}
	return nil
}

PHP

Place the official signer.php in the same directory, save as client.php, and run php client.php:

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

$ak = getenv('MEITU_OPENAPI_ACCESS_KEY');
$sk = getenv('MEITU_OPENAPI_SECRET_KEY');
if (!$ak || !$sk) { throw new RuntimeException('Missing AK/SK'); }
$action = getenv('MEITU_OPENAPI_ACTION') ?: 'push';
$body = '';
if ($action === 'push') {
    $file = getenv('MEITU_REQUEST_FILE') ?: 'request.json';
    $body = file_get_contents($file);
    if ($body === false) { throw new RuntimeException('Cannot read request.json'); }
    $payload = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
    if (!isset($payload['params']) || !is_string($payload['params'])) { throw new RuntimeException('params must be a JSON string'); }
    json_decode($payload['params'], true, 512, JSON_THROW_ON_ERROR);
    $method = 'POST';
    $url = 'https://openapi.meitu.com/api/v1/sdk/sync/push';
} elseif ($action === 'status') {
    $taskId = getenv('MEITU_TASK_ID');
    if (!$taskId) { throw new RuntimeException('Missing task_id'); }
    $method = 'GET';
    $url = 'https://openapi.meitu.com/api/v1/sdk/status?' . http_build_query(['task_id' => $taskId], '', '&', PHP_QUERY_RFC3986);
} else {
    throw new RuntimeException('MEITU_OPENAPI_ACTION must be push or status');
}
$headers = ['Content-Type' => 'application/json', 'Host' => 'openapi.meitu.com'];
$curl = (new Signer($ak, $sk))->sign($url, $method, $headers, $body);
curl_setopt_array($curl, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HEADER => false,
    CURLOPT_CONNECTTIMEOUT => 10,
    CURLOPT_TIMEOUT => 100,
    CURLOPT_FOLLOWLOCATION => false,
    CURLOPT_SSL_VERIFYPEER => true,
    CURLOPT_SSL_VERIFYHOST => 2,
]);
$response = curl_exec($curl);
if ($response === false) {
    $error = curl_error($curl);
    curl_close($curl);
    throw new RuntimeException($error);
}
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
echo 'HTTP ' . $status . PHP_EOL . $response . PHP_EOL;
if ($status < 200 || $status >= 300) { throw new RuntimeException('HTTP request failed'); }

Java

Add the official SDK to the classpath, save as Main.java, and compile and run with JDK 11+. Encode request.json as UTF-8:

import com.meitu.openai.common.Signer;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;

public class Main {
    private static String requiredEnv(String name) {
        String value = System.getenv(name);
        if (value == null || value.isBlank()) throw new IllegalArgumentException("Missing " + name);
        return value;
    }

    public static void main(String[] args) throws Exception {
        String ak = requiredEnv("MEITU_OPENAPI_ACCESS_KEY");
        String sk = requiredEnv("MEITU_OPENAPI_SECRET_KEY");
        String action = System.getenv().getOrDefault("MEITU_OPENAPI_ACTION", "push");
        String method;
        String url;
        String body = "";
        if ("push".equals(action)) {
            String filename = System.getenv().getOrDefault("MEITU_REQUEST_FILE", "request.json");
            body = Files.readString(Path.of(filename), StandardCharsets.UTF_8);
            method = "POST";
            url = "https://openapi.meitu.com/api/v1/sdk/sync/push";
        } else if ("status".equals(action)) {
            method = "GET";
            url = "https://openapi.meitu.com/api/v1/sdk/status?task_id="
                + URLEncoder.encode(requiredEnv("MEITU_TASK_ID"), StandardCharsets.UTF_8);
        } else {
            throw new IllegalArgumentException("MEITU_OPENAPI_ACTION must be push or status");
        }
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put(Signer.HeaderHost, "openapi.meitu.com");
        Map<String, String> signedHeaders = new Signer(ak, sk).sign(url, method, headers, body);
        HttpURLConnection connection = (HttpURLConnection) URI.create(url).toURL().openConnection();
        try {
            connection.setRequestMethod(method);
            connection.setConnectTimeout(10000);
            connection.setReadTimeout(100000);
            connection.setInstanceFollowRedirects(false);
            for (Map.Entry<String, String> header : signedHeaders.entrySet()) connection.setRequestProperty(header.getKey(), header.getValue());
            if ("POST".equals(method)) {
                byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
                connection.setDoOutput(true);
                connection.setFixedLengthStreamingMode(bytes.length);
                try (OutputStream output = connection.getOutputStream()) { output.write(bytes); }
            }
            int status = connection.getResponseCode();
            System.out.println("HTTP " + status);
            InputStream stream = status >= 400 ? connection.getErrorStream() : connection.getInputStream();
            if (stream != null) {
                try (InputStream input = stream) { System.out.println(new String(input.readAllBytes(), StandardCharsets.UTF_8)); }
            }
            if (status < 200 || status >= 300) throw new IllegalStateException("HTTP request failed");
        } finally {
            connection.disconnect();
        }
    }
}

Request Examples

Default Stylization

Save this as request.json and replace the input image URL before running any language example. It explicitly includes the default prompt and all fixed parameters:

{
  "task": "style_human_pet",
  "task_type": "formula",
  "init_images": [
    {
      "url": "https://example.com/input.jpg",
      "profile": {
        "version": "v1",
        "media_profiles": {
          "media_data_type": "url",
          "img_name": "main_img"
        }
      }
    }
  ],
  "params": "{\"parameter\":{\"rsp_media_type\":\"url\",\"prompt\":\"将图像背景改为动漫风,人物和宠物保持不变\",\"num_inference_steps\":15,\"true_cfg_scale\":4.5}}",
  "sync_timeout": 30
}

Custom Prompt

Change only parameter.prompt inside params. Keep the fixed parameters and media profile unchanged:

{
  "task": "style_human_pet",
  "task_type": "formula",
  "init_images": [
    {
      "url": "https://example.com/input.jpg",
      "profile": {
        "version": "v1",
        "media_profiles": {
          "media_data_type": "url",
          "img_name": "main_img"
        }
      }
    }
  ],
  "params": "{\"parameter\":{\"rsp_media_type\":\"url\",\"prompt\":\"将背景改为柔和的水彩风,保持人物和宠物的外观、姿态与表情。\",\"num_inference_steps\":15,\"true_cfg_scale\":4.5}}",
  "sync_timeout": 30
}

Processing Results

Read result.media_info_list from the task object. When a gateway data wrapper is present, use data.result.media_info_list. Query existing tasks instead of submitting them again; repeated submissions create new tasks and follow the platform's charging rules.