定期付款

扣款授权、订阅与上限——一条没有直接扣款的链,如何照样按月计费。

区块链没有直接扣款。没有人能从钱包里拉取资金;转账总是由持有私钥的人主动推送。这正是定期扣款在这里必须解决的全部问题,而解决办法是链上的扣款授权

可以在哪些链上计费

要查询,不要假设GET /v1/chains 会公布每条链的 subscriptions_availableGET /v1/merchant/chains 会在你已配置的链上公布同一个标志。在该标志为 false 的链上创建扣款授权或订阅,会返回 400 并说明原因。

它与 escrow_available 是两个独立的答案,而且两者确实会不同:一条链可以不开放定期扣款,却依然能够完美地处理一次性付款。订阅中的每一次扣款都是一笔由本网关支付费用的链上交易,而这笔费用在不同链之间相差几个数量级——所以一个部署完全可以在所有链上处理付款,而只在更少的链上开放定期扣款。

已关闭的链上已有的订阅会继续计费。关闭一条链只会阻止新的订阅;不会取消任何东西。

扣款授权

扣款授权是客户在链上授予你的许可,允许你在上限之内、每个周期收取一次。客户只需在本网关托管的页面上,用钱包签名一次。

curl -X POST $PAYGATE/v1/mandates \
  -H "Authorization: Bearer $KEY" -H "Idempotency-Key: $(uuidgen)" \
  -H 'Content-Type: application/json' \
  -d '{"cap_decimal":"50.00","period":"month","customer":"…","reference":"acct_88"}'

你会得到一个 authorization_url。把客户引导到那里。客户签名后,会触发 mandate.authorized——而这个事件是你得知客户已签名的唯一途径。

客户向一个由他们自己控制的资金库存入资金。托管合约每个周期最多只能向你转出一次约定金额。本 API 上没有任何操作可以清空这个资金库,或改变资金的去向。这是合约本身的属性,而不是网关的承诺。

发起扣款

curl -X POST $PAYGATE/v1/mandates/{id}/charges \
  -H "Authorization: Bearer $KEY" -H "Idempotency-Key: $(uuidgen)" \
  -d '{"amount_decimal":"29.00"}'

可能出现四种情况:

扣款自身的 failure_code 也以同样的方式区分:insufficient_fundsapproval_exhausted。如果你在这里只根据一件事做分支处理,那就根据它。

charge.succeeded 表示资金已从客户那里转出,并不表示你已经收到。在托管暂存模式下,charge.released 才表示你已收到,charge.returned 则是另一种结局。如果用错了事件来触发履约,你就会在错误的时刻发货,而且永远查不出原因。

订阅:如果你还想让计费自动运行

扣款授权是授权本身。订阅则是按计划、基于商品目录来使用这项授权的机制:

  1. 产品——你销售的东西。
  2. 价格——产品的金额和计费频率。不可变更:没有 PATCH,也没有 DELETE,因为直接修改金额会在下一次计费时悄无声息地改变所有现有订阅者的价格。重新定价意味着创建一个新价格,并有意识地把订阅迁移过去。
  3. 订阅——一位客户对应一个价格。
curl -X POST $PAYGATE/v1/subscriptions \
  -H "Authorization: Bearer $KEY" -H "Idempotency-Key: $(uuidgen)" \
  -d '{"customer":"…","price":"…"}'

创建订阅会发起客户的链上授权,并返回一个 authorization_url,供你把客户引导过去。每到周期边界就会计费、触发 invoice.paid,然后进入下一个周期。

上限是任何人都无法替客户提高的天花板

这是与银行卡不同的地方,它会改变你的催缴通知需要说明的内容。

银行卡没有上限:折扣到期、方案升级或用量超额,都只是一笔更大的扣款。而在这里,这意味着金额要突破客户几个月前签名同意的额度——而提高这个额度,是一笔必须有人去请求客户发起的钱包交易

所以网关会提前发出警告:

处理好这三个事件,你的客户就能及时收到请求。忽略它们,客户第一次听说这件事,就是续费失败的时候。

演练

在测试模式下,签名就是一次调用:

curl -X POST $PAYGATE/v1/test/mandates/{id}/fund \
  -H "Authorization: Bearer $KEY" -H "Idempotency-Key: $(uuidgen)" \
  -d '{"amount_decimal":"500.00"}'

curl -X POST $PAYGATE/v1/test/mandates/{id}/authorize \
  -H "Authorization: Bearer $KEY" -H "Idempotency-Key: $(uuidgen)" -d '{}'

然后对它发起扣款,让它耗尽资金,并检查你的催缴流程是否做出了合理的处理。参见测试模式