Webhook
业务事件发生时,平台向你配置的 HTTPS 地址发送 POST 请求,正文为 JSON。
配置入口在 APIHub 控制台 → Webhook 管理。
两类回调
在 Webhook 管理中可分别配置通知与扣费的 URL(也可共用同一个)。
| 类型 | 用途 | 事件 |
|---|---|---|
| 通知 | 订单、匹配、抢单、企业认证等业务消息 | 见下文通知类事件表 |
| 扣费 | 在你侧完成记账 / 扣款逻辑 | billing_deduct、billing_refund |
接入步骤
- 在「Webhook 管理」填写回调 URL,记下页面展示的平台出站 IP。
- 在你的接收服务 / 网关 / 防火墙中,将上述 IP 加入白名单。
- 实现接收路由:来源 IP 不在白名单内返回
403。 - 解析 JSON body,按
event字段分支处理,返回2xx。
请求头
| 头名称 | 说明 |
|---|---|
Content-Type | application/json |
X-Webhook-Event | 事件名,与 body 内 event 一致 |
X-Webhook-Timestamp | Unix 时间戳(秒),可用于日志关联 |
IP 白名单
Webhook 不使用签名密钥,通过 IP 白名单鉴权。平台出站 IP 在「Webhook 管理」页面查看。
本地联调时可将 127.0.0.1 加入白名单;经反向代理时,读取 X-Forwarded-For 或 X-Real-IP 中的真实来源 IP。
通用 JSON 字段
每条 Webhook 请求 body 均包含以下字段:
| 字段 | 类型 | 说明 |
|---|---|---|
event | string | 事件名称,如 order_matched、billing_deduct |
timestamp | string | 事件时间,ISO 8601,东八区,如 2026-04-08T23:30:00+08:00 |
short_code | string | 项目短链标识;企业认证类可能为 "" |
project_icon_url | string | null | 项目图标 URL |
target.client_user_id | string | null | 目标用户 ID(你系统中的终端用户 ID) |
通知类事件
事件列表
event | 说明 |
|---|---|
order_matched | 约单匹配成功 / 解锁相关通知 |
order_created | 抢单/派单下订单创建 |
order_grab_available | 有新的可抢订单 |
order_dispatched | 订单已派单 |
order_grabbed | 抢单成功 |
enterprise_authorization_pending | 企业员工发起加入申请,通知审批人 |
enterprise_authorization_approved | 审批通过,企业认领授权成功 |
额外字段(notification 对象)
| 字段 | 类型 | 说明 |
|---|---|---|
notification.title | string | 消息标题,可直接展示给终端用户 |
notification.content | string | 消息正文,可直接展示给终端用户 |
notification.link_url | string | 站内路径(以 / 开头),需拼接为完整 URL |
link_url 拼接说明
平台只下发站内路径,不含域名和 token。你需要:
- 拼上填单站根地址(见控制台「接入指南」)
- 为
target.client_user_id换取access_token,追加到 URL 末尾
js
let fullUrl = FORMFILL_ORIGIN + notification.link_url
// 保留 link_url 中已有的查询参数,在末尾追加 token
const sep = fullUrl.includes('?') ? '&' : '?'
fullUrl += sep + 'token=' + encodeURIComponent(accessToken)响应要求
返回任意 2xx 即可,平台不解析通知回调的响应体。
示例
POST /your-webhook-url HTTP/1.1
X-Webhook-Event: order_matched
{
"event": "order_matched",
"timestamp": "2026-04-08T23:30:00+08:00",
"short_code": "aB3kZ9",
"project_icon_url": "https://example.com/icon.png",
"notification": {
"title": "供方为您找到了5个匹配结果",
"content": "您提交的信息已成功匹配到5个结果",
"link_url": "/order/order-detail?short_code=aB3kZ9&submission_id=2"
},
"target": { "client_user_id": "u_10001" }
}扣费类事件
billing_deduct — 扣费
用户触发付费操作时推送。额外包含 billing 对象:
| 字段 | 类型 | 说明 |
|---|---|---|
billing.amount | string | 应扣金额,两位小数,单位元,如 "1.00" |
billing.reason | string | 扣费原因说明,可展示给用户 |
响应规范:
| 场景 | HTTP | 响应体 |
|---|---|---|
| 扣费成功 | 200 | {"ok": true} |
| 扣费失败(余额不足等) | 200 | {"ok": false} |
建议无论成功或失败均返回 HTTP
200,仅用ok字段区分,避免网络层误判。
billing_refund — 退款
管理员处理投诉选择退款时推送,与 billing_deduct 使用同一扣费回调 URL。收到后直接将 billing.amount 返还给对应用户余额,返回任意 2xx 即可(平台不解析响应体)。
事件路由示例
js
app.post('/webhook/billing', express.json(), (req, res) => {
if (!isAllowedIp(getClientIp(req))) return res.status(403).send('forbidden')
const { event, billing, target } = req.body
const { client_user_id } = target
const { amount } = billing
if (event === 'billing_deduct') {
const ok = deductUserBalance(client_user_id, parseFloat(amount))
return res.json({ ok })
}
if (event === 'billing_refund') {
refundUserBalance(client_user_id, parseFloat(amount))
return res.status(200).send('ok')
}
return res.status(200).send('unknown event')
})平台投递行为
| 项目 | 行为 |
|---|---|
| 重试 | 同一事件仅发送一次,无自动重试 |
| 多条配置 | 同一租户多条匹配 Webhook,顺序各发一次 |
| 超时 | 整体 10 秒;TCP 连接 5 秒 |
| HTTP 非 2xx | 视为未送达,不会重发,也不推失败类事件 |
| 网络错误 | 记 warn 日志,不排队重试,需业务侧自行补偿 |