Webhooks 集成指南¶
当特定的礼品卡事件发生时,Gift Card Hero 会向你的服务器发送 HTTP POST 请求。使用 Webhooks 可以实时让外部系统与礼品卡活动保持同步。
设置¶
- 进入左侧导航中的 For developers
- 勾选 Enable REST API 并保存。只有在 REST API 开启时,Webhook 设置才会显示
- 点击 Generate Secret,生成 Webhook 签名密钥

密钥只会显示一次
请复制密钥并妥善保管。如果丢失,请点击 Regenerate Secret 生成新密钥。旧密钥会立即失效,因此也需要同时更新你的服务器。
- 为每个需要接收的 Webhook 类型输入端点 URL,然后点击保存栏中的 Save

新增或修改的端点 URL 必须以 https:// 开头,并指向可从互联网访问的服务器。私有网络中的地址(例如 localhost、127.0.0.1、10.x.x.x、192.168.x.x 等)在保存时会被拒绝。在此规则出台之前保存的 URL 会继续工作,直到你修改它为止,但只有在它指向公共地址时才会被调用。要对本地服务器进行测试,请通过 ngrok 等隧道将其暴露出来,并使用其提供的公开 https URL。
事件类型¶
Gift Card Hero 有三个 Webhook URL 字段:
| 事件 | Topic 请求头的值 | 触发时机 |
|---|---|---|
| Gift card order | gift_card_order |
Gift Card Hero 处理订单中的礼品卡。负载列出属于该订单的卡 |
| Gift card payment | gift_card_payment |
创建了一个全部或部分使用礼品卡付款的订单 |
| Gift card balance change | gift_card_balance |
目前不会发送 |
余额变动 Webhook
页面上有 Gift card balance webhook URL 字段,但 Gift Card Hero 目前不会发送此事件。目前若要跟踪余额变动,请轮询 GET /gift-cards/transactions,或对付款使用 gift_card_payment 事件。
只有在 Enable REST API 开启且该事件的 URL 已填写时,才会发送 Webhook。
投递¶
- 方法: POST
- 超时: 6 秒
- 尝试次数: 总共最多 5 次投递尝试(首次尝试加最多 4 次重试),延迟呈指数增长,初始约为 30 到 60 秒
- 重定向: 不会跟随。
3xx响应被视为投递失败,因此请使用端点的最终 URL。
如果你的端点在 6 秒内没有返回 2xx 响应,则视为投递失败,并会重试。
请求头¶
每个 Webhook 请求都包含以下请求头:
| 请求头 | 值 |
|---|---|
Content-Type |
application/json |
User-Agent |
GiftHero-Webhooks/1.0 |
X-GiftHero-Topic |
事件类型(例如 gift_card_order) |
X-GiftHero-Signature |
用于验证的 HMAC-SHA256 签名。仅在你生成了 Webhook 密钥时发送 |
签名验证¶
X-GiftHero-Signature 请求头包含一个 HMAC-SHA256 签名,采用十六进制编码,并以 sha256= 为前缀。
重要: 签名是针对负载正文中仅包含
{ type, timestamp }的 JSON 对象计算的,而不是整个请求正文。
验证步骤¶
- 解析请求正文,提取
type和timestamp字段 - 构造签名负载:
JSON.stringify({ type, timestamp }) - 使用你的 Webhook 密钥作为密钥,计算 HMAC-SHA256
- 将结果进行十六进制编码,并以
sha256=为前缀 - 使用恒定时间比较,将其与
X-GiftHero-Signature请求头进行比较
示例(Node.js)¶
const crypto = require('crypto');
function verifyWebhook(body, signature, secret) {
const signingPayload = JSON.stringify({
type: body.type,
timestamp: body.timestamp
});
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(signingPayload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
负载结构¶
每个请求正文都具有相同的外层结构。事件详情位于 data 中:
{
"type": "gift_card_order",
"timestamp": "2026-03-15T10:30:00.000Z",
"data": { }
}
礼品卡订单(gift_card_order)¶
{
"type": "gift_card_order",
"timestamp": "2026-03-15T10:30:00.000Z",
"data": {
"order": {
"id": 5551234567890,
"name": "#1042",
"email": "buyer@example.com",
"createdAt": "2026-03-15T10:30:00.000Z",
"lineItems": [
{
"id": 11198765432100,
"title": "Gift Card",
"quantity": 1,
"sku": "GC-50",
"variantId": 44556677
}
]
},
"giftCards": [
{
"id": 987654321,
"balance": "50.00",
"currency": "USD",
"lastCharacters": "ab12",
"initialValue": "50.00",
"customer": { "id": 123, "email": "buyer@example.com", "name": "Alex Buyer" },
"recipient": { "id": 456, "email": "friend@example.com", "name": "Sam Friend" },
"code": "abcd1234efgh5678",
"lineItemId": 11198765432100,
"sku": "GC-50"
}
]
}
}
礼品卡付款(gift_card_payment)¶
giftCards 中的每一项还会携带为该订单付款的 transaction。
{
"type": "gift_card_payment",
"timestamp": "2026-03-16T14:22:00.000Z",
"data": {
"order": {
"id": 5551234567891,
"name": "#1043",
"email": "shopper@example.com",
"createdAt": "2026-03-16T14:22:00.000Z",
"lineItems": [
{ "id": 11198765432200, "title": "Running Shoes", "quantity": 1, "sku": "SHOE-9" }
]
},
"giftCards": [
{
"id": 987654321,
"balance": "0.00",
"currency": "USD",
"lastCharacters": "ab12",
"initialValue": "50.00",
"customer": null,
"recipient": null,
"transaction": {
"id": "gid://shopify/OrderTransaction/123456789",
"amount": "50.00",
"currency": "USD",
"type": "debit",
"createdAt": "2026-03-16T14:22:00.000Z"
}
}
]
}
}
字段说明¶
data.order和data.giftCards是你应当依赖的字段。data顶层还会重复部分订单字段(orderId、orderName、orderEmail、createdAt、lineItems),并包含内部字段(storeId、shop、jobType)。请不要依赖这些字段。balance是构建 Webhook 时卡的余额,而不是下单时的余额。code是完整的礼品卡代码。仅当 Gift Card Hero 有该代码记录时才会包含,否则省略。请将其视为密码,并确保你的端点安全。- 当卡可以与订单行匹配时,会包含
lineItemId和sku。 lineItems条目包含id、title、quantity、sku和variantId(不含价格)。- 如果无法加载某张卡的详细信息,其条目会缩减为
id、零金额以及空的lastCharacters。遇到这种情况时,请通过 REST API 重新读取该卡。
最佳实践¶
- 尽快返回 2xx:立即确认收到 Webhook,并异步处理负载。超过 6 秒的响应会被视为失败。
- 处理重复项:由于重试,同一事件可能被多次投递。请使用事件数据中的订单和礼品卡 ID 进行去重。
timestamp是每次尝试的时间,因此不能作为稳定的键。 - 验证 HMAC 签名:在处理任何 Webhook 负载之前,务必验证
X-GiftHero-Signature请求头。拒绝签名无效的请求。 - 使用幂等键:将 Webhook 处理程序设计为幂等的,使同一事件处理两次的结果与处理一次相同。
- 监控失败:如果你的端点持续失败,Gift Card Hero 将在总共 5 次尝试后停止重试。请定期检查服务器日志和端点健康状况。