发送应用消息

服务端 API 更新于 2026-09-21 阅读 11

阅读指引:本篇是《开放平台服务端 API 指南》的第 6 部分。接口基础地址、通用约定与各接口请求限制,请先阅读《服务端 API 概览》。

9. 发送应用消息

POST /openapi/v1/messages/send

接口已开放,只接受应用级 Bearer Token 和 application/json 请求。每次请求只能选择一种接收目标类型和一种消息类型;消息发送不额外要求 material:manage,但素材型消息引用的素材必须已经由当前应用上传并处于可用状态。

应用消息与代发消息本接口发送的是“应用以自身身份发送”的应用消息。平台另有受控的代发能力:应用 X 可以代替真实用户 A,向用户 B 或群 C 发送 P2P/Group 消息;向群 C 代发时,用户 A 必须是该群成员。代发的当前边界见第 9.10 节。

9.1 通用请求结构

{
  "request_id": "notice_20260826_000001",
  "recipient": {
    "type": "user",
    "ids": ["20001"]
  },
  "message": {
    "type": "text",
    "payload": {
      "content": "系统维护将在今晚 22:00 开始。"
    }
  }
}
字段 必填 类型 限制与说明
request_id string 本次发送的幂等标识,1~64 个 ASCII 字符;只允许字母、数字、点、下划线、冒号和横线。同一次请求重试必须复用原值和完全相同的目标、消息内容;不得把同一值用于不同消息。
recipient object 接收目标。只允许 type 和按目标类型决定是否出现的 ids
message.type string 消息类型:textfileimagevoicetext_cardarticle_cardtemplate_card
message.payload object 必须与 message.type 对应;不接受 null、其他消息类型的字段或任何未声明字段。
  • 完整 HTTP 请求体最大 64 KiB;超限请求被拒绝。
  • JSON 必须只有一个顶层对象;字段名须按本文大小写提交,不得重复声明同一字段,未知字段会导致整个请求无效。
  • 初始限流为同一应用与来源 IP 每分钟 60 次;应用应使用指数退避,不能紧密循环重试。

9.2 接收目标与 Scope

recipient.type ids 所需 Scope 说明
user 必填,1~100 个 message:send:user 用户 ID 使用十进制正整数字符串。每项最长 128 字节;任何重复值(包括数值相同但写法不同的 ID)均拒绝;值须在正 int64 范围内,推荐使用无前导零的标准写法。用户须存在且在发布范围内;默认 target_policy=authorized_users_only 时还须保持有效 OAuth 授权,配置为 reachable_users 时只要求可达且在范围内。
org_node 必填,1~100 个 message:send:org_node 组织节点 ID 使用十进制正整数字符串;节点必须 active 且在管理员授权的组织范围内。每个节点固定覆盖自身与当前全部后代。
all 必须省略 message:send:all 只表示当前租户全部有效用户;当前还要求发布范围显式包含 user:0org_node:0、组织根节点或部分用户与组织的组合都不等于 all;即使是空数组也不能提交 ids
group 必填且只能有 1 个 group:app 群 ID 使用十进制正整数字符串。应用必须被群主或管理员添加到该群,且关系当前为 active;应用实时 Scope 和 Token Scope 也都必须包含 group:app

user/org_node/groupids 不接受 JSON 数字、空字符串、零、负数、首尾空白、重复值或超过数量限制的数组。没有权限、不可达或不存在的目标不会因为被提交而获得访问权限。同一组织请求同时选择父节点和其子节点时,服务端只保留父节点覆盖的发送,不让子节点造成重复消息。

9.2.1 应用自身向群发送消息

群应用发送复用本章同一个接口和全部消息体规则,不新增群专用消息接口或消息类型。区别仅在接收目标:recipient.type=group,并且 ids 正好包含一个群 ID。

curl -X POST "${OPENAPI_BASE_URL}/openapi/v1/messages/send" \
  -H "Authorization: Bearer ${APP_ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "request_id": "group_notice_20001_20260910_001",
    "recipient": {
      "type": "group",
      "ids": ["20001"]
    },
    "message": {
      "type": "text",
      "payload": {
        "content": "审批流程已经更新,请及时查看。"
      }
    }
  }'
  • 这是应用以自身身份发送的标准群消息,发送者是应用、接收者是群;不是用户授权代发,也不伪装成某个群成员。
  • 群成员在群会话中接收该消息;应用自身不因此成为群成员,也不能读取群历史消息。
  • 支持的消息类型与应用自身发送保持一致:text/file/image/voice/text_card/article_card/template_card;当前仍不支持 video
  • 文件、图片和语音仍须引用当前应用已上传且可用的 media_id。群目标可发送模板卡片内容,但当前不支持群消息的操作菜单回调;需要动作回调时应使用第 10.9 节支持的服务号通知场景。
  • 未绑定、已移除、应用下架、群不可用或暂停的部门群均不会落消息,并作为无效接收目标处理。应用被重新上架后不会自动恢复原群关系。
  • request_id 是幂等标识;同一次重试必须复用原值和完全相同的群及消息内容。

9.3 文本消息 text

{
  "type": "text",
  "payload": {
    "content": "你的订单已经支付成功。"
  }
}
字段 必填 限制
content UTF-8 文本,1~2048 字节;不能是纯空白。允许换行、回车和制表符,禁止 NUL 及其他不可见控制字符。

9.4 文件、图片和语音消息

三种素材型消息使用相同载荷结构,但 media_id 的素材类型必须和 message.type 完全一致。

{
  "type": "image",
  "payload": {
    "media_id": "media_0123456789abcdef0123456789abcdef"
  }
}
message.type 素材上传类型 载荷字段 限制
file type=file media_id,必填 string 使用文件素材的原文件名、大小、扩展名等已解析信息。
image type=image media_id,必填 string 只支持素材章节允许的 JPG/JPEG、PNG;应用不提交尺寸或缩略图。
voice type=voice media_id,必填 string 只支持素材章节允许的 M4A、MP3、WAV;应用不提交时长。
  • media_id 长度不超过 64 字节,以 media_ 开头;后续部分只允许 ASCII 字母、数字、下划线和横线。
  • 素材必须属于当前 Token 对应的应用、已经处理完成且类型匹配。素材不可用、类型错误或引用其他应用的素材均按无效请求处理。
  • 不要提交文件名、URL、MD5、大小、扩展名、宽高、缩略图或时长;这些字段会被视为未知字段。
  • 当前发送接口不支持 video,即使已经上传视频素材也不能用于本接口。

9.5 文本卡片 text_card

{
  "type": "text_card",
  "payload": {
    "title": "领奖通知",
    "description": "恭喜你获得奖品,请在有效期内领取。",
    "url": "http://oa.internal/prize",
    "buttonName": "更多"
  }
}
字段 必填 限制与说明
title 去除首尾空白后非空,最多 128 个 Unicode 字符;禁止控制字符。
description 纯文本或受限标记文本,包含标记在内最多 512 个 Unicode 字符;必须包含可见文本。
url 绝对 HTTP/HTTPS URL,最多 2048 字节;点击标题、正文或按钮时打开。
buttonName 1~4 个文字,禁止纯空白和控制字符;省略时固定显示“详情”。

description 可以直接提交纯文本,例如 恭喜你获得奖品。如果需要区分字体颜色,只能使用以下受限标记:

<div class="gray">辅助信息</div>
<div class="normal">正文信息</div>
<div class="highlight">强调信息</div>
<br>
  • 只允许 divbrdiv 必须且只能有一个 class 属性,值只能是 gray/normal/highlight
  • div 不能嵌套;标签外只能出现空白。禁止链接、图片、脚本、样式、事件属性及其他标签或属性。
  • 正文中的 &<> 等特殊字符必须使用 HTML 实体正确转义。非法内容会被拒绝,不会静默删除。

卡片内容安全description 不是通用 HTML 展示区。应用不得把终端用户输入或外部页面片段直接作为标记文本提交;如内容来自用户输入,应按纯文本提交,或先在应用后端生成符合白名单的安全片段。

9.6 图文卡片 article_card

{
  "type": "article_card",
  "payload": {
    "articles": [
      {
        "title": "中秋节礼品领取",
        "description": "今年中秋节公司有豪礼相送",
        "url": "http://oa.internal/mid-autumn-gift",
        "imageUrl": "http://static.internal/images/mid-autumn-gift.png"
      },
      {
        "title": "领取地点和时间",
        "url": "http://oa.internal/mid-autumn-gift/location"
      }
    ]
  }
}
字段 必填 限制与说明
articles 数组,1~8 条;不能是 null 或空数组,服务端保持提交顺序。
articles[].title 去除首尾空白后非空,最多 128 个 UTF-8 字节;禁止控制字符。
articles[].description 纯文本,最多 512 个 UTF-8 字节;禁止控制字符,不支持 HTML。省略等同于空字符串。
articles[].url 绝对 HTTP/HTTPS URL,最多 2048 字节;每篇文章使用自己的跳转地址。
articles[].imageUrl 封面图片的绝对 HTTP/HTTPS URL,最多 2048 字节。省略时使用无图布局。
  • 第一版只支持 URL 跳转,不支持小程序目标。
  • 封面只支持远程 imageUrl,不能使用应用素材 media_id。建议提供客户端普遍支持的 JPEG 或 PNG。
  • 服务端不会抓取、探测或转存 url/imageUrl;应用负责保证目标在用户网络环境中可访问。

9.7 模板卡片 template_card

模板卡片由客户端原生渲染。当前只开放文本通知型 textNotice 和图文展示型 newsNoticebuttonInteractionvoteInteractionmultipleInteraction 尚未开放。模板卡片沿用第 9.2 节按接收目标确定的消息 Scope,不增加卡片或交互专用 Scope,也不支持用户授权代发接口。

只有操作菜单产生 WebhookactionMenu.actionList[] 的菜单项点击会产生第 10.9 节所述的 message.template_card.action 事件。cardActionjumpList、引用区、图片区和横向内容中的跳转只在客户端打开目标,不会回传给应用。

文本通知型 textNotice

{
  "request_id": "gift_notice_20260907_001",
  "recipient": {
    "type": "user",
    "ids": ["20001"]
  },
  "message": {
    "type": "template_card",
    "payload": {
      "cardType": "textNotice",
      "source": {
        "iconUrl": "https://static.example.com/app.png",
        "desc": "行政服务",
        "descColor": 0
      },
      "actionMenu": {
        "desc": "请选择操作",
        "actionList": [
          {"text": "确认领取", "key": "confirm"},
          {"text": "暂不领取", "key": "decline"}
        ]
      },
      "mainTitle": {
        "title": "中秋礼品领取通知",
        "desc": "请在规定时间内完成确认"
      },
      "emphasisContent": {
        "title": "9月15日",
        "desc": "确认截止日期"
      },
      "subTitleText": "领取时请出示员工工牌。",
      "horizontalContentList": [
        {"keyName": "领取地点", "value": "行政楼一层"},
        {"keyName": "领取说明", "value": "点击访问", "type": 1, "url": "https://oa.example.com/gift"}
      ],
      "jumpList": [
        {"type": 1, "title": "查看领取说明", "url": "https://oa.example.com/gift/help"}
      ],
      "cardAction": {
        "type": 1,
        "url": "https://oa.example.com/gift"
      },
      "taskId": "gift_2026_user_20001"
    }
  }
}
字段 必填 限制与说明
cardType 固定为 textNotice
source 卡片来源样式,结构见下文。
actionMenu 卡片右上角操作菜单,结构见下文;填写时 taskId 必填。
mainTitle 条件 mainTitle.titlesubTitleText 至少一项非空;标题最多 26 个 Unicode 字符,说明最多 30 个。
emphasisContent 标题最多 10 个 Unicode 字符,说明最多 15 个;两者不能同时为空。
quoteArea 引用内容及可选跳转,结构见下文;建议不与 emphasisContent 同时使用。
subTitleText 条件 最多 112 个 Unicode 字符。文本通知型不能提交 cardImage/imageTextArea/verticalContentList
horizontalContentList 横向键值内容列表,最多 6 项,结构见下文。
jumpList 跳转指引列表,最多 3 项,结构见下文。
cardAction 整张卡片的 URL 或小程序跳转,结构见下文;它不产生操作 Webhook。
taskId 条件 存在 actionMenu 时必填,格式见下文。

图文展示型 newsNotice

{
  "type": "template_card",
  "payload": {
    "cardType": "newsNotice",
    "source": {
      "iconUrl": "https://static.example.com/news.png",
      "desc": "企业资讯",
      "descColor": 0
    },
    "actionMenu": {
      "actionList": [
        {"text": "感兴趣", "key": "interested"},
        {"text": "不再提醒", "key": "mute"}
      ]
    },
    "mainTitle": {
      "title": "园区开放日活动",
      "desc": "欢迎员工及家属报名参加"
    },
    "cardImage": {
      "url": "https://static.example.com/open-day.png",
      "aspectRatio": 2.25
    },
    "verticalContentList": [
      {"title": "活动时间", "desc": "9月20日 09:00"},
      {"title": "活动地点", "desc": "总部园区"}
    ],
    "cardAction": {
      "type": 1,
      "url": "https://oa.example.com/open-day"
    },
    "taskId": "open_day_20260920"
  }
}
字段 必填 限制与说明
cardType 固定为 newsNotice
source 卡片来源样式,结构见下文。
actionMenu 卡片右上角操作菜单,结构见下文;填写时 taskId 必填。
mainTitle.title 最多 26 个 Unicode 字符;mainTitle.desc 最多 30 个。
cardImage / imageTextArea 至少一个 必须至少提供一个图片区。cardImage.aspectRatio 省略时为 2.25,提交时必须大于 0。
quoteArea 引用内容及可选跳转,结构见下文。
verticalContentList 最多 4 项;每项标题必填且最多 26 个 Unicode 字符,说明最多 50 个。
horizontalContentList 横向键值内容列表,最多 6 项,结构见下文。
jumpList 跳转指引列表,最多 3 项,结构见下文。
cardAction 整张卡片的 URL 或小程序跳转,结构见下文;它不产生操作 Webhook。
taskId 条件 存在 actionMenu 时必填,格式见下文。
subTitleText / emphasisContent 禁止 图文展示型不能提交这些文本通知型专属字段;即使提交空字符串 subTitleText 也会被拒绝。

公共结构、任务与操作菜单

以下结构以字段表中明确引用的卡片类型为准;不能向某种 cardType 附加未声明的结构。

来源 source
字段 必填 限制与说明
iconUrl 来源图标的绝对 HTTP/HTTPS URL;建议使用 72×72 像素方形图片。
desc 来源说明,最多 20 个 Unicode 字符;它是应用自定义内容,不代表平台认证。
descColor 整数;0 灰色、1 黑色、2 红色、3 绿色,默认 0
右上角菜单 actionMenu
字段 必填 限制与说明
desc 菜单辅助说明,最多 40 个 Unicode 字符。
actionList 操作列表,1~3 项;各项 key 不得重复。
actionList[].text 操作项展示文本,最多 12 个 Unicode 字符,不能是纯空白。
actionList[].key 1~64 个 ASCII 字节,只允许字母、数字、点、下划线、冒号和横线;菜单事件会原样返回该值。
主标题 mainTitle
字段 必填 限制与说明
title 条件 一级标题,最多 26 个 Unicode 字符;具体必填条件由卡片类型决定。
desc 标题辅助信息,最多 30 个 Unicode 字符。
关键数据 emphasisContent
字段 必填 限制与说明
title 条件 关键数据文本,最多 10 个 Unicode 字符;与 desc 至少一项非空。
desc 条件 关键数据含义,最多 15 个 Unicode 字符;与 title 至少一项非空。
引用区域 quoteArea
字段 必填 限制与说明
type 整数;0 无跳转、1 跳转 URL、2 小程序跳转(当前不可用),默认 0
url 条件 type=1 时必填,必须是绝对 HTTP/HTTPS URL。
appId 条件 当前不可提交;小程序跳转不可用。
pagePath 当前不可提交;小程序跳转不可用。
title 引用标题,最多 30 个 Unicode 字符。
quoteText 引用正文,最多 300 个 Unicode 字符;允许换行、回车和制表符,不支持 HTML。
横向内容 horizontalContentList[]
字段 必填 限制与说明
keyName 左侧名称,最多 5 个 Unicode 字符。
value 右侧内容,最多 30 个 Unicode 字符。
type 整数;0 普通文本、1 URL、2 附件、3 成员详情,默认 0
url 条件 type=1 时必填,必须是绝对 HTTP/HTTPS URL。
mediaId 条件 type=2 时必填;必须是当前应用可用的文件素材标识。
userId 条件 type=3 时必填;用户必须处于应用可见范围。
跳转指引 jumpList[]
字段 必填 限制与说明
type 整数;0 无跳转、1 URL、2 小程序(当前不可用)、3 智能问答,默认 0
title 跳转项标题,最多 30 个 Unicode 字符,不能是纯空白。
url 条件 type=1 时必填,必须是绝对 HTTP/HTTPS URL。
appId 条件 当前不可提交;小程序跳转不可用。
pagePath 当前不可提交;小程序跳转不可用。
question 条件 type=3 时必填,最多 300 个 Unicode 字符;允许换行、回车和制表符。
卡片整体跳转 cardAction
字段 必填 限制与说明
type 整数;1 跳转 URL、2 小程序跳转(当前不可用)。
url 条件 type=1 时必填,必须是绝对 HTTP/HTTPS URL。
appId 条件 当前不可提交;小程序跳转不可用。
pagePath 当前不可提交;小程序跳转不可用。
通栏图片 cardImage
字段 必填 限制与说明
url 图片的绝对 HTTP/HTTPS URL。
aspectRatio 有限数值;宽高比,省略时为 2.25,提交时必须大于 0
左图右文 imageTextArea
字段 必填 限制与说明
type 整数;0 无跳转、1 URL、2 小程序(当前不可用),默认 0
url 条件 type=1 时必填,必须是绝对 HTTP/HTTPS URL。
appId 条件 当前不可提交;小程序跳转不可用。
pagePath 当前不可提交;小程序跳转不可用。
title 区域标题,最多 26 个 Unicode 字符,不能是纯空白。
desc 区域说明,最多 50 个 Unicode 字符。
imageUrl 左侧图片的绝对 HTTP/HTTPS URL。
垂直内容 verticalContentList[]
字段 必填 限制与说明
title 内容标题,最多 26 个 Unicode 字符,不能是纯空白。
desc 内容说明,最多 50 个 Unicode 字符。
任务标识 taskId

存在 actionMenu 时必填;1~128 个 ASCII 字节,只允许字母、数字、下划线、@ 和横线。它是应用提供的业务任务标识,不是发送幂等键;发送幂等仍使用 request_id

  • 请求仍执行严格 JSON 校验:未知字段、字段类型错误、多余的顶层 JSON 值以及与 type 不匹配的目标字段都会拒绝整个请求。
  • 每个文本字段会去除首尾空白后校验;禁止 NUL、格式控制字符及不允许的不可见控制字符。允许多行的引用正文或问答内容只能使用换行、回车和制表符。
  • 同一发送批次的多个接收者可以共享同一个 taskId。应用不得只按 taskId 去重不同用户的操作,建议业务键至少包含 task_id + operator_id + action_key
  • 未配置或未验证 Webhook 不影响卡片发送,但菜单点击事件可能被跳过,且没有补发接口。

小程序跳转当前不可用quoteArea/cardAction/imageTextArea/jumpListtype=2 是尚不可用的跳转类型,提交将返回 170410,请使用 URL 跳转。上述字段表中的 appId/pagePath 不应在当前请求中提交。此限制不影响 horizontalContentList[].type=2 的文件附件。

类型相关字段不能混用:无跳转时省略 URL、应用标识和页面路径;URL 跳转只提交 URL;附件只提交 mediaId;成员详情只提交 userIdnewsNotice 必须省略 subTitleText,即使空字符串也不可提交。示例中的跳转行为与卡片呈现还需兼容客户端支持。

9.8 URL 与内网地址

卡片 URL 支持公网域名、私有网络域名、私有 IPv4/IPv6,以及部署允许的 HTTP 地址。URL 必须包含协议头,不允许用户名或密码,也不允许 javascript:data:file: 等协议。默认禁止 localhost*.localhost127.0.0.0/8::1

卡片 URL 使用要求发送接口只执行上述 URL 结构、协议和 loopback 校验,卡片跳转 URL 和封面 URL 不要求属于应用配置的可信域名。应用后端必须自行限制可提交的目标域名,不能把终端用户输入直接写入这些字段。

9.9 响应、部分失败与错误码

{
  "code": 200,
  "message": "ok",
  "data": {
    "request_id": "notice_20260826_000001",
    "message_id": "message_batch_xxx",
    "sent_at": 1787727845123,
    "invalid_recipients": [
      { "recipient_id": "20002" }
    ],
    "failed_recipients": [
      { "recipient_id": "20003" }
    ]
  }
}
响应字段 JSON 类型 出现条件与含义
code integer 始终返回;成功为 200,调用方必须检查该字段。
message string 始终返回的简短结果文本,不应替代 code 做程序判断。
data.request_id string 服务端接受并原样返回的请求幂等标识。
data.message_id string 成功受理时返回的本次操作消息标识;按不透明字符串处理。
data.sent_at integer 成功受理时返回,Unix 毫秒时间戳;应用可自行按目标时区格式化。
data.invalid_recipients object[] 不存在、不可达或超出应用授权范围的目标;为空时省略。
data.failed_recipients object[] 通过目标校验但实际发送失败的目标;为空时省略。应用可使用新的 request_id 只重试这些目标。
*.recipient_id string 请求中对应的原始接收目标 ID。
业务码 含义与处理
170410 请求结构、接收目标格式、消息字段、内容、素材引用或 URL 无效。
170411 消息类型尚未开放;模板卡片中也用于拒绝 buttonInteraction/voteInteraction/multipleInteraction
170412 全部接收目标无效或应用无权访问。
170417 消息暂时无法保存或发送;使用原 request_id 和完全相同的请求进行有限次数重试。
170105 Token 缺少当前 recipient.type 所需 Scope。
170104 应用 Token 无效、过期、已撤销或 Token 类型错误;重新获取应用 Token。
170108 同一应用与来源 IP 超过每分钟 60 次;退避到下一个限流窗口。

消息接口使用 JSON 业务码表达结果,调用方必须检查 code,不能只根据 HTTP 200 判断成功。invalid_recipients/failed_recipients 为空时会被省略;失败响应通常不包含 data

9.9.1 请求去重、重试与结果确认

request_id 应在应用内唯一,不能跨不同发送业务复用。应用身份发送的正常去重窗口为 10 分钟:处理中重复提交返回 170419;已有结果时复用发送结果,重复读取不延长窗口;同一标识对应不同目标或内容时返回 170410。权限、目标可用性等条件仍会重新校验,不能要求变更授权后的重试一定返回完全相同的响应。

情况 建议处理
200,含失败明细 分别处理无效目标与失败目标。去重窗口内原请求重试不会主动重发已返回的失败子集;确认需要重发的失败目标后使用新 request_id。
170419,request processing 短暂退避后以同一 request_id 和相同请求重试;不要立刻更换 ID。
170410 / 170411 / 170412 分别检查请求或 ID 冲突、不支持的消息类型、无效接收者;修改业务请求后使用新 ID。
170417 / 170418 发送失败或服务暂不可用;检查返回明细。确认失败后再重发,避免把结果不明误认为一定未发送。
连接中断、客户端超时、无法解析响应 结果不明。在去重窗口内可用原 ID 有限重试,仍需接受重复风险;不要直接以新 ID 重发整个批次。

去重是有限保护,不保证消息恰好送达一次。超过窗口或平台去重服务异常时,重复请求可能再次发送;应用应保存自己的业务发送记录,并为重要业务设计重复处理机制。发送成功也不等于用户已收到或已读;当前无应用侧按 request_id 查询最终投递状态的接口。

9.10 用户授权代发消息

POST /openapi/v1/messages/delegate_send

接口已开放。代发表示“用户 A 通过应用 X 向用户 B 或群 C 发送消息”:消息真实发送者是用户 A,应用 X 作为代发应用写入消息展示信息。接口只接受包含 message:delegate:send 的用户级 Bearer Token,不接受应用级 Token。

消息体复用范围request_id、64 KiB 请求体、严格 JSON以及第 9.3~9.6、9.8 节的文本、素材、普通卡片和 URL 规则与 /messages/send 一致。当前代发只支持 text/file/image/voice/text_card/article_card,不支持 videotemplate_card。素材必须属于用户 Token 中绑定的应用 X。

curl -X POST "${OPENAPI_BASE_URL}/openapi/v1/messages/delegate_send" \
  -H "Authorization: Bearer ${USER_ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "request_id": "meeting_reminder_20260901_001",
    "recipient": {
      "type": "user",
      "ids": ["20002", "20003"]
    },
    "message": {
      "type": "text",
      "payload": {
        "content": "会议将在 10 分钟后开始。"
      }
    }
  }'
recipient.type ids 所需 Scope 约束
user 必填,1~100 个 message:delegate:send 用户 ID 为十进制正整数字符串,格式、长度和去重规则与第 9.2 节一致。不能把当前 Token 对应的用户 A 自己作为目标;无效目标进入 invalid_recipients
group 必填,1~100 个 message:delegate:send 群 ID 为十进制正整数字符串。用户 A 必须是有效群成员,并遵守群状态、全员禁言、成员禁言和消息风控规则;发送失败的群进入 failed_recipients
org_node / all 不支持 代发不能用于组织节点或全员群发。

9.11 获取代发用户 Token

管理员必须先为应用 X 授予 message:delegate:send,应用再通过第 5 章 H5 OAuth2 或第 6 章 JSSDK getAuthCode,让当前用户 A 授权该 Scope。应用后端使用 authorization code 换取用户 Token,并在代发时直接使用该 Token;请求体不提交用户 A 的 ID。

scope=message:delegate:send
  • 用户 A、应用 X 和有效 Scope 均由用户 Token 确定。请求只提交本文列出的字段,不提交或覆盖发送者身份。
  • 应用被下架、授权用户被移出应用发布范围、用户 Token 失效、用户撤销该 Scope,或应用当前已不再拥有该 Scope 时,代发都会被拒绝。
  • 接收者在与用户 A 的单聊或目标群会话中收到消息,并看到代发应用标识。

9.12 代发响应、时间和限流

HTTP 响应结构与第 9.9 节完全相同。data.sent_at 使用 Unix 毫秒时间戳;invalid_recipientsfailed_recipients 都回显请求中的原始字符串 ID。

  • data.message_id 的生成和返回规则与 /messages/send 完全相同:有效发送目标只有一个且成功时返回该消息标识;多个有效目标至少一个成功时返回批次标识;全部失败时不返回。
  • 同一应用与授权用户每秒最多发起 5 次代发;超限返回 170108
  • 同时保留同一应用与来源 IP 每分钟 60 次的基础限流。
  • 至少一个目标成功时 code=200;全部目标无效返回 170412;存在有效目标但全部发送失败返回 170417
  • 用户 Token 无效或 Token 类型错误返回 170209;缺少 message:delegate:send 返回 170105

代发重试限制:request_id 仍必填,但用户授权代发不提供第 9.9.1 节的十分钟请求去重保证。相同 ID 重复提交可能产生多条消息;应用须在自己的后端控制并发和重复提交,超时后不要自动无条件重发。

与应用自身发送的身份边界/messages/send 只接受应用级 Token,目标是 user/org_node/all/group,其中 group 必须是应用自身的 active 绑定群;/messages/delegate_send 只接受用户级 Token,目标是 user/group,其中群权限来自授权用户的群成员身份。不要在两个接口之间混用 Token 或群授权模型。