Shopify 知识库 · 概念
Webhooks:订阅、校验与重试
说明 Shopify Webhooks 的订阅方式(应用配置文件与 Admin API)、投递目标、请求头与 HMAC 校验、响应时限与重试、去重与对账、强制合规 webhook,并区分它与前台 Web Pixels 事件、Flow 自动化以及开发者预览中的 Events。
Webhook 是 Shopify 在店铺里发生事件后主动通知应用服务器的机制,官方称其为“持续轮询店铺数据的高性能替代”。它解决的是“应用要及时知道订单、商品、客户等发生了变化”;不解决顾客在浏览器里的行为采集,也不保证每条事件必达。Webhooks 概览
本库哪些内容依赖它
- Admin GraphQL API:webhook 告诉应用“有变化”,拉取详情与对账用 Admin API;
- OAuth 回调指南:HMAC 校验的思路相同,但回调与 webhook 是两条链路、校验对象不同;
- 两个 App 共用后端:验签必须用接收该请求的 App 的 secret,
app/uninstalled与shop/redact的处理边界在那里; - App Review 准备:三个强制合规 webhook 的验收;
- 环境隔离:各环境的 webhook 入口应指向各自环境;
- 隐私与同意:商家在后台处理顾客数据请求,与应用侧合规 webhook 是同一件事的两端;
- Web Pixels、Flow:分工见下文。
本文是 webhook 机制的权威来源,其他文章只写各自页面语境下的用法。
核心对象与概念
| 对象 | 含义 | 备注 |
|---|---|---|
| Topic | 事件类型,如 products/create、orders/create | 参考页给出的示例;topic 总数官方页未写明 |
| 应用级订阅(app-specific) | 在 shopify.app.toml 声明,对所有安装该应用的店铺一律生效 | 随应用部署生效 |
| 店铺级订阅(shop-specific) | 经 Admin API 的 webhookSubscriptionCreate 创建,每店可不同 | 用 webhookSubscriptions 查询管理 |
| 投递目标 | HTTPS 地址、Amazon EventBridge ARN、Google Cloud Pub/Sub URI | Pub/Sub 格式 pubsub://{project-id}:{topic-id} |
api_version | 决定载荷的序列化版本,配置在 [webhooks] | 官方建议每季度更新到最新稳定版 |
| 合规 topic | customers/data_request、customers/redact、shop/redact | 见下文 |
| Events | 下一代订阅机制,支持字段级触发与自定义 GraphQL 载荷 | 开发者预览,见下文 |
在哪里配置
- 应用级:
shopify.app.toml中的[[webhooks.subscriptions]]。必填topics与uri;可选include_fields(限定载荷字段)、filter(过滤表达式,用于控制是否投递)、name(字母数字、-、_,最长 50 字符)、compliance_topics。写入[webhooks] api_version后部署生效。已部署订阅可在 Dev Dashboard 的 Versions > Configuration 中查看。 - 店铺级:Admin API 的
webhookSubscriptionCreate,以及webhookSubscriptions查询。 - 最小配置形态(官方页给出的示例形态,域名为虚构):
[webhooks]
api_version = "2026-07"
[[webhooks.subscriptions]]
topics = ["products/create"]
uri = "https://your-app.example.com/webhooks/products"
与主题、Liquid 和 API 的连接
- 与 Liquid 无关。 Webhook 是服务端到服务端的通知,不在店面运行,也不出现在主题里。
- 载荷形状。 投递体是所订阅 topic 的完整 REST 资源的 JSON;即使 Admin API 以 GraphQL 为主(见Admin GraphQL API),webhook 载荷仍是 REST 形。需要 GraphQL 载荷与字段级触发时看 Events。
- 请求头。 每次投递携带下表头(Delivery structure):
| 请求头 | 含义 |
|---|---|
X-Shopify-Topic | topic 名,如 products/update |
X-Shopify-Hmac-Sha256 | Base64 编码的 HMAC 签名,仅 HTTPS 投递 |
X-Shopify-Shop-Domain | 触发事件的 myshopify.com 域名 |
X-Shopify-API-Version | 序列化载荷所用的 API 版本 |
X-Shopify-Webhook-Id | 每次投递唯一的复合键,用于识别与去重单次投递 |
X-Shopify-Triggered-At | Shopify 触发该投递的时间戳 |
X-Shopify-Event-Id | 同一商家动作产生的所有投递共享的 ID |
X-Shopify-Name | 开发者在 name 字段给订阅起的名字(可选) |
限制、数值与易错点
核验于 2026-09-29,逐条标来源;数值会变,使用前重读来源页。
- 响应要快,且只有 2xx 算成功。 官方写明 Shopify 的连接超时为 1 秒,整个请求超时为 5 秒;用
200 OK确认收到,200 范围之外(包括 3xx)都算错误。所以处理器应先验签、落队列、立刻返回,再异步处理。HTTPS 投递 - 重试与自动删除。 无响应或错误时,Shopify 在之后 4 小时内重试 8 次;连续 8 次失败后,经 Admin API 创建的订阅会被自动删除。订阅页写明应用级订阅失败时不会被 Shopify 删除,店铺级会被删除。管理订阅。EventBridge 与 Pub/Sub 的重试策略两页均未读到,未核验。
- HMAC 校验步骤。 取
X-Shopify-Hmac-Sha256头;对原始请求体用应用的 client secret 计算 HMAC-SHA256;用 Base64 解码后的值做恒定时间比较;不一致就拒绝。官方特别写明:若在验签前用express.json()之类中间件解析了正文,就无法得到原始字节,验签中间件必须放在任何正文解析之前。若轮换 client secret,用新密钥生成摘要可能最长需要一小时生效,轮换后一小时内出现验签不一致时,先排除这一因素。验证投递 - 投递不保证必达,也不保证顺序。 官方写明 webhook 投递并不总是有保证,应用可能因处理器故障或停机而漏掉事件;Shopify 不保证同一 topic 内或跨 topic 的顺序。建议做对账任务,定期用
updated_at过滤从 API 拉取;排序用X-Shopify-Triggered-At或载荷里的updated_at。最佳实践 - 去重用哪个头。 最佳实践页写用
X-Shopify-Webhook-Id来忽略重复投递;Delivery structure 页把它描述为每次投递唯一的复合键,把X-Shopify-Event-Id描述为同一商家动作的所有投递共享的 ID。Event-Id 由同一动作的所有投递共享,所以它相同并不表示是重复投递,不能单独作去重键。Webhook-Id 在重试时是否不变,官方页未写明,未核验;落地前先在测试店对失败重试做一次观察,再决定去重键。 - 强制合规 webhook。 通过 Shopify App Store 分发的应用必须订阅三个 topic:
customers/data_request(顾客向店主请求其数据)、customers/redact(店主请求删除某顾客的数据)、shop/redact(店主卸载应用 48 小时后发送)。要求以 2xx 确认,并在收到请求后 30 天内完成对应动作;配置为compliance_topics = ["customers/data_request", "customers/redact", "shop/redact"];未提供或未按要求响应,审核会被拒。官方页表述的适用范围是 App Store 分发的应用;自定义分发与其他类型是否也必须订阅,该页未写,法规义务另需合规确认。隐私合规。webhook 参考页也写明:通过 App Store 分发的应用必须订阅这些强制 topic。 - 订阅的作用域。 应用级订阅对每个安装的店铺一视同仁;店铺间需要不同订阅时,只能用店铺级。同一 topic 同时存在两种订阅时是否会重复投递,官方页未写,未核验,去重逻辑不要假定不会。
- Events 仍在预览。 官方写明 Events 处于
unstableAPI 版本的开发者预览,只覆盖部分 topic,“测试可用,生产继续用 webhook”;它支持字段级triggers、query_filter与自定义 GraphQL 载荷,只能在shopify.app.toml配置;Events 与 webhook 可以在同一份配置里并存。Events 与 webhooks 对比
与 Web Pixels 和 Flow 的分工
| 机制 | 运行位置 | 触发 | 适合 |
|---|---|---|---|
| Webhook | Shopify 到应用服务器 | 店铺数据变化(订单、商品、客户等) | 服务端同步、通知、合规响应 |
| Web Pixels | 顾客浏览器的沙箱(App Pixel 为 strict,Custom Pixel 为 lax) | 顾客行为事件 | 前台采集,见 Web Pixels |
| Flow | Shopify 后台自动化 | 触发器(含订单、库存、客户等) | 无需自建服务的后台自动化,见 Flow |
三者不是同一条数据链路:webhook 不会替代 Pixel 的浏览器事件(顾客是否同意、页面是否加载都不在其中),Pixel 也拿不到只发生在后台的变化(如手动调整库存)。购买事件的验证见购买与事件验证,部署方式比较见标签与网关。Flow 中 HTTP 请求动作的行为本库尚未核验,本文不下结论。
验证一次
- 在开发店部署一个应用级订阅,触发一次对应事件,核对
X-Shopify-Topic、X-Shopify-Shop-Domain、X-Shopify-API-Version与配置的api_version一致; - 用错误密钥、被解析过的正文各发一次请求,确认验签都会失败,只有原始字节加正确 secret 才通过;
- 让处理器故意返回 500 或超过 5 秒,观察重试次数、间隔,并记录重试请求里
X-Shopify-Webhook-Id与X-Shopify-Event-Id是否变化(决定去重键); - 乱序与漏投用对账验证:停掉接收端一段时间后恢复,确认对账任务能按
updated_at补齐; - 三个合规 topic 各触发一次(触发或模拟方式官方页未读,未核验),确认 2xx 响应且删除动作可追溯;卸载后 48 小时的
shop/redact需另行跟踪。
待继续完善
- delivery filtering 的
filter表达式语法与限制; - EventBridge、Pub/Sub 的投递、重试与权限配置;
- 各 topic 的载荷字段与版本差异;
- Events 进入正式版后的 topic 覆盖与迁移路径。