消息与素材

开发帮助 更新于 2026-09-21 阅读 9

阅读指引:本篇汇总应用与用户交互的三条主线:上传素材、发送消息、通过 Webhook 接收事件。字段级细节见《素材上传与下载》《发送应用消息》《Webhook 事件回调》。

素材上传与下载

应用素材属于当前应用私有资源,只接受具备 material:manage应用级 Token(不接受用户 Token)。上传返回的 media_id 是后续引用和下载的唯一标识,不能跨应用使用。

type 大小 格式与处理
file 5 B~20 MiB 普通文件,下载时使用规范化安全附件名
voice 5 B~2 MiB 仅 M4A、MP3、WAV,时长不超过 60 秒,不支持 AMR
video 5 B~10 MiB 仅 MP4;当前消息发送不支持视频消息
image 5 B~10 MiB 仅 JPG/JPEG、PNG

要点:

  • 上传使用 multipart/form-data,整个请求最大 20 MiB + 64 KiB,且只能有一个名为 media 的文件字段;不接受调用方提交的大小、MD5、时长和宽高。
  • 文件扩展名必须与实际格式一致,改后缀绕不过校验;图片视频宽高不超过 20,000 像素,总像素不超过 1 亿。
  • 下载原始素材 GET /materials/content 只能提交一个 media_id,不支持 Range。
  • 素材上传专用限流返回 HTTP 429、170507

发送应用消息

POST /openapi/v1/messages/send,只接受应用级 Bearer Token 和严格 JSON(最大 64 KiB)。每次请求只能选择一种接收目标类型和一种消息类型:

{
  "request_id": "notice_20260826_000001",
  "recipient": { "type": "user", "ids": ["20001"] },
  "message": {
    "type": "text",
    "payload": { "content": "系统维护将在今晚 22:00 开始。" }
  }
}

接收目标与 Scope

recipient.type ids 所需 Scope 说明
user 1~100 个 message:send:user 用户须存在、在发布范围内;默认还须保持有效 OAuth 授权
org_node 1~100 个 message:send:org_node 固定覆盖节点自身及全部后代;不能写 department
all 必须省略 message:send:all 仅当前租户全部有效用户,且发布范围须显式含 user:0
group 且只能 1 个 group:app 应用须已被群主/管理员添加进该群且关系 active

消息类型

类型 说明
text 纯文本,1~2048 字节,不能纯空白
file / image / voice 素材型,media_id 的素材类型必须与消息类型完全一致
text_card 文本卡片:标题、描述(仅支持 div.gray/normal/highlightbr 受限标记)、跳转 URL、按钮名
article_card 图文卡片,1~8 条,封面只支持远程 imageUrl
template_card 客户端原生渲染的模板卡片,当前开放 textNotice(文本通知型)与 newsNotice(图文展示型)

要点:

  • request_id 是幂等标识(1~64 个 ASCII 字符):同一次重试必须复用原值和完全相同的目标与内容;不同消息不得复用。
  • 卡片中的 url/imageUrl 由应用后端从允许名单生成;text_card 描述中的特殊字符须 HTML 实体转义,用户输入建议按纯文本提交。
  • 模板卡片只有 actionMenu 操作菜单的点击会回传 Webhook(message.template_card.action 事件);群目标可发模板卡片但当前不支持操作菜单回调。
  • 代发能力 POST /messages/delegate_sendmessage:delegate:send,用户 Token):应用可代替真实用户向用户或群发消息,目标仅 user/group,不能向发送者本人代发,向群代发时该用户须是群成员。
  • 发送接口限流为每应用 + 来源 IP 每分钟 60 次,命中返回 170108

通过 Webhook 接收事件

平台会向管理员配置的 webhook_url 异步投递用户上行消息、模板卡片操作、组织目录失效通知和群应用变化通知。应用后端必须完成四件事:

  1. 部署一个公网 HTTPS 的 POST 接口;
  2. 使用 sign_key原始请求体验签;
  3. 正确响应 URL 验证 challenge;
  4. event_id 分流处理消息、卡片操作与同步任务。

验签

请求头 X-Matrix-* 携带事件与签名信息,签名算法:

canonical = UTF8(X-Matrix-Timestamp) || 0x0A
          || UTF8(X-Matrix-Nonce)     || 0x0A
          || raw_request_body

signature = lowercase_hex(HMAC_SHA256(key = UTF8(sign_key), data = canonical))

必须先读取未经解析的原始 body 再计算;用恒定时间比较签名,校验 X-Matrix-Event-ID == body.event_id,并拒绝与本机时间相差超过 5 分钟的请求。不要对 JSON 重新序列化后验签。

URL 验证

event_type=webhook.url.verifymessage.type=webhook_verify_text 的验证消息与普通消息分离:不要写入用户会话,也不要触发业务逻辑。必须在 HTTP 2xx 响应中原样返回 challenge,并使用 sign_key 对响应签名(code 必须是数字 0,响应 body 不超过 1024 字节),仅返回 200 不算验证成功。

事件处理

事件 触发条件 处理要点
message.created 用户给应用发消息 message_id 幂等落库;媒体引用见下
message.template_card.action 用户点击模板卡片操作菜单 校验 task_idoperator_idaction_key 后执行业务
organization.department.changed / organization.member.changed 组织目录变化 触发异步目录同步,以 sync-state 为准(见《目录与群数据同步》)
group.* 群绑定关系与群数据变化 触发异步群同步,以 groups/changes 为准
  • 消息中的图片、文件、语音、视频通过 GET /openapi/v1/messages/media/download 用 Webhook 返回的 resource_id 下载;票据绑定应用与原消息且短期有效。
  • 平台对失败投递会按策略重试;应用按 event_id 做幂等(同一事件的 HTTP 重试期间 event_id 不变),并在 5 秒内返回 2xx,耗时业务异步执行。
  • 验签通过后还应使用共享存储原子记录 nonce,重放请求不得再次产生业务副作用。