PAYATHON 2026

Braintree 是否支持分期付款?

支付老李

结论

Braintree 通常不提供独立的“分期付款计划(installment plan)”功能。它的 Recurring Billing 主要用于订阅,也可以通过限定订阅的计费次数,模拟固定期数的分期扣款。

例如,业务要求“首期立即支付,之后每月扣款,共 12 期”时,通常需要:

  1. 创建按月计费的 Braintree Plan。
  2. 使用该 Plan 创建 Subscription。
  3. 在应用数据库中记录总期数和已支付期数。
  4. 达到约定期数后主动取消 Subscription。

Braintree 负责保存支付方式、定期发起交易并处理支付结果。分期合同、剩余本金、期数终止等业务规则,通常仍由商户系统管理。

为什么 Recurring Billing 不等于完整的分期付款

订阅和分期付款都可以表现为周期性收费,但两者的业务含义并不相同:

  • 订阅通常会持续提供服务,直到用户或商户取消。
  • 分期付款有固定总金额、固定期数和明确的结束条件。
  • 分期业务还可能涉及首付款、利息、提前结清、退款、逾期和监管要求。

即使使用 Subscription 完成周期扣款,也不能只依赖 Braintree 的订阅状态管理分期计划。商户系统还应保存并校验以下信息:

  • 分期订单 ID
  • 总金额
  • 每期金额
  • 总期数
  • 已成功支付期数
  • 下一扣款日期
  • 剩余应付金额
  • 分期状态
  • 对应的 Braintree Subscription ID

实现方式一:用 Subscription 模拟固定期数分期

先在 Braintree 控制台配置按月计费的 Plan,再使用客户的 paymentMethodToken 创建订阅:

const result = await gateway.subscription.create({
  paymentMethodToken: paymentMethodToken,
  planId: "installment-monthly-plan",
  price: "100.00"
});

if (!result.success) {
  throw new Error(result.message);
}

const subscriptionId = result.subscription.id;

假设订单总额为 1200.00,每月支付 100.00,共 12 期,应用端应同时保存类似的数据:

const installment = {
  orderId: "ORDER-10001",
  subscriptionId,
  totalAmount: "1200.00",
  installmentAmount: "100.00",
  totalInstallments: 12,
  paidInstallments: 0,
  status: "ACTIVE"
};

每次收到 Braintree Webhook 后,再根据实际事件更新付款记录。只有确认对应交易成功,才能增加已支付期数。

下面是简化后的示意代码。具体事件类型和字段应以当前 Braintree SDK 及官方文档为准:

const webhookNotification = await gateway.webhookNotification.parse(
  req.body.bt_signature,
  req.body.bt_payload
);

const subscriptionId = webhookNotification.subscription?.id;

if (isSuccessfulBillingEvent(webhookNotification.kind)) {
  const installment = await findInstallmentBySubscriptionId(subscriptionId);

  if (installment && !await eventAlreadyProcessed(webhookNotification)) {
    installment.paidInstallments += 1;

    if (installment.paidInstallments >= installment.totalInstallments) {
      const cancelResult = await gateway.subscription.cancel(subscriptionId);

      if (!cancelResult.success) {
        throw new Error(cancelResult.message);
      }

      installment.status = "COMPLETED";
    }

    await saveInstallment(installment);
    await markEventProcessed(webhookNotification);
  }
}

isSuccessfulBillingEvent 和幂等记录都属于业务层逻辑,这段示意不能直接当作完整的生产代码使用。尤其要先确认 Webhook 表示的是“已成功结算”“已提交结算”还是其他状态,再判断何时将该期标记为已支付。

实现方式二:由商户系统逐期创建 Transaction

如果每期金额或扣款日期可能变化,或者需要更精确地控制扣款次数,可以不使用 Subscription。商户系统可以保存客户的支付方式 Token,再通过定时任务逐期创建交易:

const result = await gateway.transaction.sale({
  amount: "100.00",
  paymentMethodToken: paymentMethodToken,
  orderId: "ORDER-10001-INSTALLMENT-03",
  options: {
    submitForSettlement: true
  }
});

if (!result.success) {
  throw new Error(result.message);
}

这种方式更灵活,但以下工作需要由商户自行完成:

  • 扣款调度
  • 重试策略
  • 失败通知
  • 期数计算
  • 幂等控制
  • 对账
  • 计划终止
  • 支付方式失效处理

不要保存原始卡号、CVV 等敏感卡数据。应使用 Braintree Vault 返回的 paymentMethodToken,并遵守适用的 PCI DSS 要求。

金额不能整除时的处理

总金额不一定能被期数整除。例如,将 100.00 分成 3 期时,如果每期都收取 33.33,最终合计只有 99.99。

金额计算应使用最小货币单位,以免出现浮点误差:

function splitInstallments(totalMinorUnits, count) {
  const base = Math.floor(totalMinorUnits / count);
  const remainder = totalMinorUnits % count;

  return Array.from({ length: count }, (_, index) =>
    base + (index < remainder ? 1 : 0)
  );
}

console.log(splitInstallments(10000, 3));
// [3334, 3333, 3333]

对于人民币,10000 表示 100.00 元,即 10000 分。不同货币的小数位规则可能不同,应按具体货币处理。

注意事项

不要只按时间自动增加已支付期数

进入下一个月,并不代表上一期已经支付成功。已支付期数应以实际交易结果为准,同时还要处理扣款失败、重试、拒付和退款。

Webhook 必须做幂等处理

同一通知可能因重试而多次送达。系统应使用能够稳定识别事件或交易的标识,避免重复记账,不能收到通知后直接执行 paidInstallments += 1。

完成最后一期后及时停止订阅

使用 Subscription 模拟分期时,必须设置可靠的终止机制,否则订阅可能在约定期数结束后继续扣款。取消失败时,还应触发告警和人工处理流程。

退款不等于减少一期

全额退款、部分退款和拒付都会影响剩余应付金额,但不能简单地折算成“少付一期”。订单账本应分别记录扣款、退款和争议交易。

分期能力可能因支付方式和地区而不同

部分地区或支付方式可能支持由发卡行、钱包或支付服务商管理的“先买后付”或卡分期。这类产品与商户通过 Recurring Billing 模拟分期并不相同。是否可用,取决于商户所在地区、账户配置、支付方式以及 Braintree 当前支持的产品。上线前,应查看最新官方文档,并向 Braintree 支持团队确认具体商户账户的支持情况。

选择建议

如果金额和周期固定,业务规则也比较简单,可以使用 Subscription,由应用记录分期期数,并在最后一期支付成功后取消订阅。

如果扣款日期、每期金额、重试方式或提前结清规则较复杂,更适合由应用逐期创建 Transaction。如果需要金融意义上的信用分期、利息计算或“先买后付”,应先确认 Braintree 在目标市场是否提供相应的支付方式,不要把普通 Subscription 当作完整的分期产品。

备注:内容仅供参考。