NodeJS对接Stripe如何实现manual payout手动打款功能
Stripe 出行场景手动打款给司机的实现指引
你当前用Charges API实现的乘客扣款逻辑,资金默认会直接进入你的Stripe平台主账户,要实现给司机手动结算车费,按以下流程落地即可。
首先先修正你现有支付代码的冗余问题:创建Charge时不需要同时传customer和source参数,传已创建的customer ID后Stripe会自动调用该客户绑定的默认支付方式,重复传source容易触发参数校验错误,修正后核心扣款逻辑如下:
const customer=await stripe.customers.create({ name: req.body.name, email: req.body.email, source: req.body.stripeToken, address: { line1: '510 Townsend St', postal_code: '98140', city: 'San Francisco', state: 'CA', country: 'US', }, }) const charge=await stripe.charges.create({ amount: req.body.amount * 100, currency: "USD", customer: customer.id, description: "出行服务乘车费支付", receipt_email:req.body.email })
核心前提说明
乘客支付成功后,资金不会立刻进入可打款的可用余额,会根据你Stripe账户的结算周期(出行类美国账户一般是T+3)进入待结算状态,只有可用余额内的资金才能用来发起打款,不要在支付成功后立刻发起结算。
给司机打款有两种合规方案,根据你的业务复杂度选即可,优先推荐第一种。
方案1:Stripe Connect 转账(平台类业务官方推荐,合规风险最低)
这个方案不需要你直接操作打款到司机银行卡,Stripe会帮你处理KYC校验、打款到卡、税务申报等合规流程,适配出行服务场景。
实现步骤:
- 给每个注册司机创建Stripe Connect Custom账户,通过Stripe托管的表单引导司机提交身份信息、本地银行卡信息完成KYC审核,审核通过后每个司机对应一个唯一的
acct_开头的Connect账户ID,存在本地的司机表中 - 订单服务完成(乘客确认到达、无投诉)后,等对应订单的资金进入可用余额,调用Transfer接口把扣除平台服务费、通道费后的司机应得金额转到对应司机的Connect账户
- 你可以给司机的Connect账户设置自动打款规则(比如日结、周结),资金到账后Stripe会自动把钱打到司机绑定的银行卡,不需要你额外调用Payout接口
核心转账代码:
// 计算司机应得金额:总车费 - 平台服务费 - Stripe通道费 const driverAmount = Math.floor((order.totalAmount - platformFee - stripeFee) * 100) const transfer = await stripe.transfers.create({ amount: driverAmount, currency: "usd", destination: driver.connectAccountId, // 提前存储的司机Connect账户ID description: `订单${order.orderNo} 乘车费结算`, metadata: { order_id: order.id, driver_id: driver.id } })
配置webhook监听
transfer.paid事件,收到事件后再更新本地订单的结算状态,不要用接口同步返回结果作为最终结算成功依据,银行侧处理失败会通过事件回调通知。
方案2:直接发起Manual Payout到司机银行卡(适合小规模简单场景)
如果不想接入Connect,要直接从平台余额打款到司机银行卡,需要先满足两个前提:
- 提前向Stripe申请开通第三方打款权限:默认Stripe账户只允许打款到你自己绑定的对公/法人银行卡,给第三方个人打款需要提交业务场景说明,审核通过后才能使用
- 必须通过Stripe官方的安全组件收集司机银行卡信息,禁止自己在服务端存储银行卡号、CVV等敏感信息,收集后绑定为你Stripe账户下的外部收款方,拿到每个银行卡对应的
ba_开头的ID存在本地司机表
满足前提后,打款核心代码:
const payout = await stripe.payouts.create({ amount: driverAmount, currency: "usd", destination: driver.bankAccountId, // 提前绑定的司机银行卡ID description: `订单${order.orderNo} 司机结算`, method: 'standard', // standard为标准到账(3个工作日,无额外手续费);instant为即时到账(收1.5%手续费) metadata: { order_id: order.id, driver_id: driver.id } })
必做的校验和风控逻辑
- 打款前先查询账户可用余额,避免余额不足打款失败:
const balance = await stripe.balance.retrieve() const availableUsd = balance.available.find(item => item.currency === 'usd').amount if(availableUsd < driverAmount) throw new Error('可用余额不足,暂时无法结算')
- 所有打款必须关联真实的订单、司机服务协议记录,Stripe会不定期抽查资金流向,无真实业务背景的打款会触发账户冻结
- 配置webhook监听
payout.failed、payout.paid事件,同步更新结算状态,处理打款失败的退款、重试逻辑 - 如果采用手动Payout方案,年度给单个司机打款超过600美元时,需要自行给司机开具1099税表完成税务申报,Connect方案下Stripe会自动处理税表流程。
内容的提问来源于stack exchange,提问作者Haris Abbasi
相关产品推荐
相关产品推荐

