API AK/SK Signing Guide

Overview

Meitu Open Platform APIs support request authentication with an Access Key (AK) and Secret Key (SK). The caller canonicalizes the HTTP method, path, query parameters, headers, and request body according to this guide, then uses SDK-HMAC-SHA256 to generate the Authorization header.

AK/SK authentication applies to requests whose body does not exceed 12M. For a body larger than 12M, use Token authentication as specified by the API reference for the corresponding capability. The SK must be stored on a server and must not be written into client-side code.

Prerequisites

ItemDescription
AKThe application's Access Key, used to identify the caller
SKThe Secret Key paired with the AK, used to calculate the signature
Request URLThe final HTTPS endpoint provided by the corresponding capability API reference
HTTP methodThe GET, POST, or other method specified by the API
Request parametersThe final query parameters, headers, and request body

Complete the following processing before signing:

  1. Construct the final URL, query parameters, and request fields according to the capability API reference.
  2. Serialize the JSON body into its final UTF-8 bytes. Signing and transmission must use the same bytes. Do not serialize or modify the body again after signing.
  3. Set Host to match the URL. For a JSON request, also set Content-Type as required by the API.
  4. Set X-Sdk-Date in UTC format, or let the signing SDK generate it.

This guide uses the synchronous task submission endpoint: https://openapi.meitu.com/api/v1/sdk/sync/push.

Signed request components

A canonical request contains the following six components, separated by newline characters (\n):

CanonicalRequest =
    HTTPMethod + "\n" +
    CanonicalURI + "\n" +
    CanonicalQueryString + "\n" +
    CanonicalHeaders + "\n" +
    SignedHeaders + "\n" +
    PayloadHash

HTTPMethod

Use the HTTP method that will be sent, such as GET or POST. The value must exactly match the actual request.

CanonicalURI

Use the absolute path portion of the URL and apply RFC 3986 path encoding and normalization. CanonicalURI must end with /. If the actual request path does not end with /, add / only for signature calculation and leave the transmitted URL unchanged.

/api/v1/sdk/sync/push/

CanonicalQueryString

Use an empty string when there are no query parameters. When query parameters are present, percent-encode names and values separately as UTF-8 according to RFC 3986. Do not encode A-Z, a-z, 0-9, -, _, ., or ~. Encode spaces as %20 and preserve the equals sign for empty values, for example marker=. Sort by encoded parameter name in ascending order and join parameters with &.

CanonicalHeaders

Convert signed header names to lowercase, remove leading and trailing whitespace from values, and sort by lowercase name in ascending order. Write each item as name:value and separate items with a newline character (\n). Do not append a newline after the final item. When combining the components using the formula above, use exactly one newline between CanonicalHeaders and SignedHeaders, with no blank line between them. X-Sdk-Date must be signed. Common JSON requests also include host and content-type.

SignedHeaders

Join the signed header names with semicolons in the same order as CanonicalHeaders:

content-type;host;x-sdk-date

PayloadHash

By default, calculate SHA-256 over the final request body bytes and encode it as lowercase hexadecimal:

PayloadHash = LowercaseHex(SHA256(RequestBodyBytes))

For an empty body, use this digest:

e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

When the corresponding capability API explicitly supports excluding the body from the signature, set X-Sdk-Content-Sha256: UNSIGNED-PAYLOAD and use the literal UNSIGNED-PAYLOAD in the PayloadHash position. The header itself must still be added to CanonicalHeaders and SignedHeaders.

Signature calculation

1. Calculate the canonical request digest

HashedCanonicalRequest = LowercaseHex(SHA256(UTF8(CanonicalRequest)))

2. Build the string to sign

StringToSign =
    "SDK-HMAC-SHA256" + "\n" +
    XSdkDate + "\n" +
    HashedCanonicalRequest

XSdkDate must be identical to the value of the X-Sdk-Date request header.

3. Calculate the signature

Signature = LowercaseHex(HMAC-SHA256(UTF8(SecretKey), UTF8(StringToSign)))

4. Generate Authorization

AuthorizationFields =
    "SDK-HMAC-SHA256 Access=" + AccessKey +
    ", SignedHeaders=" + SignedHeaders +
    ", Signature=" + Signature

Authorization = "Bearer " + Base64(UTF8(AuthorizationFields))

Send the generated value as the Authorization request header.

Complete request example

The following example sends a POST request to the synchronous task submission endpoint. The body contains five top-level fields: task, task_type, init_images, params, and sync_timeout. The value of params is a JSON string. sync_timeout: 30 is an example value; the actual field and value must follow the corresponding capability API reference.

The final body is the following single-line UTF-8 string with no trailing newline:

{"task":"/v1/replace-with-product-task","task_type":"formula","init_images":[{"url":"https://example.com/input.jpg","profile":{"media_profiles":{"media_data_type":"url"},"version":"v1"}}],"params":"{\"parameter\":{\"rsp_media_type\":\"url\"}}","sync_timeout":30}

The SHA-256 digest of the body is:

e8c94cde52db9a0ac0a58d0927cc65176707ba57ec5530367fa1dd971664b534

The request information is:

POST /api/v1/sdk/sync/push HTTP/1.1
Host: openapi.meitu.com
Content-Type: application/json
X-Sdk-Date: 20260824T010203Z

{"task":"/v1/replace-with-product-task","task_type":"formula","init_images":[{"url":"https://example.com/input.jpg","profile":{"media_profiles":{"media_data_type":"url"},"version":"v1"}}],"params":"{\"parameter\":{\"rsp_media_type\":\"url\"}}","sync_timeout":30}

The corresponding CanonicalRequest is:

POST
/api/v1/sdk/sync/push/

content-type:application/json
host:openapi.meitu.com
x-sdk-date:20260824T010203Z
content-type;host;x-sdk-date
e8c94cde52db9a0ac0a58d0927cc65176707ba57ec5530367fa1dd971664b534

The CanonicalRequest has no additional trailing newline. Its SHA-256 digest is:

55b1ca679a9a69e295a8a0295951d4ea60b28917495d8b3ca476734b1c7bbf4e

The corresponding StringToSign is:

SDK-HMAC-SHA256
20260824T010203Z
55b1ca679a9a69e295a8a0295951d4ea60b28917495d8b3ca476734b1c7bbf4e

After calculating Signature with the actual AK, SK, and SignedHeaders above, generate the request header:

Authorization: Bearer <base 64_AUTHORIZATION />

Replace the timestamp, task name, image URL, and business parameters with actual request values. Recalculate the signature whenever any value changes.

Request time requirements

X-Sdk-Date uses UTC time in YYYYMMDDTHHMMSSZ format:

20260824T010203Z

The API gateway validates the difference between request time and receive time. Keep the calling system clock synchronized and use the current time to sign every request. Generate a new X-Sdk-Date and Authorization when retrying.

Common errors

SymptomCheck
Signature verification failsVerify that the AK and SK are paired and that the HTTP method, URL, query parameters, signed headers, and body match the signing input
Path signature mismatchVerify that CanonicalURI ends with /; the transmitted URL must not gain a trailing slash because of signing normalization
Query signature mismatchVerify RFC 3986 encoding, %20 for spaces, equals signs for empty values, and parameter ordering; do not modify the query after signing
Header signature mismatchVerify the names, values, and SignedHeaders order of Host, Content-Type, and X-Sdk-Date
Body digest mismatchVerify that signing and transmission use the same UTF-8 bytes and that no reserialization, line-ending change, or encoding change occurs
UNSIGNED-PAYLOAD verification failsVerify that the API supports this mode, the header name and value are correct, and the header is included in the signature
Request time errorVerify the system clock, UTC format, and whether an old X-Sdk-Date or Authorization was reused
Body exceeds the limitAK/SK authentication supports bodies within 12M; use Token authentication as specified by the capability API reference above the limit