← 全部教程

教程 4 / 9

创建结账,验证付款。

从后端创建发票并处理已验证付款通知。

完成后您将拥有

具备重试和重复保护的服务端付款流程。

1. 准备 ID 和访问权限

先准备已启用店铺和经过测试的付款方式。在 设置 → API 访问中创建仅限所需项目的读写凭据。将令牌保留在后端,切勿放入浏览器代码或公开仓库。

复制 项目 API ID 和 店铺 API ID ,位置为店铺的 基本 → API ID 区域。这些是 UUID,不是可读项目标识符或订单号。请使用自己的 API 主机名。

在 商店 → IPN中先创建签名机密,再提供 ipn_url。商户 VPS 必须能访问您的 HTTPS 接收器。

2. 创建发票

替换占位符,从后端发送此请求。金额使用十进制字符串,而不是浮点计算。

curl --fail-with-body --request POST \
  'https://api.example.com/v1/projects/YOUR_PROJECT_ID/stores/YOUR_STORE_ID/invoices' \
  --header 'Authorization: Bearer YOUR_MERCHANT_API_TOKEN' \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: order-1042-attempt-1' \
  --data '{
  "amount": "10.00",
  "currency": "EUR",
  "order_id": "order-1042",
  "description": "Example order",
  "ipn_url": "https://shop.example.com/payments/wholly-ipn",
  "metadata": {
    "cart_id": "cart-1042"
  }
}'

保存 data.invoice_id 到订单,然后将客户跳转至 links.checkout。新的付款尝试使用唯一幂等键。超时时使用以下内容重试: 同一凭据、键和完全相同的正文原始字节.

省略 payment_methods 会使用店铺接受的付款方式。可用链 slug 和代码为每张发票缩小范围;绝不会因此启用尚未接受的资产。 全部请求字段和响应示例 →

3. 选择 IPN、Webhook 或两者

IPN 跟随发票生命周期。设置店铺默认 IPN URL,或使用 ipn_url 为单张发票覆盖。 Webhook 让端点订阅所选事件,例如 invoice.settled.

两者使用相同签名格式,但 机密不同:IPN 使用店铺 IPN 机密,每个 Webhook 端点有独立机密。两者都不使用 API Bearer 令牌签名。

如果两者都向应用投递,通知可能重叠。不要为订单重复记账。

4. 验证并保存通知

  1. JSON 解析前读取准确的原始请求正文。验证 Wholly-Signature ,使用匹配机密并检查时间戳/重放。官方 SDK 提供验证器。
  2. 验证签名正文中的项目、店铺、发票和事件身份。未签名投递头不能作为认证来源。
  3. 用唯一标识持久保存事件: event_id,然后尽快返回 HTTP 2xx。订单交给后台工作进程处理。
  4. 从配置的 API 主机获取当前发票,而非请求中提供的任意主机。核对保存的项目、店铺、金额、币种和订单参考。

PHP · Python · JavaScript / TypeScript · 签名规范与接收器示例

5. 结算后仅履约一次

对于 基于事件的 接收器,处理 event_type = invoice.settled,然后验证当前的 status = settled 及异常处理策略。在数据库事务/唯一订单约束下,仅履约一次。

事件类型与状态不同

快速最终确认的链可能同时发送 payment.received 和 invoice.settled 搭配 status = settled。另一条链的 payment.received 仍可能显示 processing。两种流程都不是错误。

按以下字段为事件去重: event_id,不要仅用序列号:不同事件类型可能共用一个序列号。基于状态的 SDK 处理器则合并发票修订,忽略事件类型直接检查状态。 不要将这种合并与事件类型筛选混用。 两种方式都仍需订单级重复保护。

检查 requires_review 及手动处理结果后再履约。 amount_status = paid 本身不能证明确认。顶层已付资产字段概述结算; payment_info 包含详细收款和报价数据。 全部状态、事件及异常规则 →

6. 测试重试与恢复

测试小额付款、重复投递、过期发票和临时不可用接收器。事件重放不能让订单重复入账。处理乱序事件时,不要覆盖更新状态。

检查 商店 → IPN / Webhook → 历史 → 详情,或发票详情的投递区域。重发复用已记录事件,不是新的结算。

处理额度不足会暂停 IPN/Webhook,但付款继续。通过 API 核对未完成订单,并在恢复后处理保留的投递。切勿依据浏览器跳转或客户截图履约。