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
| Item | Description |
|---|---|
| AK | The application's Access Key, used to identify the caller |
| SK | The Secret Key paired with the AK, used to calculate the signature |
| Request URL | The final HTTPS endpoint provided by the corresponding capability API reference |
| HTTP method | The GET, POST, or other method specified by the API |
| Request parameters | The final query parameters, headers, and request body |
Complete the following processing before signing:
- Construct the final URL, query parameters, and request fields according to the capability API reference.
- 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.
- Set
Hostto match the URL. For a JSON request, also setContent-Typeas required by the API. - Set
X-Sdk-Datein 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" +
PayloadHashHTTPMethod
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-datePayloadHash
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:
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855When 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" +
HashedCanonicalRequestXSdkDate 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:
e8c94cde52db9a0ac0a58d0927cc65176707ba57ec5530367fa1dd971664b534The 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
e8c94cde52db9a0ac0a58d0927cc65176707ba57ec5530367fa1dd971664b534The CanonicalRequest has no additional trailing newline. Its SHA-256 digest is:
55b1ca679a9a69e295a8a0295951d4ea60b28917495d8b3ca476734b1c7bbf4eThe corresponding StringToSign is:
SDK-HMAC-SHA256
20260824T010203Z
55b1ca679a9a69e295a8a0295951d4ea60b28917495d8b3ca476734b1c7bbf4eAfter 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:
20260824T010203ZThe 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
| Symptom | Check |
|---|---|
| Signature verification fails | Verify 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 mismatch | Verify that CanonicalURI ends with /; the transmitted URL must not gain a trailing slash because of signing normalization |
| Query signature mismatch | Verify RFC 3986 encoding, %20 for spaces, equals signs for empty values, and parameter ordering; do not modify the query after signing |
| Header signature mismatch | Verify the names, values, and SignedHeaders order of Host, Content-Type, and X-Sdk-Date |
| Body digest mismatch | Verify that signing and transmission use the same UTF-8 bytes and that no reserialization, line-ending change, or encoding change occurs |
UNSIGNED-PAYLOAD verification fails | Verify that the API supports this mode, the header name and value are correct, and the header is included in the signature |
| Request time error | Verify the system clock, UTC format, and whether an old X-Sdk-Date or Authorization was reused |
| Body exceeds the limit | AK/SK authentication supports bodies within 12M; use Token authentication as specified by the capability API reference above the limit |