Webhooks

SubHub 通过 Webhook 向你的服务端推送购买与权益变更事件。所有请求使用 HTTPS POST,带签名验证。

概述

当平台发生购买完成、退款、权益发放或撤销等事件时,SubHub 向你配置的 HTTPS 端点发送 POST 请求。

Webhook 在工作区(Workspace)级别配置 — 同一工作区下所有 iOS / Android 应用的事件统一投递,无需按应用重复配置。

这与 App Store / Google Play 的 Inbound 商店通知不同:后者按应用分配接收地址,由 SubHub 自动处理。

事件类型

事件触发时机
purchase.completed购买验证通过
purchase.refundedProvider 确认退款
purchase.pending购买已上报,待 Provider 确认
entitlement.grantedEntitlement 实例写入
entitlement.revokedEntitlement 失效
member.createdSDK 首次初始化
member.identifiedidentify() 关联身份

Payload 结构

purchase.completed
{
  "id": "evt_a1b2c3d4",
  "type": "purchase.completed",
  "created_at": "2026-06-27T18:32:00.000Z",
  "data": {
    "purchase": {
      "id": "pur_001",
      "member_id": "mem_001",
      "product_id": "prod_01PROMO",
      "provider": "apple",
      "status": "completed",
      "amount": 18,
      "currency": "CNY"
    }
  }
}

签名验证

每个 Webhook 请求包含 SubHub-Signature 请求头。使用 Webhook Secret 验证 payload 完整性。

签名算法:HMAC-SHA256,timestamp 防重放。

Node.js 验证示例
const crypto = require('crypto');

function verifySignature(payload, signature, secret) {
  const [t, v1] = signature.split(',').map(s => s.split('=')[1]);
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${t}.${payload}`)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(v1), Buffer.from(expected)
  );
}

重试机制

投递失败时,平台采用指数退避自动重试:1 分钟、5 分钟、15 分钟,最多 3 次。

你的端点应返回 2xx 状态码确认接收。非 2xx 响应触发重试。

可在 Webhook 详情页查看投递日志与重试历史。

最佳实践

  • 端点必须在 30 秒内响应
  • 先验证签名,再处理业务逻辑
  • 使用 idempotency — 同一 event id 可能重投
  • 异步处理耗时操作,快速返回 200
  • Staging 环境使用独立 Webhook 端点