跳到主要内容

用 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 解析器会改变字节,导致验签永远失败。

下一步