鉴权与签名

所有开放 API 请求都用 API Key 鉴权。对安全要求更高的场景,可以给单个 Key 开启「必须签名」,防篡改、防重放。

API Key

  • 在开放平台的「API Key」页创建。Key 以 sk- 开头,后接 48 位字母和数字。
  • 明文只在创建时显示一次,之后只显示首尾片段(如 sk-ab12…wxyz)。遗失请删除后重建。
  • 每个 Key 可以单独设置:名称、可调用的模型、每分钟请求数、并发数、有效期、额度上限(可按日 / 周 / 月自动重置)、是否必须签名;可随时停用或删除。
  • Key 调用产生的费用从 Key 所属秒做账号的点数中扣除。
  • Key 只能调用 /v1 开放接口;官网、开放平台的登录状态不能用来调用 /v1。
请勿在前端暴露 Key

Key 只应保存在你的服务器端。不要写进网页、小程序或 App 的代码里,也不要提交到代码仓库。

Bearer 鉴权(默认)

在每个请求的 HTTP 头里带上 Key:

请求头
Authorization: Bearer sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

POST /v1/messages(Messages 格式)另外接受 x-api-key: sk-… 头,方便直接使用对应 SDK;其他接口只认 Authorization 头。

缺少 Key,或 Key 无效、已停用、已过期、已删除时返回 HTTP 401,错误码 unauthorized,不扣点。完整列表见错误码。

请求签名(可选)

在开放平台编辑 Key 时开启「必须签名」,系统会为这个 Key 生成一个签名密钥(sig_ 开头,只显示一次;可在开放平台重置,旧密钥立即失效)。此后用这个 Key 发起的每个请求(包括文本模型接口),除了 Authorization 头,还必须带上以下三个头。没开启签名的 Key 带了也不校验。

请求头说明
X-Mz-Timestamp当前 Unix 时间戳(秒)。与服务器时间相差超过 300 秒的请求会被拒绝。
X-Mz-Nonce随机串,16~64 位字母或数字。同一个 Key 10 分钟内不能重复使用,用于防重放。
X-Mz-Signature签名值:用签名密钥对「签名串」做 HMAC-SHA256,结果转为小写十六进制。

签名串拼法

按顺序取以下 5 项,用换行符 \n 连接,末尾不加换行:

  1. HTTP 方法,大写,如 POST。
  2. 请求路径,含 /v1 前缀;有查询串时原样带上,如 /v1/tasks?status=succeeded。
  3. 与 X-Mz-Timestamp 相同的时间戳。
  4. 与 X-Mz-Nonce 相同的随机串。
  5. 请求体原始字节的 SHA-256,小写十六进制;没有请求体(如 GET)时取空串的 SHA-256。

例:签名密钥为 sig_demoSigningSecret0123456789abcdefghijKLM,POST /v1/tasks 的请求体为 {"model":"qwen-image-3.0","input":{"prompt":"一只橘猫","count":1}}(UTF-8,不含多余空格)时,签名串为:

签名串
POST
/v1/tasks
1791536400
3f9a1c7e5b2d4086a1e9c3b7d5f20e48
a544feafab06035562a597bb71c9cc9990178079ab414baef6a196806701d65f

对应的请求头如下,可用来核对你的实现:

带签名的请求头
Authorization: Bearer sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X-Mz-Timestamp: 1791536400
X-Mz-Nonce: 3f9a1c7e5b2d4086a1e9c3b7d5f20e48
X-Mz-Signature: 2180aa868bed353d9d294ed61d22ba69d3524184bb2eb6c9e7818cfc6c62569c

签名必须基于实际发送的请求体字节计算。先签名、再改动请求体(例如重新序列化 JSON)会导致验签失败。

签名示例

# 需要 bash 与 openssl
KEY="$MIAOZUO_API_KEY"            # sk- 开头的 API Key
SECRET="$MIAOZUO_SIGNING_SECRET"  # 开启签名时生成的签名密钥(sig_ 开头)
BODY='{"model":"qwen-image-3.0","input":{"prompt":"一只橘猫","count":1}}'

TS=$(date +%s)
NONCE=$(openssl rand -hex 16)
BODY_HASH=$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | sed 's/^.* //')
STRING_TO_SIGN=$(printf 'POST\n/v1/tasks\n%s\n%s\n%s' "$TS" "$NONCE" "$BODY_HASH")
SIGNATURE=$(printf '%s' "$STRING_TO_SIGN" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')

curl https://api.miaozuo.cn/v1/tasks \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -H "X-Mz-Timestamp: $TS" \
  -H "X-Mz-Nonce: $NONCE" \
  -H "X-Mz-Signature: $SIGNATURE" \
  -d "$BODY"

签名失败

缺少签名头、时间戳超出 300 秒、随机串重复或签名不匹配时,返回 HTTP 401,错误码 signature_invalid,message 会说明具体原因,不扣点。

文本模型接口同样要求签名

开启了「必须签名」的 Key 调用文本模型接口时也要带签名头。主流 SDK 默认只发送 Bearer 头,如果不方便给 SDK 加自定义请求头,请另建一个不开启签名的 Key 专门用于文本调用,并用「可调用的模型」限制它的范围。