如何在 Square Connect API 中处理定期付款?
结论
可以不发送 Square Invoice,直接完成周期性扣款。不过,旧版 Square Connect API 的 Checkout API 不能把订单定义为 recurring,也不能在 Checkout 请求中设置扣款日期或频率。
常见的实现流程如下:
- 首次付款时取得客户授权。
- 将银行卡保存为 card on file。
- 在自己的系统中记录订阅周期、下次扣款时间和订阅状态。
- 每个 billing period 到期后,由服务器调用支付接口扣款。
旧文档中的“支持 recurring payments”,通常是指商户可以使用已保存的银行卡发起后续扣款,并不代表 Checkout API 提供了完整的订阅调度功能。FAQ 和 API 文档看起来存在矛盾,往往是因为两者描述的功能层级不同,或者发布时间不同。
实现流程
1. 创建或识别客户
先在 Square 中创建 Customer,并在本地保存 Square 返回的 customer ID。不要只通过姓名或邮箱来关联客户。
2. 保存银行卡
使用 Square 提供的前端支付组件安全生成 card nonce/token,再由后端将银行卡关联到 Customer。
银行卡号、CVV 等原始卡片信息不应经过自己的服务器。一次性 nonce 也不能作为可重复使用的凭据。保存成功后,应使用 Square 返回的 card ID,或相应版本 API 提供的 card-on-file 标识。
保存银行卡前,还需要取得客户对后续周期性扣款的明确授权,并记录以下内容:
- 扣款金额或金额计算方式
- 扣款频率
- 首次扣款日期
- 取消方式
- 金额变化时的通知规则
3. 在业务系统中保存订阅计划
Checkout API 不处理周期调度,因此需要在自己的数据库中记录类似信息:
{
"customer_id": "CUSTOMER_ID",
"card_id": "CARD_ID",
"amount": 1999,
"currency": "USD",
"interval": "month",
"next_billing_at": "2026-09-01T00:00:00Z",
"status": "active"
}
interval、next_billing_at 和 status 是业务系统中的字段,并不表示 Checkout API 接受这些参数。
4. 到期时发起扣款
由定时任务、任务队列或账单服务查找已到期的订阅,再使用保存的卡片发起支付。
对于旧版 Transactions/Charge 风格的接口,请求结构大致如下:
curl -X POST \
"https://connect.squareup.com/v2/locations/LOCATION_ID/transactions" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"idempotency_key": "subscription_123_period_2026_09",
"amount_money": {
"amount": 1999,
"currency": "USD"
},
"card_nonce": "CUSTOMER_CARD_ID",
"reference_id": "subscription_123"
}'
这段代码展示的是旧版 Square Connect/Transactions API 的实现思路。具体字段能否继续使用,取决于账户采用的 API 版本。较新的 Square API 通常使用 Payments API,并通过 source_id 指定保存的 Card ID。例如:
const response = await squareClient.payments.create({
sourceId: cardId,
idempotencyKey: `subscription-${subscriptionId}-${billingPeriod}`,
amountMoney: {
amount: 1999n,
currency: "USD"
},
customerId,
referenceId: subscriptionId,
note: "Monthly subscription payment"
});
SDK 的初始化方式、方法签名和金额类型可能随版本变化,具体应以项目锁定版本的官方文档为准。
为什么不能只使用 Checkout API
Checkout API 主要用于创建一次性的托管结账流程。即使首次订单通过 Checkout 完成,该订单也不会因此在未来自动重复执行。
周期性付款还需要处理以下问题:
- 账单周期计算
- 夏令时和月末日期
- 扣款失败重试
- 卡片失效或更换
- 订阅暂停与取消
- 金额变更
- 重复任务和并发执行
- 客户通知与退款
因此,不能通过重复提交同一个 Checkout 来实现周期扣款,也不能重复使用一次性支付 nonce。
更合适的现代方案
如果当前 Square 账户和所在地区支持 Subscriptions API,可以优先评估这一方案。对于标准订阅业务,它通常比自行调度 card-on-file 扣款更合适,可以管理计划、订阅、阶段和周期账单。
它能否完全替代自建账单逻辑,还要看具体需求,包括:
- 所在国家或地区是否受支持
- 订阅金额是否固定
- 是否需要按使用量计费
- 是否需要复杂的试用、升级或按比例计费
- 是否需要关联现有订单系统
如果必须维护旧版 Square Connect 集成,采用“card on file + 每个 billing period 调用支付接口”的方式更符合该 API 的能力范围。
注意事项
- 每次扣款都必须使用唯一且可重复计算的
idempotency_key,避免任务重试导致重复扣款。 - 只有支付成功后才能推进
next_billing_at。支付失败时,应将订阅转入明确的重试或欠费状态。 - 不要无限重试被拒绝的付款,需要区分临时错误和永久拒付。
- 客户删除或更换银行卡后,需要同步更新订阅使用的 card ID。
- 保存银行卡并不等于自动取得周期扣款授权。授权记录和用户取消机制需要单独处理。
- API 文档中的 recurring payments 示例可能只是在说明如何通过 card on file 发起后续付款,不一定表示 Checkout API 支持声明式 recurring order。
- Square Connect、Transactions API、Checkout API、Payments API 和 Subscriptions API 分属不同阶段或承担不同职责。实施前,需要确认项目实际使用的 API 和 SDK 版本。
备注:内容仅供参考。
