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。除特别说明外,所有时间字段均为 Unix 秒时间戳,read_rate 返回 0–1 的小数。

单个消息推送

POSThttps://open.qzhuli.com/open/message/push

向一个已完成应用授权、且已连接对应数字员工的私域用户发送消息。接口会先记录消息批次,再执行 IM 推送和可选的短信兜底。

Body 字段类型必填说明
q_uidstring目标用户的 Q UID。
messagestring消息正文;不能为空,最多 10,000 个字符且不超过 60,000 字节。
titlestring通知标题,最多 100 个字符;不传时使用数字员工名称生成默认标题。
urlstring点击消息后的跳转地址,最多 2,048 字节;默认 qzhuli://open-platform/message
message_idstring业务幂等 ID,1–64 位,仅允许 A-Z a-z 0-9 . _ ~ -。同一 App 下相同 ID 必须使用相同消息内容。
message_importanceinteger消息重要级别 123,默认 1
sms_fallback_enabledinteger是否启用短信兜底,0/1,默认 0;启用时 message_importance 必须不低于 2
timeout_secondsinteger等待 IM 已读后触发兜底的秒数,范围 60–86,400,默认 60
请求示例
POST /open/message/push
Content-Type: application/json
Authorization: Bearer APP_ACCESS_TOKEN

{
  "q_uid": "q_...",
  "title": "订单提醒",
  "message": "你的订单已发货",
  "url": "https://example.com/orders/123",
  "message_id": "order_123",
  "message_importance": 2,
  "sms_fallback_enabled": 1,
  "timeout_seconds": 300
}
成功响应
{
  "code": 200,
  "msg": "发送成功",
  "data": {
    "message_id": "om_01H...",
    "client_message_id": "order_123",
    "status": "sent"
  }
}

info单个推送成功响应只返回批次 ID、幂等 ID 和当前状态;如果用户未授权或数字员工未连接,会返回错误码,并在 data.message_id 中保留已创建的消息批次 ID。

群发消息

POSThttps://open.qzhuli.com/open/message/broadcast

向多个私域用户创建一个群发批次。服务端会去重 q_uid_list,每个收件人分别记录投递结果,最多支持 1,000 个用户。

Body 字段类型必填说明
q_uid_liststring[]目标用户 Q UID 数组,去重后数量必须为 1–1,000。
messagestring消息正文;不能为空,最多 10,000 个字符且不超过 60,000 字节。
titlestring通知标题,最多 100 个字符;不传时按数字员工名称生成。
urlstring跳转地址,最多 2,048 字节;默认 qzhuli://open-platform/message
message_idstring业务幂等 ID,规则同单个推送;相同 ID 不能复用到不同内容或收件人。
message_importanceinteger消息重要级别 123,默认 1
sms_fallback_enabledinteger是否启用短信兜底,0/1,默认 0;启用时重要级别至少为 2
timeout_secondsinteger兜底等待时长,范围 60–86,400,默认 60
成功响应
{
  "code": 200,
  "msg": "发送完成",
  "data": {
    "message_id": "om_01H...",
    "client_message_id": "campaign_20260917",
    "status": "partial",
    "title": "活动通知",
    "message": "活动开始了",
    "url": "qzhuli://open-platform/message",
    "total_count": 2,
    "sent_count": 1,
    "read_count": 0,
    "failed_count": 1,
    "read_rate": 0,
    "submitted_time": 1770000000
  }
}

批次状态为 queuedsentpartialfailed;群发接口返回的计数分别表示收件人总数、已发送数、已读数和失败数。

消息发送记录

GEThttps://open.qzhuli.com/open/message/records

分页读取当前应用创建的消息批次。读取时会同步已读回执,因此返回的批次状态和计数可能比上一次查询更新。

Query 参数类型必填说明
pageinteger页码,从 1 开始,默认 1,最大 1000
page_sizeinteger每页数量,默认 20,最大 100
成功响应
{
  "code": 200,
  "msg": "获取成功",
  "data": {
    "items": [{
      "message_id": "om_01H...",
      "client_message_id": "order_123",
      "status": "sent",
      "title": "订单提醒",
      "message": "你的订单已发货",
      "url": "qzhuli://open-platform/message",
      "total_count": 1,
      "sent_count": 1,
      "read_count": 1,
      "failed_count": 0,
      "read_rate": 1,
      "submitted_time": 1770000000,
      "recipient_type": "single",
      "recipient_name": "张三",
      "recipient_count": 1,
      "uid": "u_...",
      "app_id": "app_...",
      "app_name": "订单助手"
    }],
    "page": 1,
    "page_size": 20,
    "total": 1
  }
}

recipient_typesinglebroadcast;群发记录的 uid 和单个收件人名称可能为空,详情请调用已读状态接口。

消息已读状态

POSThttps://open.qzhuli.com/open/message/read_status

读取一个消息批次下每个收件人的投递和已读状态,也可用于查询群发的失败原因。

Body / Query 字段类型必填说明
message_idstring消息批次 ID,即发送接口返回的 data.message_id
pageinteger收件人页码,从 1 开始,默认 1,最大 1000
page_sizeinteger每页收件人数,默认 100,最大 100
请求示例
{
  "message_id": "om_01H...",
  "page": 1,
  "page_size": 100
}
成功响应
{
  "code": 200,
  "msg": "获取成功",
    "data": {
    "message_id": "om_01H...",
    "client_message_id": "campaign_20260917",
    "title": "活动通知",
    "message": "活动开始了",
    "url": "qzhuli://open-platform/message",
    "status": "sent",
    "total_count": 1,
    "sent_count": 1,
    "read_count": 1,
    "failed_count": 0,
    "read_rate": 1,
    "submitted_time": 1770000000,
    "recipients": [{
      "q_uid": "q_...",
      "uid": "u_...",
      "recipient_name": "张三",
      "status": "read",
      "sent_time": 1770000010,
      "read_time": 1770000040,
      "sms_status": "disabled",
      "reason": "",
      "error_message": ""
    }],
    "recipient_page": 1,
    "recipient_page_size": 100
  }
}

响应中的批次字段与发送记录一致;recipients 是收件人明细,sent_timeread_time 为 Unix 秒时间戳。收件人 status 可能为 queuedsendingsentreadfailed;失败时查看 reasonerror_message

统计概览

GEThttps://open.qzhuli.com/open/stats/overview

返回当前应用的授权、连接和消息投递汇总,不需要额外 query 参数。

成功响应
{
  "code": 200,
  "msg": "获取成功",
  "data": {
    "login_count": 128,
    "active_private_users": 96,
    "new_connections": 24,
    "today_new_connections": 5,
    "sent_count": 320,
    "read_count": 256,
    "read_rate": 0.8
  }
}
字段说明
login_count当前有效授权用户数,同一应用用户只计一次。
active_private_users当前有效的数字员工连接数。
new_connections最近 30 天内建立连接的数量。
today_new_connections今天首次授权的用户数。
sent_count按逻辑消息去重后的发送总数。
read_count已收到真实已读回执的消息数。
read_rate已读数 / 发送数,范围 0–1;没有发送记录时为 0

私域用户列表

GEThttps://open.qzhuli.com/open/stats/private_users

分页读取当前应用的有效私域用户。列表只返回脱敏手机号;如需在授权范围内读取完整手机号,应使用对应用户 access token 调用用户信息接口。

Query 参数类型必填说明
pageinteger页码,从 1 开始,默认 1
page_sizeinteger每页数量,默认 20,最大 100
成功响应
{
  "code": 200,
  "msg": "获取成功",
  "data": {
    "items": [{
      "q_uid": "q_...",
      "name": "张三",
      "phone_masked": "138****0000",
      "phone_authorized": true,
      "connection_status": "connected",
      "status": 1,
      "last_authorize_time": 1770000000
    }],
    "page": 1,
    "page_size": 20,
    "total": 128
  }
}
字段说明
q_uid开放平台用户标识。
name用户昵称,找不到用户时为空字符串。
phone_masked脱敏手机号,例如 138****0000;未授权时为空。
phone_authorized当前应用授权范围内是否有可用手机号。
connection_statusconnected 表示已连接数字员工,authorized 表示已授权但尚未连接。
status授权记录状态;此列表只返回有效记录 1
last_authorize_time最近一次授权时间,Unix 秒时间戳。

错误处理

不能只判断 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、日志或前端源码。手机号拒绝后本次授权不会完成。