用 Webhook 监听订单事件
订阅订单与履约 webhook,让应用随订单的生命周期流转而联动。签名校验、重试、请求头等通用机制在 Webhook 概述 里统一讲——本篇聚焦订单事件。
适用场景
同步订单状态、触发发货,或退款对账。
前置需求
- 一个已跑通 OAuth 的公开应用——先完成 开发独立应用。下面的每个请求都带
Access-Token: {token}头,使用你为每个店铺保存的 token。 - 先读 Webhook 概述。
订单生命周期事件
| Topic | 触发时机 | 参考 |
|---|---|---|
orders/create | 下单 | orders/create |
orders/paid | 支付完成 | orders/paid |
orders/fulfilled | 订单完全履约 | orders/fulfilled |
orders/partially_fulfilled | 订单部分履约 | orders/partially_fulfilled |
orders/cancelled | 订单取消 | orders/cancelled |
orders/refunded | 订单退款 | orders/refunded |
fulfillments/create | 创建履约 | fulfillments/create |
fulfillments/update | 更新履约 | fulfillments/update |
订阅
每个 topic 注册一条订阅——对上面列出的每个订单与履约 topic 都调用一次。从 2026-01 起,请求体要把订阅包在 webhook 对象里。
POST /openapi/2026-01/webhooks
请求体:
{
"webhook": {
"topic": "orders/paid", // 每个 topic 注册一条
"address": "https://your-app.example.com/webhook/orders-paid"
}
}
返回创建的订阅对象。版本差异与清理旧订阅见 Webhook 概述。
接收、验签与分发
对原始请求体验签,再按 topic 分发到其他指南里的操作。
const express = require('express');
const crypto = require('crypto');
const app = express();
function verifyWebhook(rawBody, hmacHeader, clientSecret) {
const digest = crypto.createHmac('sha256', clientSecret).update(rawBody).digest('base64');
return crypto.timingSafeEqual(Buffer.from(digest), Buffer.from(hmacHeader));
}
// 只在 webhook 路由挂 express.raw()——验签需要原始字节。
app.post('/webhook/:event', express.raw({ type: '*/*' }), async (req, res) => {
if (!verifyWebhook(req.body, req.get('X-Shoplazza-Hmac-Sha256'), CLIENT_SECRET)) {
return res.sendStatus(401);
}
const shop = req.get('X-Shoplazza-Shop-Domain');
const topic = req.get('X-Shoplazza-Topic');
const payload = JSON.parse(req.body.toString('utf8'));
// orders/* 带 order;fulfillments/* 带 fulfillment(含 order_id)
const orderId = payload.order?.id || payload.fulfillment?.order_id;
// ... 查该店铺 token、拉订单详情(见管理订单)、按 topic 联动 ...
res.sendStatus(200);
});
注意
对未解析的原始请求体验签。只在 webhook 路由挂 express.raw()——全局 JSON 解析器会改变字节,导致验签永远失败。