跳转到主要内容
请在 Business 头像菜单 → 开发者 → Webhook 中创建和管理 Webhook 端点。

验证公钥

获取并缓存 Anyway 的 Ed25519 公钥:
publicKey 是带前缀的原始公钥表示,keys 是等价的 JWKS 表示。投递信封遵循 Standard Webhooks,并使用非对称 Ed25519(v1a)签名。如果密钥轮换后验证开始失败,请刷新缓存公钥。

事件

当前事件包括: 端点未选择任何事件时,会订阅全部受支持事件,因此未选择事件的现有端点也会开始收到 refund.* 事件。 对不处理的事件类型请返回 2xx,或明确选择需要的事件。只有验证通过的 order.paid 才能触发履约。 周期末取消会通过 subscription.updated 报告;在 subscription.ended 之前,请使用 cancelAtPeriodEnd 和 currentPeriodEnd 表示计划取消状态。收到 fullyRefunded: true 的 refund.succeeded 时,请收回被退款订单授予的权益。部分退款(fullyRefunded: false)由你自己的 策略决定,多数商户会保留权益。

投递请求头与签名内容

签名覆盖以下精确字节序列:
解析 JSON 之前,必须使用原始请求体验证。请拒绝过期时间戳和未知签名。

验证 Ed25519 签名

载荷

签名后的信封包含 type、RFC 3339 timestamp、apiVersion、端点身份,以及与事件类型对应的 data.order 或 data.subscription。退款事件同时包含 data.refund 和被退款订单 data.order。 订单和订阅事件使用相同的 product 结构。例如,临时产品返回:
正式产品还会包含 product.id。名称只用于展示,不能作为权益标识。如果产品 ID 和名称都不存在,订单事件返回 product: null,订阅事件则省略 product。 重要订单字段包括: 如果付款链接包含 merchant_reference=PUR_456&user_id=USR_123&source=web,订单事件会返回 相同的值:
Webhook 签名覆盖包括 merchantMetadata 在内的完整原始请求体。签名验证只能证明载荷由 Anyway 投递,并不会让最初对买家可见的查询参数变成可用于授权的可信数据。 不要只根据 merchantMetadata、买家备注、电子邮箱或 URL 参数授权访问。请将订单、金额、币种、产品和关联值与你的服务端记录核对。

订阅载荷

订阅事件使用 data.subscription。重要字段包括:
merchantReference 和 merchantMetadata 属于订单载荷,不是 data.subscription 的字段。 需要首笔结账上下文时,请使用 subscriptionId 查询相关订单。

退款载荷

每笔退款最终只会发送一个事件:
  • 支付渠道确认款项已退回后发送 refund.succeeded。同一订单分两次退款会发送两个事件,各自带有 不同的 refundId。
  • 退款在 Anyway 审核中被拒绝,或处理时未能完成,发送 refund.failed,没有退回任何款项。
仍在等待审核的退款在有结果前不会发送事件。合计金额只统计通过 Anyway 发起的退款。 data.order 与订单事件中的订单对象相同,可用 orderId、merchantReference 或 subscriptionId 与你自己的记录匹配。
data.order.status 反映退款完成时的订单状态,全额退款后可能仍显示 PAID。请根据退款字段, 而不是订单状态,决定收回哪些权益。

投递行为

  • 持久化加入队列后快速返回 2xx。
  • 每次尝试的超时时间为 10 秒。
  • 网络错误、408、429 和 5xx 会重试。
  • 3xx,以及除 408、429 之外的永久性 4xx 不会重试。
  • 最多投递 12 次,指数退避最长一小时。
  • 429 和 503 的 Retry-After 会被采用,最长一小时。
  • 投递至少一次,事件也可能乱序到达。
使用 webhook-id 作为投递幂等键。不要让迟到的待处理(Pending)事件把本地 已支付(Paid)订单回退,也不要让更早的订阅更新覆盖较新的生命周期状态。
不要记录 Webhook 签名、API 密钥、完整付款信息、身份文件、提现账户信息或未脱敏的客户元数据。