API 文档 · v1

从创建应用到真实调用

1

创建应用

控制台创建应用,保存 AppKey、AppSecret 和回调地址。

2

扫码授权

把授权地址放到登录按钮,用户在 Q助理 App 扫码确认。

3

换 token 并调用

服务端换取用户或应用 token,再调用对应接口。

keyAppSecret 仅在创建或重置时完整展示一次,请妥善保存并仅在服务端使用。

请求头与统一响应

服务端调用 POST https://open.qzhuli.com/oauth/access_token 和业务 API 时需要以下请求头。业务 API 还需要 Authorization: Bearer ACCESS_TOKEN

请求头说明
X-QZ-App-Key控制台生成的 AppKey
X-QZ-TimestampUnix 毫秒时间戳,允许与服务端相差约 5 分钟
X-QZ-Nonce每次请求新生成的 16–64 位随机串
X-QZ-Sign按签名规则生成的小写 HMAC-SHA256
统一成功响应
{
  "code": 200,
  "msg": "获取成功",
  "data": { "...": "业务数据" }
}

POST 使用 JSON body,GET 使用 query。列表返回 itemstotalpagepage_size;时间为 Unix 秒,金额为分。

签名规则

浏览器跳转 GET https://open.qzhuli.com/oauth/authorize 不签名;其余对外服务端接口均须签名。每次请求使用新的 nonce,且 nonce 为 16–64 位 A-Za-z0-9_- 随机串。

  1. 收集 body 或 query 的全部业务字段。POST https://open.qzhuli.com/oauth/access_tokenapp_secret 仅用于凭证校验,不参与签名;业务字段不得使用 app_keytimestampnonceaccess_tokensign
  2. 加入请求头的 app_keytimestampnonce;业务 API 还加入 Bearer token 作为 access_token
  3. 字段名按 ASCII 升序排序。字符串原样、整数十进制、布尔值为 true/false;字符串数组保持顺序并编码为无空格 JSON。字段名和值按 RFC 3986 编码后以 key=value&... 拼接。
  4. UPPERCASE_METHOD + "\n" + PATH + "\n" + 规范字段串 为待签名文本,使用 AppSecret 的原始 UTF-8 值计算 HMAC-SHA256,输出小写 hex。
待签名文本示例
POST
/oauth/access_token
app_key=YOUR_APP_KEY&grant_type=client_credentials&nonce=RANDOM_NONCE_AT_LEAST_16&timestamp=UNIX_MS_TIMESTAMP

时间戳允许与平台相差约 5 分钟;同一 AppKey 下 nonce 只能使用一次。业务接口签名时,access_token 必须与 Authorization: Bearer ... 中的值完全一致。

扫码授权

授权地址由你的应用生成 state 并保存到服务端会话。开启 PKCE 时同时保存 code_verifier,仅把 challenge 放进地址。

浏览器跳转
https://open.qzhuli.com/oauth/authorize?app_key=YOUR_APP_KEY&redirect_uri=https%3A%2F%2Fexample.com%2Foauth%2Fcallback&state=RANDOM_STATE&scope=user_info&code_challenge=PKCE_CHALLENGE&code_challenge_method=S256

平台会展示二维码并完成扫码和授权。用户同意后回调 redirect_uri?code=...&state=...;用户拒绝则回调 error=access_denied&state=...。若应用开启手机号授权,用户必须明确同意;拒绝则本次应用授权不完成。

接口用途
GET https://open.qzhuli.com/oauth/authorize发起扫码授权并处理授权回调

服务端换 token

POSThttps://open.qzhuli.com/oauth/access_token

换码请求在服务端执行,不能把 AppSecret 放在浏览器。AppKey 放在 X-QZ-App-Key 请求头,body 示例:

authorization_code
{
  "app_secret": "YOUR_APP_SECRET",
  "grant_type": "authorization_code",
  "code": "ONE_TIME_CODE",
  "redirect_uri": "https://example.com/oauth/callback",
  "code_verifier": "PKCE_VERIFIER"
}
响应示例
{ "code": 200, "data": {
  "access_token": "ou_...", "refresh_token": "or_...",
  "token_type": "Bearer", "credential_type": "user",
  "expires_in": 7200, "user": { "q_uid": "q_..." }
} }

应用服务端令牌也可用 grant_type=client_credentials 换取,用于应用级消息、统计和控制台以外的业务调用。

用户信息

POSThttps://open.qzhuli.com/open/user/info

使用用户 access_token,body 传该 token 对应的 q_uid。手机号只在应用开启手机号、用户本次同意且授权版本有效时返回;其他情况不会返回该字段。

响应示例
{ "code": 200, "data": {
  "q_uid": "q_...", "nickname": "用户昵称", "avatar": "https://...",
  "is_connected_agent": true, "phone": "13800000000"
} }

消息与统计

以下接口使用 grant_type=client_credentials 换得的应用 access token,并在请求头携带 Authorization: Bearer APP_ACCESS_TOKEN

接口请求说明
POST https://open.qzhuli.com/open/message/pushq_uidmessage、可选 title/url/message_id/message_importance/sms_fallback_enabled/timeout_seconds单个已授权用户发送,返回 message_id 与投递状态
POST https://open.qzhuli.com/open/message/broadcastq_uid_list(1–1000)及消息字段群发,返回成功/失败数量
GET https://open.qzhuli.com/open/message/recordspage,page_size真实发送记录分页
POST https://open.qzhuli.com/open/message/read_statusmessage_id,可选 page,page_size查询真实已读状态
GET https://open.qzhuli.com/open/stats/overview无业务参数授权、连接、发送、已读率统计
GET https://open.qzhuli.com/open/stats/private_userspage,page_size私域用户真实分页,列表仅返回脱敏手机号
消息发送 body
{ "q_uid": "q_...", "title": "订单提醒", "message": "你的订单已发货", "message_id": "order_123" }

错误处理

不能只判断 HTTP 200:业务错误可能仍返回 HTTP 200,必须同时检查 code;网关错误还可能返回 4xx/5xx。

code处理建议
40001参数、授权范围或版本冲突;修正请求后重试
40002缺少/无效签名、会话或企业上下文;重新读取会话或检查请求头
40003access_token 无效/过期;按授权流程重新换 token
40004一次性 code 已使用或已过期;重新发起扫码授权
40005数字员工尚未连接;确认用户已完成应用授权且仍为有效私域用户
40006消息参数或目标不可用;不要伪造成功记录,展示服务端 msg
429/5xx按退避重试;幂等写请求沿用同一业务 message_id
security AppSecret、access_token、code 只放服务端;永远不要写入 URL、日志或前端源码。手机号拒绝后本次授权不会完成。