Webhooks
对话开始、转人工、结束、被评分,退款或补偿完成,收到新反馈时,purser 把签过名的事件 POST 到你自己系统的地址。
Webhooks 用来告诉你自己的系统 purser 里发生了什么。比如对话转人工时在你的 CRM 里开一张工单,或者把顾客评分记进数据仓库。purser 会向你指定的地址发 HTTPS POST,签名方式和退款接口相同。
添加接收地址
进入 接入 → Webhooks。只有店主和管理员能操作。
- 填写地址,必须是公网可以访问的
https://地址。 - 勾选要接收的事件。
- 点「添加」。签名密钥只显示这一次,请存进你服务器的环境变量,比如
PURSER_WEBHOOK_SECRET。 - 点「发送测试」。purser 会发一个签好名的
ping,页面上显示你的服务器返回的状态码。
每个工作区最多 10 个接收地址。每个地址都有:
- 启用:关掉后暂停投递;
- 更换密钥:新密钥同样只显示一次,旧密钥立刻失效;
- 投递记录:最近 30 次投递,每次都有状态和响应码。
事件
| 事件 | 什么时候 | data |
|---|---|---|
conversation.created | 新对话开始(任何渠道) | conversationId、channel、status、customerId、email、language、assignedUserId |
conversation.handoff | 对话开始等人:进实时队列(queued)或成为工单(awaiting_human) | 同上 |
conversation.closed | 对话结束 | 同上 |
conversation.rated | 顾客给对话打分 | conversationId、score(1–5)、comment、handledBy(ai 或客服的用户 ID) |
action.completed | 退款或补偿执行完(成功或失败) | actionId、kind(refund、coupon、points、replacement、exchange、address_change、order_cancel)、status(succeeded 或 failed)、orderId、customerId、amount、currency、conversationId |
feedback.created | 收到新的产品反馈 | feedbackId、number、body、categoryId、source、email、customerId |
customerId 是你自己系统里的顾客 ID,只有已识别的顾客才有;匿名访客是 null。
以下内容永远不会发送:
- 试聊里的对话;
- 被判定为不是顾客来信的邮件(营销邮件、平台通知、自动回复)。
请求格式
POST <你的地址>
content-type: application/json
user-agent: purser-webhooks/1
purser-signature: t=<unix 秒>,v1=<hex HMAC-SHA256(密钥, "<t>.<原始 body>")>
purser-event: conversation.handoff
purser-delivery: <投递 ID>{
"id": "<投递 ID>",
"event": "conversation.handoff",
"createdAt": 1790000000000,
"workspaceId": "<工作区 ID>",
"data": {
"conversationId": "01K…",
"channel": "web",
"status": "queued",
"customerId": "cus_mia",
"email": null,
"language": "en",
"assignedUserId": null
}
}验签方法和退款接口一样(见校验签名):
- 对收到的原始 body 计算;
t和你的服务器时钟相差超过 5 分钟就拒绝;- 用常量时间比较。
响应、重试和顺序
- 返回任何
2xx都算送达。其他状态码、超时(10 秒)或网络错误都会重试。 - 重试间隔依次是 1 分钟、5 分钟、30 分钟、2 小时、6 小时、12 小时、24 小时。试满 8 次后这次投递记为失败。
- 地址卡片上会显示连续失败了几次。重新启用这个地址会把次数清零。
- 同一事件可能送到不止一次,也可能乱序。用
id去重;判断状态以data.status和createdAt为准,不要看到达的先后。 - 请尽快响应,耗时的处理放到响应之后做。
- 投递记录保留 14 天。