当网站发生特定事件时,Kanorio 可实时通知您的系统:买家付款、包裹出货或送达、访客提交表单、寄件域名失效、寄送额度用尽、流量突破里程碑等。通过连接 Zapier、Make、n8n 或您自建的程序,即可自动将数据写入电子表格、转发至团队聊天群组、建立客服工单,或同步至您的 ERP 与 CRM 系统。
您可在网站主控台的技术设置中的“串接”分页进行设置。Webhook 为商务版功能,仅限网站拥有者与管理员新增或管理;其他成员无法查看网址、密钥及推送记录。
每个网站最多可新增 5 个 Webhook。
展开每个端点后,皆可设置“订阅事件”:
目前支持的事件如下(字段细节请见文末“事件参考”):
| 事件 | 发送时机 | 事件代码 |
|---|---|---|
| 订单付款 | 买家完成付款时 | ec.order.paid |
| 货态更新 | 包裹出货、到店、送达或配送异常时 | ec.shipment.statusChanged |
| 表单回复 | 访客提交表单时,包含完整题目与答案 | customers.form.submitted |
| 寄件域名失效 | 寄件域名验证失败时 | customers.sendingDomain.degraded |
| 寄送额度提醒 | 额度用尽、自动加购、加购达上限或扣款失败时 | customers.messagingQuota.alert |
| 流量里程碑 | 网站累计浏览量突破 100、500 时 | site.analytics.milestone |
| 串接暂停 | Webhook 因连续失败被暂停时(不会发送至该端点) | customers.teamDestination.disabled |
| 测试事件 | 点击“发送测试”时 | team.test |
Webhook 的发送与否仅取决于此处的订阅设置。自动通知各情境面板虽会显示“N 个端点已订阅”或“尚未连接”,但开关控制权在于此处。
Webhook 不会取代寄给您的 Email。启用 Webhook 后,原本寄给拥有者的通知信(如新订单与表单回复)仍会正常发送;货态更新的团队 Email 默认是关闭的。若需调整团队 Email,请至“自动通知”设置。
展开每个端点即可查看“最近推送”记录:包含事件、结果、HTTP 状态与时间;展开单笔记录可查看尝试次数、耗时、下次重试时间与错误原因。7 天内的通知可“查看内容”以检视发送数据,亦可点击“重送”再次发送;重送将使用相同的通知编号,接收端可据此判断是否重复。
“发送测试”不会计入失败次数,排查问题时可放心多次测试。
Kanorio 会从固定的 IP 发送 Webhook。若您的接收端仅允许白名单来源,请将以下三个 IPv4 全部加入(首次发送、测试与手动重送来自前两个,自动重试来自第三个):
| 用途 | IP |
|---|---|
| 首次发送、测试、手动重送 | <MAIN_EGRESS_IP_1> |
| 首次发送、测试、手动重送 | <MAIN_EGRESS_IP_2> |
| 自动重试 | 168.144.105.51 |
白名单仅为额外防护,无法取代签名验证:请务必验证 X-Kanorio-Signature(详见下方“给工程师”)。若 IP 需变更,我们会先在此公告,并保留新旧 IP 并行一段时间后再移除旧 IP。
不会。Webhook 不经由 Kanorio 寄信,因此不计入 Email 寄送额度。
端点将暂停推送,设置与密钥将保留,列表上会标示"超出方案"。升级回商务版后即可立即恢复。
当接收端响应过慢或出错时,Kanorio 会进行重试;您亦可能手动重送。请使用 X-Kanorio-Delivery(或 JSON 中的 id)来判断是否已处理过该通知。
目前可先通过 Zapier 或 Make 转发:利用 Webhook 接收 Kanorio 的通知,再转发至 Slack 频道或 LINE。
Webhook 会将订单与表单答案发送至 Kanorio 以外的系统,因此网址与签名密钥仅拥有者与管理员可见。其他成员仅能查看端点名称与状态。
没有独立的沙盒环境。请使用"发送测试"确认连接,并透过"查看内容"检视真实事件发送的数据;开发阶段可先将端点指向 webhook.site 这类接收服务来观察格式。
每则通知皆为 POST 请求,Content-Type: application/json,并附带以下 header:
| Header | 内容 |
|---|---|
X-Kanorio-Event | 事件代码,与 JSON 中的 event 相同 |
X-Kanorio-Delivery | 通知编号,与 JSON 中的 id 相同;重试与重送时不变 |
X-Kanorio-Signature | 签名,格式为 t=时间戳,v1=签名;密钥轮替期间会有两个 v1 |
User-Agent | Kanorio-Notifications/1.0 |
接收端响应任何 2xx 即视为成功,响应内容不会被读取。请在 8 秒内响应;若需较长处理时间,请先回传 200 再进行异步处理。Kanorio 不会跟随重定向,3xx 将视为失败。
所有事件的 JSON 结构相同,接收端仅需设置一次:
{ "version": "1", "id": "3f9c2a…", "event": "ec.order.paid", "occurredAt": "2026-09-29T12:00:00.000Z", "websiteId": "cmk…", "title": "新订单 #1024,NT$1,280", "summary": "「我的商店」收到一笔已付款的订单。", "fields": [{ "label": "订单编号", "value": "#1024" }], "data": { "…": "依事件而异,见下方事件参考" }, "actionUrl": "https://app.kanorio.com/store/transactions?tx=…" }
| 字段 | 类型 | 说明 |
|---|---|---|
version | string | 目前为 "1"。仅新增字段不会变更版本号;移除或修改既有字段才会升版,并于此文章公告 |
id | string | 通知编号(32 码),与 X-Kanorio-Delivery 相同。重试与重送时不变,请用此字段进行去重 |
event | string | 事件代码,详见上方事件表 |
occurredAt | string | 事件发生时间,ISO 8601(UTC) |
websiteId | string | 网站 ID。同一个端点仅会收到建立该端点之网站的事件 |
title、summary | string | 依网站语系排版的一行标题与摘要,可直接转发至聊天群组 |
fields | array | { label, value } 数组,供人类阅读的细节(订单编号、金额、表单题目与答案等)。标签文字随网站语系变更,程序判断请使用 data |
data | object | 事件原始数据,不随语系改变。各事件字段详见下方 |
actionUrl | string | null | 回到 Kanorio 后台查看该笔数据的链接 |
以下为各事件的 data 字段。“可空”表示该字段可能为 null。
ec.order.paid 订单付款买家完成付款、订单成立时发送;每笔订单发送一次。
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
orderId | string | 订单 ID,与后台网址 ?tx= 相同 | |
orderNumber | number | ✓ | 人类可读的订单编号(例如 1024);极早期订单可能无此字段 |
amount | number | 买家支付总额(商品+运费),以该币别的最小单位计算(ISO 4217 minor unit):NT$1,280 为 128000、US$12.80 为 1280、日圆无小数则 ¥1,280 为 1280。换算显示金额请除以 10 的“小数位数”次方 | |
currency | string | ISO 4217 大写,例如 TWD、USD | |
itemCount | number | 品项数量 | |
customerName | string | ✓ | 买家姓名 |
customerEmail | string | ✓ | 买家 Email |
ec.shipment.statusChanged 货态更新出货单进入出货、到店、送达或配送异常时发送;同一张出货单的每个货态各发送一次。
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
orderId | string | 订单 ID | |
orderNumber | number | ✓ | 订单编号 |
shipmentId | string | 出货单 ID;一笔订单可能有多张出货单 | |
status | string | IN_TRANSIT(已出货)、AT_STORE(已到店)、DELIVERED(已送达)、EXCEPTION(配送异常) | |
carrier | string | 物流服务代码,例如 PAYUNI_LOGISTICS、MANUAL(卖家自寄) | |
trackingNumber | string | ✓ | 追踪号码/托运单号 |
storeName | string | ✓ | 超商取货的门店名称;宅配为 null |
customers.form.submitted 表单回复访客提交表单且通过垃圾判定时发送;每笔回复发送一次。
| 字段 | 类型 | 可空 | 说明 |
|---|---|---|---|
formId | string | 表单 ID | |
formName | string | 表单名称 | |
submissionId | string | 回复 ID | |
submitter | object | { name, email, phone },各字段可为 null;由表单内的姓名、Email、电话题目自动识别 | |
answers | array | 依题目顺序,每题一个对象(见下表) |
answers[] 的每一项:
| 字段 | 类型 | 说明 |
|---|---|---|
fieldId | string | 题目 ID,同一张表单内固定;请使用此字段而非 label 对应字段 |
type | string | 题型:short_text、long_text、email、phone、name、choice、date、time、rating、file |
label | string | 题目文字 |
value | string | string[] | number | null | 原始答案。单选为字符串、多选为字符串数组、评分为数字、日期时间为字符串(YYYY-MM-DD、HH:mm)、文件题为文件 ID(一个或多个);未填写为 null |
display | string | 人类可读字符串,与 fields 相同;文件题显示文件名 |
customers.sendingDomain.degraded 寄件域名失效已验证的自有寄件域名验证失效时发送;同一个域名每天最多发送一次。
| 字段 | 类型 | 说明 |
|---|---|---|
domain | string | 失效的寄件域名 |
customers.messagingQuota.alert 寄送额度提醒寄送额度状态变更时发送。
| 字段 | 类型 | 说明 |
|---|---|---|
reason | string | exhausted(本期额度用尽)、auto_upgraded(已自动加购一级)、auto_upgrade_limit(本期自动加购达上限)、payment_failed(加购费用扣款失败) |
quota | number | 本期额度(封) |
levels | number | 目前的加购级数 |
periodStart | string | 本期起算时间,ISO 8601 |
site.analytics.milestone 流量里程碑网站累计浏览量突破里程碑时发送,每个里程碑发送一次。
| 字段 | 类型 | 说明 |
|---|---|---|
milestone | number | 100 或 500 |
customers.teamDestination.disabled 串接暂停某个 Webhook 端点被自动暂停时发送(连续失败达门槛或接收端回传 410)。仅会发送至其他正常的端点。
| 字段 | 类型 | 说明 |
|---|---|---|
destinationId | string | 被暂停的端点 ID |
failures | number | 连续失败次数 |
lastError | string | 最后一次错误,例如 HTTP 503、超时 |
team.test 测试事件点击“发送测试”时发送,仅发送一次、不重试、不写入推送记录。
验证方式:
X-Kanorio-Signature 取出 t 与所有 v1。t、一个英文句点与原始请求内容(未经解析、重新序列化的 raw body)串接,例如 1790000000.{"version":"1",…}。v1 比对,相符才接受。Node.js 示例:
import { createHmac, timingSafeEqual } from "node:crypto"; function verify(rawBody, header, secret) { const parts = header.split(",").map((part) => part.split("=")); const t = parts.find(([key]) => key === "t")?.[1]; const signatures = parts.filter(([key]) => key === "v1").map(([, value]) => value); if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex"); return signatures.some( (v1) => v1.length === expected.length && timingSafeEqual(Buffer.from(expected), Buffer.from(v1)) ); }
Zapier、Make、n8n 等服务通常无处编写验证逻辑;其接收网址本身包含随机路径,通常不需额外验证签名。
签名密钥可在串接列表展开该端点后,点击“显示”查看。若怀疑密钥外流,请点击“产生新密钥”:
v1),任一相符即可。