tgpay cryptoAPI
crypto-payapiwebhookssignature

API 参考:webhook

阅读约 1 分钟最后更新: 2026年8月11日

事件一发生,webhook 就把它推到您的服务器。在更多 → 商户 API里给您的应用设好 Webhook URL;此后您订阅的每一个事件,平台都会 POST 一段带签名的 JSON。

外层结构

{
  "update_id": 123,
  "update_type": "invoice_paid",
  "request_date": "2026-08-11T12:00:00Z",
  "payload": {  }
}

同一个事件重复投递时,update_id 保持不变——请拿它做去重。request_date 是每次投递尝试 各自打的。payload 是该事件类型的完整对象:账单类事件给账单对象,红包类给红包对象, 订阅类给订阅对象(各自的结构见对应的参考页面)。

事件类型

update_type什么时候触发Payload
invoice_paid账单被付掉——一定会投递账单对象
invoice_expired账单到了期限还没付账单对象
check_activated您的某个红包被领了红包对象
refund_completed一笔退款执行完成refunded_* 字段的账单对象
subscription_activated用户完成了套餐授权订阅对象
subscription_charged某一期扣款完成——charge.kind 说明是哪一种:initialrenewalresubscribe订阅对象加 charge{period_no, kind, asset, amount, fee, paid_at}
subscription_cancelled订阅被任意一方取消订阅对象
subscription_expired宽限期过完仍未付款订阅对象

invoice_paid 之外的一切都要主动订阅(这是相对 Crypto Bot 的扩展——严格照 Crypto Bot 写的消费端,除非您自己去开,否则永远碰不到一个陌生的 update_type)。请在商户 API 页面上 按应用去额外的 webhook 事件里开——这些开关在设好 webhook URL 之后出现,标签就是上表里 那些原样的标识符。

怎么验签

每次投递都带着 TgCryptoPay-API-Signature 请求头(Crypto-Pay-API-Signature 是取值 相同的兼容别名):对原始请求体做十六进制 HMAC-SHA256,密钥是您应用主 API 令牌的 SHA-256 摘要。这就是 Crypto Bot 那套方案,所以现成的验签代码原样就能用:

import hashlib, hmac

secret = hashlib.sha256(API_TOKEN.encode()).digest()
expected = hmac.new(secret, raw_body, hashlib.sha256).hexdigest()
ok = hmac.compare_digest(expected, headers["TgCryptoPay-API-Signature"])

请对收到的原始字节验签——重新序列化一遍的结果可能逐字节地不一样,验签就过不了。只有主 令牌签名;受限令牌永远不签。更换主令牌会立刻给 webhook 签名换密钥,所以请在同一次操作里 把服务器上的密钥也更新掉。

投递和重试

  • 10 秒内返回任意 2xx 就算投递成功。
  • 其余情况——错误状态码、超时、连接失败——都会以指数退避重试:第一次重试大约在 10 秒之后, 间隔翻倍直到 8 小时,最多 17 次,摊在大约 3 天里。
  • 最后一次尝试之后,这次投递就丢弃了。webhook URL 本身永远不会被自动停用——一个不稳的接收端 不会悄悄把您的应用退订掉。
  • 正因为有重试,您的处理逻辑必须是幂等的:处理之前先按 update_id 去重。

⚠️ 先验签,再发货

任何人都能往您的 webhook URL 上 POST。在签名校验通过之前,请把请求体当作不可信输入:别发货、 别给用户入账、别把什么标记成已付款。安全的顺序是:验签 → 按 update_id 去重 → 处理。