Go Signature SDK Integration Guide
Overview
The Go Signature SDK generates AK/SK signatures for Meitu Open Platform API requests. It uses the request method, URL, headers, and body to generate Authorization, then returns an *http.Request ready to send.
The SDK signs and creates the request. Application code sends it through http.Client.Do.
Requirements
- Go
1.20or later - An Open Platform Access Key (AK) and Secret Key (SK)
- Server-side HTTPS access to
openapi.meitu.com - The SK must be stored only on the server and must not be distributed to clients
Download and import
SDK version: 1.0.3
Download AIGCP-API-go-sdk-1.0.3.zip
Main files after extraction:
AIGCP-API-go-sdk-1.0.3/
├── demo.go
├── go.mod
└── signer/
└── sign.goThe archive uses the module name github.com/mtlab/api. Import the signer in the example as follows:
import "github.com/mtlab/api/signer"To run the example directly, save the code as demo.go in the extracted directory and execute go run .. To integrate it into an existing Go project, copy the signer directory into that project and change the import to the corresponding module path.
API reference
Create a signer
signer.NewSigner(accessKey, secretKey) returns a *signer.Signer.
| Parameter | Type | Description |
|---|---|---|
accessKey | string | Open Platform AK |
secretKey | string | Open Platform SK |
Sign a request
Sign has the following signature:
func (s *Signer) Sign(url, method string, headers http.Header, body string) (*http.Request, error)| Parameter | Type | Description |
|---|---|---|
url | string | Complete request URL, including the path and query parameters |
method | string | HTTP method, such as http.MethodPost or http.MethodGet |
headers | http.Header | Headers to sign; must include a Host matching the URL |
body | string | Final request body; GET requests normally use an empty string |
| Return value | Description |
|---|---|
*http.Request | Request containing X-Sdk-Date and Authorization, ready to send |
error | Returned when the URL, request, or a manually supplied signing date is invalid |
Sign modifies the supplied headers. Send the returned request directly after signing.
Complete POST example
This example calls the production synchronous task submission endpoint:
https://openapi.meitu.com/api/v1/sdk/sync/push
The request body contains the five top-level fields task, task_type, init_images, params, and sync_timeout. The value of params is a JSON string. Replace the sample task, image URL, params, and timeout with values defined by the target capability API reference.
package main
import (
"fmt"
"io"
"net/http"
"os"
"time"
"github.com/mtlab/api/signer"
)
func main() {
accessKey := os.Getenv("AIGCP_ACCESS_KEY")
secretKey := os.Getenv("AIGCP_SECRET_KEY")
if accessKey == "" || secretKey == "" {
fmt.Fprintln(os.Stderr, "AIGCP_ACCESS_KEY and AIGCP_SECRET_KEY are required")
os.Exit(1)
}
endpoint := "https://openapi.meitu.com/api/v1/sdk/sync/push"
body := `{"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}`
headers := make(http.Header)
headers.Set(signer.HeaderHost, "openapi.meitu.com")
headers.Set("Content-Type", "application/json")
sign := signer.NewSigner(accessKey, secretKey)
req, err := sign.Sign(endpoint, http.MethodPost, headers, body)
if err != nil {
fmt.Fprintln(os.Stderr, "sign request:", err)
os.Exit(1)
}
client := &http.Client{Timeout: 60 * time.Second}
resp, err := client.Do(req)
if err != nil {
fmt.Fprintln(os.Stderr, "send request:", err)
os.Exit(1)
}
defer resp.Body.Close()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Fprintln(os.Stderr, "read response:", err)
os.Exit(1)
}
fmt.Printf("status=%s\n%s\n", resp.Status, responseBody)
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
os.Exit(1)
}
}Run the example:
export AIGCP_ACCESS_KEY='<your-access-key>'
export AIGCP_SECRET_KEY='<your-secret-key>'
go run .GET example
Use the actual URL from the API reference for the target GET endpoint. The following function adds query parameters before signing and creates a signed request with an empty body:
func buildSignedGetRequest(sign *signer.Signer, endpoint, taskID string) (*http.Request, error) {
parsedURL, err := url.Parse(endpoint)
if err != nil {
return nil, err
}
query := parsedURL.Query()
query.Set("task_id", taskID)
parsedURL.RawQuery = query.Encode()
headers := make(http.Header)
headers.Set(signer.HeaderHost, parsedURL.Host)
return sign.Sign(parsedURL.String(), http.MethodGet, headers, "")
}This function requires the net/url import. When calling it, set endpoint to the complete HTTPS address of the target GET API. Follow the corresponding API reference for the task_id parameter name. Send the returned request through http.Client.Do.
Notes
Hostmust match the host in the request URL. If the URL contains a non-default port, include that port inHost.- Finalize the URL, HTTP method, query parameters, headers, and body before calling
Sign; do not modify them after signing. - Serialize a JSON body only once. The string passed to
Signmust exactly match the bytes sent. - GET requests normally use an empty string body; POST requests use the final body.
- Keep the system clock synchronized. If
X-Sdk-Dateis absent, the SDK writes the current UTC time automatically. - By default, the SDK calculates SHA-256 over the body. Only when the target API explicitly supports it, set the following header before signing:
headers.Set(signer.HeaderContentSha256, "UNSIGNED-PAYLOAD")- Follow the platform and target API reference for AK/SK payload-size limits; the current signing guide specifies payloads within
12M.
Common errors
| Symptom | Resolution |
|---|---|
401, signature error, or authentication failure | Confirm the AK/SK, HTTP method, complete URL, Host, query parameters, headers, and body match the values used for signing. |
| Time validation failure | Synchronize the server clock and let the SDK generate X-Sdk-Date. |
| POST body verification failure | Confirm that the body was not reserialized, compressed, transcoded, or modified after signing. |
| Query signature failure | Use url.Values to build the final query string before signing, and do not modify the URL afterward. |
UNSIGNED-PAYLOAD request failure | Confirm the target API supports this mode and that the header name and value match exactly. |
| Network timeout or connection failure | Check the HTTPS address, DNS, proxy, outbound network, and client timeout configuration. |
| Non-2xx response | Read the response body and handle the error code according to the target capability API reference. |