← 所有文章
教程

通过 UnifyPort 添加与移除消息表情回应

通过 UnifyPort 添加消息表情回应时,调用 POST /v1/messages/reaction,提交选定的账号、会话、消息、原消息发送者及 emoji。要移除当前连接账号已有的回应,保留目标并发送 emoji: ""。最容易混淆的是:sender_id 指原消息的作者,不是操作员,也不是你想修改其回应的任意用户。

要点

  • 当前发送操作支持 whatsapp 和 telegram;接收回应事件是另一项能力。
  • 使用选中的原消息定位目标,不要使用回应事件自身的消息 ID。
  • 回应他人的消息时明确传入 sender_id;省略时默认指连接账号自身。
  • 添加与移除应是明确操作,不要设计成失败后反复重试的切换开关。

将请求字段对应到原消息

消息回应接口操作的是已有消息,不是发送一条包含表情的文本,也不使用引用回复 token。

请求字段从已保存的 message.received 事件取值
account_id顶层 account_id
conversation_iddata.conversation.id
message_iddata.message.id
sender_iddata.sender.id,即原消息作者
emoji操作员选择的表情;移除时为空字符串

在群聊中,会话标识群组,发送者标识成员。不要因为私聊中两者看起来相似,就把发送者替换成会话目标。保留渠道返回的完整标识,不要根据联系人名称或手机号自行拼接。

如果入口是 message.reaction 事件,则必须再区分:data.message.id 标识回应自身,data.message.target_message_id 才指向原消息。该事件的发送者是作出回应的人,不一定是原消息作者。应先找到已保存的原消息,再构造操作。回应 webhook 处理教程解决的是接收与状态投影问题;本文解决的是主动发送请求。

构造明确的添加或移除请求

以下 JavaScript 只是请求构造示例,不是已执行的集成测试,也不是完整接收器。输入应是经过验签、持久化,并由有权限的操作员选中的原始消息事件。函数名和错误文字属于本地应用代码。

function buildReactionRequest(original, emoji) {
  if (original.type !== 'message.received' ||
      !['whatsapp', 'telegram'].includes(original.provider)) {
    throw new Error('Select a supported original message');
  }

  const conversation = original.data?.conversation;
  const message = original.data?.message;
  const sender = original.data?.sender;
  if (!original.account_id || !conversation?.id ||
      !message?.id || !sender?.id) {
    throw new Error('Original message context is incomplete');
  }
  if (typeof emoji !== 'string') {
    throw new Error('Choose an emoji or an empty string');
  }

  return {
    account_id: original.account_id,
    conversation_id: conversation.id,
    message_id: message.id,
    sender_id: sender.id,
    emoji
  };
}

传入 "👍" 请求添加回应,传入 "" 请求移除。该函数只检查上下文和数据类型,不保证上游接受任意表情。不要用 null、省略字段或自行添加的 remove 标记代替空字符串。

由后端使用 X-Api-Key,将生成的 JSON 发往 POST /v1/messages/reaction。密钥不得进入浏览器代码。发送前验证操作员对消息账号及消息的访问权限,并固定选中的目标,避免新消息到来后操作对象改变。

如果需要的是带引用的一句话,而非表情回应,应使用单独的 WhatsApp 引用回复流程。其不透明 reply_token 不是回应标识。

根据操作能力启用按钮,而非事件能力

当前渠道操作矩阵与 webhook 事件矩阵描述的是不同能力:

渠道通过此接口发送回应回应事件映射
whatsapp支持支持
telegram支持支持
line不支持支持
twitter、zalo、tiktok、whatsapp-protocol不支持不支持

这是文档中的适配器映射,不保证每个账号或上游条件下都可用。LINE 收件箱可以显示传入回应,但不能因此启用发送回应按钮。不支持的组合返回 501 unsupported_by_provider,重复调用不会增加能力。

UnifyPort 提供连接账号的非官方接口。Telegram 官方 Bot API另有机器人使用的 setMessageReaction。如果要求机器人身份,应使用对应原生契约;不要将其请求结构复制到本接口,也不要把其限制直接当成 UnifyPort 的行为定义。

分开保存意图、请求结果与观察状态

接口文档展示的成功响应为 200 OK,包含 data.ok: true。保存实际 HTTP 结果及返回的 request_id,不要把成功结果解释为其他人已经看见回应。

建议应用按以下方式处理:

  1. 同一账号、同一目标消息的操作串行执行,避免旧的添加任务在较新的移除任务之后运行。
  2. 发送前记录期望表情,另行记录 HTTP 结果。
  3. 出现 react_message_failed 时检查错误与原始目标。超时则保留“结果不确定”,不要自动发送相反操作作为补偿。
  4. 收到匹配的回应事件时幂等更新观察状态;不要假定每次请求必有回调,或回调一定有序。

接收侧配置 signing_secret 并遵循投递文档:对时间戳、点号及原始请求体进行 HMAC-SHA256 验证,检查时间新鲜度,持久化后再确认投递。接收到 webhook 不等于获得了自动发起新操作的授权。

验收检查与常见问题

上线前分别测试:收到的私聊消息、其他群成员的消息、账号自己发送的消息、空字符串移除、不支持的渠道及网络结果不确定。确认新消息到来不会改变选定目标。这是建议测试清单,不是已完成的测试结果。

sender_id 能指定由谁作出回应吗?

不能。它指定被回应消息的作者。执行操作的是当前连接账号,不能用该字段冒充其他回应者。

再发送相同表情就能移除吗?

文档规定使用 emoji: "" 移除,不应假定存在切换语义。

为什么能接收 LINE 回应,却不能发送?

入站事件解析和出站操作有独立支持矩阵。当前出站回应操作只映射到 Telegram 和 WhatsApp。

下一步与参考资料

先对照消息回应接口实现目标检查,再加入收件箱按钮。证据不足时保留未确定状态,不要虚构回应查询接口或保证重放能力。

核对日期:2026-10-16。

UnifyPort API

让消息接入变成一条稳定的产品管线。

先用统一 API 跑通发送,再用标准事件把所有入站消息接回业务系统。