Conversation Hub 统一会话
Conversation Hub 是网站客服、Telegram 作者/客服和后续 IM 渠道共用的会话协议。
首次接入请从客服接入指南开始。本页是接口概览,不代表生产验收完成。
联调 API 使用 https://staging-api.open4x.com,生产 API https://api.open4x.com 需单独验收开通。开始前应验证 API、Console 和 Widget 的自定义域名均可访问。
P0/P1 接入步骤
- 以业务系统的外部会话 ID 创建或更新会话。
- 由服务端签发短期 Widget Session。
- 绑定 Widget 渠道和 Telegram 作者/客服渠道。
- 注册事件 Webhook,先验 HMAC、按
event_id去重,再持久化到事件 inbox 并记录去重标记。 - 统一回复接口使用稳定的
client_message_id,需要引用时传reply_to_message_id。
API Key 和 Connected Account 只能保存在服务端,浏览器只能拿 Widget Session Token。
主要接口
| 方法 | 接口 | 用途 |
|---|---|---|
POST | /v1/conversations | 按外部 ID 创建或更新会话 |
POST | /v1/conversations/{id}/widget-session | 签发 15–60 分钟 Widget Session |
POST | /v1/conversations/{id}/channels | 绑定 Widget 或 Telegram 渠道 |
POST | /v1/conversations/{id}/messages | 发送公开消息或内部备注 |
GET | /v1/conversations/{id}/messages | 分页查询历史消息 |
GET | /v1/conversations/events | 租户级增量事件读取 |
POST | /v1/conversations/webhooks | 注册签名事件 Webhook |
POST | /v1/conversations/telegram/identities/bind | 创建一次性 Telegram 绑定链接 |
GET | /v1/conversations/credentials/status | 在不暴露密钥的情况下验证 API Key 策略 |
GET | /v1/conversations/inbox | 查询租户客服工作队列 |
PATCH | /v1/conversations/{id} | 更新状态、优先级或语言 |
POST | /v1/conversations/{id}/assignments | 分配或转接作者/客服 |
POST | /v1/conversations/{id}/participants | 增加或恢复会话参与者 |
PATCH | /v1/conversations/{id}/participants/{participantId} | 更新参与者状态或显示信息 |
DELETE | /v1/conversations/{id}/participants/{participantId} | 移除参与者并停用其渠道 |
POST | /v1/conversations/{id}/presence | 上线、输入中、离开、离线状态 |
POST | /v1/conversations/{id}/messages/{messageId}/receipts | 写入送达/已读回执 |
POST | /v1/conversations/deliveries/{deliveryId}/retry | 重试死信投递 |
GET | /v1/conversations/{id}/deliveries | 查询渠道投递状态和错误 |
POST | /v1/conversations/attachments/{attachmentId}/scan-result | 写入租户病毒扫描结果 |
API Key 按需使用 conversation:read、conversation:write、conversation:events:write。
Telegram 双向闭环
Knoveria 创建绑定链接,作者或客服打开 Bot 后,Open4X 产生 telegram.identity.started。Knoveria 再把该 Telegram Chat 绑定到目标会话。Telegram 入站消息只写入一次,投递时跳过来源渠道并实时推送到 Widget;反向也一样。
Telegram 私聊必须由用户先启动 Bot。Bot Token 保存在加密的 telegram-bot Connected Account 中,不进入浏览器。
telegram.identity.started 事件包含 binding_id、identity_id、 external_user_id、external_chat_id、telegram_user_id、 participant_id,以及事件信封中的 event_id 和会话内递增的 sequence。
运营与附件
分配使用 Knoveria 自有的作者或客服 ID,并且只在当前租户会话内生效。传入 replace_active_role: true 时,会先结束同角色的其他活动分配。在线/离开状态最长 120 秒,输入中最长 15 秒,建议由前端定时心跳。回执只允许 sent → delivered → read 单向推进。
附件只能传租户自己的 storage_key 或公开 HTTPS 下载地址,同时提供文件名、MIME 和大小。Open4X 不会主动抓取任意 URL。附件初始为 pending,由租户扫描服务调用 scan-result 标记为 clean 后,才允许渠道适配器暴露文件;当前文本投递链路不宣称所有渠道的二进制文件都已完整支持。
幂等和 Webhook
使用 client_message_id 处理网络重试:相同内容返回原消息,内容变化返回 409。内部备注必须使用 visibility: internal,永远不会投递给用户或作者。
Webhook 签名原文为 <unix_timestamp>.<raw_body>,请求头为 X-Open4X-Event-Signature: sha256=<hex>,时间戳头为 X-Open4X-Event-Timestamp。使用独立 Webhook Secret,不使用 Bridge API Key;SDK 默认接受 300 秒时间偏差。
总共最多投递 8 次,包含首次投递。七次重试分别在上次失败后至少等待 30、60、120、240、480、960、1920 秒;定时任务实际执行可能更晚,不承诺精确到秒。单次请求超时为 10 秒,仅 HTTP 2xx 视为成功。最终失败进入 dead_letter,使用 POST /v1/conversations/events/{eventId}/replay 重放,保持原 event_id。
所有渠道投递结果还会明确返回 environment 和 dry_run。当 dry_run=true 时只是模拟结果,不能视为 Telegram 已真实送达。
完整协议见 OpenAPI 和仓库中的 Conversation Hub 文档。
定向投递
公开消息支持三种范围:
| 模式 | 含义 |
|---|---|
all | 投递给会话中的所有活动渠道,兼容旧版本默认行为 |
direct | 只投递给 recipient_participant_ids 中的参与者 |
relay | 由客服中继给指定参与者,必须提供 relay_from_message_id |
订单会话建议使用 A(客户)→B(客服)、C(作者)→B 的路由。B 再明确 选择回复 A、C 或双方。Widget Session 可以携带 participant_id 和默认接收人, 浏览器不需要也不能自行选择其他参与者。
渠道绑定时应注明它代表的参与者:
{
"channel_type": "telegram",
"provider": "telegram",
"external_channel_id": "123456789",
"connected_account_id": "ca_...",
"participant_id": "part_creator_1"
}低代码 SDK
仓库 sdk/ 提供:
open4x-conversation-client.ts:服务端客户端;open4x-widget.ts:不暴露 API Key 的 Widget 挂载器;react/Open4XSupportWidget.tsx:React 组件封装;open4x-web-component.ts:适用于原生 HTML、Vue、Svelte 等框架的<open4x-support-widget>自定义元素。
客户只需要提供一个服务端 Session 接口。该接口验证登录用户和订单权限, 使用 Bridge Key 调用 Open4X,再返回短期 session_token。前端随后使用 sessionUrl 或正式 Widget Loader。
SDK 还提供 createWidgetSessionForContext,可以在一次服务端调用中完成会话 upsert 和 Session 签发。客户原有的订单或工单数据库不需要为 Open4X 增加专用 表,但仍应由客户自己完成业务授权和外部 ID 映射。
接入层级可以按项目选择:零构建页面使用托管 Loader;需要自定义按钮或界面时 使用浏览器 Controller;Vue、Svelte 或普通 HTML 使用自定义元素;React 项目使用 React 组件。它们共用同一套短期 Session 协议。
同一个 Conversation Hub 支持多方会话。可以加入 customer、creator 和 support_agent,把各自的 Widget 或 Telegram 渠道绑定到 participant_id, 再用 audience_mode: direct 实现 A/B、C/B 的定向消息。需要客服中继时,使用 relay 和 relay_from_message_id,由客服明确选择消息接收人。