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.20 or 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.go

The 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.

ParameterTypeDescription
accessKeystringOpen Platform AK
secretKeystringOpen 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)
ParameterTypeDescription
urlstringComplete request URL, including the path and query parameters
methodstringHTTP method, such as http.MethodPost or http.MethodGet
headershttp.HeaderHeaders to sign; must include a Host matching the URL
bodystringFinal request body; GET requests normally use an empty string
Return valueDescription
*http.RequestRequest containing X-Sdk-Date and Authorization, ready to send
errorReturned 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

  • Host must match the host in the request URL. If the URL contains a non-default port, include that port in Host.
  • 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 Sign must 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-Date is 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

SymptomResolution
401, signature error, or authentication failureConfirm the AK/SK, HTTP method, complete URL, Host, query parameters, headers, and body match the values used for signing.
Time validation failureSynchronize the server clock and let the SDK generate X-Sdk-Date.
POST body verification failureConfirm that the body was not reserialized, compressed, transcoded, or modified after signing.
Query signature failureUse url.Values to build the final query string before signing, and do not modify the URL afterward.
UNSIGNED-PAYLOAD request failureConfirm the target API supports this mode and that the header name and value match exactly.
Network timeout or connection failureCheck the HTTPS address, DNS, proxy, outbound network, and client timeout configuration.
Non-2xx responseRead the response body and handle the error code according to the target capability API reference.