如何选择支持客户直接向商户转账的 payment gateway?
明确结论
应选择面向平台业务的 Marketplace Payment / Platform Payment 方案,而不是普通的 payment gateway。常见产品有 Stripe Connect、Adyen for Platforms、PayPal Commerce Platform 等。
这类方案允许每个商户开通或绑定独立的收款账户。客户付款后,支付服务商负责扣款、身份验证、资金结算和商户入账,平台只需传递订单金额和收款商户标识。
不过,“平台完全不参与资金划转”可能有两种含义:
- 如果是指平台不保管资金、不提现,也不手工向商户转账,平台型支付方案可以实现。
- 如果是指平台既不创建支付,也不指定收款方,还不承担任何支付责任,那就只能让客户跳转到商户自己的收银台。统一的站内结账通常无法同时满足这些条件。
为什么普通 payment gateway 不适合
普通 payment gateway 通常只对应一个签约主体和一个结算账户。客户在网站付款后,资金先结算给该主体,再由平台自行分账或转账给商户。这样一来,平台就会介入资金处理,并可能面临以下问题:
- 商户入驻和身份验证;
- 分账、退款及拒付处理;
- 资金留存和结算周期;
- 税务、反洗钱及支付牌照要求;
- 商户之间的订单与资金对账。
Marketplace Payment 则会为每个商户建立独立的 connected account、sub-merchant account 或类似账户,由支付服务商处理 KYC/KYB、支付和结算。
推荐的实现流程
1. 确认平台的法律角色
先与支付服务商确认谁是交易中的商户主体,也就是 Merchant of Record。
如果每个入驻商户都是独立的收款主体,支付页面、订单信息和用户协议中应明确展示实际销售方。退款、拒付、税费和消费者投诉分别由谁承担,也要提前确定。
API 能实现“直接结算”,不代表平台一定没有合规责任。具体责任取决于国家或地区、商品类型、资金路径,以及平台与支付服务商签订的协议。
2. 为每个商户建立支付账户
商户注册平台后,应引导其完成支付服务商的开户流程。通常需要提交:
- 企业或个人身份信息;
- 银行账户;
- 联系方式和经营地址;
- 商品或服务类别;
- 税务信息;
- 实际控制人信息。
平台需要保存支付服务商返回的商户账户 ID,例如:
merchant_123 -> acct_xxxxxxxxxxxxx
银行卡号、CVV 或网银凭据不应保存在平台自己的数据库中。
3. 创建订单时指定收款商户
客户提交订单后,服务端根据商品所属商户找到对应的 connected account,然后创建支付。
下面是一个 Stripe Connect 风格的示例。具体字段和可用的资金流模式可能因账户类型、国家或地区而异,接入前应以当前官方文档和合同为准:
const paymentIntent = await stripe.paymentIntents.create({
amount: 10900,
currency: "cny",
payment_method: paymentMethodId,
confirm: true,
transfer_data: {
destination: merchant.stripeAccountId
},
metadata: {
order_id: order.id,
merchant_id: merchant.id
},
return_url: "https://example.com/payment/return"
});
其中:
amount使用最小货币单位;destination指向实际收款商户;metadata只保存订单标识,不能放置敏感数据;- 是否支持
cny、特定付款方式和目标结算地区,需要根据服务商实际开放的范围确认。
如果平台需要收取佣金,可以在服务商允许的模式下设置平台服务费,例如:
const paymentIntent = await stripe.paymentIntents.create({
amount: 10900,
currency: "usd",
application_fee_amount: 900,
transfer_data: {
destination: merchant.stripeAccountId
},
metadata: {
order_id: order.id
}
});
平台不收佣金时,可以不设置 application_fee_amount。但这不代表平台一定不承担支付手续费、退款或拒付责任。相关责任由所选账户和交易模式决定。
4. 使用 Webhook 更新订单
不能只根据浏览器的跳转结果判断支付成功。客户可能在跳转前关闭页面,回调请求也可能被伪造。订单状态应由经过签名验证的支付服务商 Webhook 更新:
app.post(
"/webhooks/payment",
express.raw({ type: "application/json" }),
async (req, res) => {
let event;
try {
event = stripe.webhooks.constructEvent(
req.body,
req.headers["stripe-signature"],
process.env.STRIPE_WEBHOOK_SECRET
);
} catch (error) {
return res.status(400).send("Invalid webhook signature");
}
if (event.type === "payment_intent.succeeded") {
const paymentIntent = event.data.object;
await markOrderAsPaid(paymentIntent.metadata.order_id);
}
if (event.type === "payment_intent.payment_failed") {
const paymentIntent = event.data.object;
await markOrderAsFailed(paymentIntent.metadata.order_id);
}
res.sendStatus(200);
}
);
Webhook 处理必须保证幂等。同一个事件即使重复到达,也不能导致重复发货或重复记账。
多商户购物车需要特别处理
如果一个订单中包含多个商户的商品,并非所有服务商和地区都支持“一次付款直接进入多个商户账户”。通常有三种处理方式:
- 按商户拆成多笔支付;
- 由支付服务商先记录平台交易,再按规则拆分结算;
- 平台作为统一销售主体收款,再向各商户付款。
采用第三种方式时,平台通常会更深地介入资金流,也可能承担更多合规责任。如果“不经手资金”是硬性要求,应优先考虑前两种方式,并确认相应的客户体验、退款方式和手续费是否可以接受。
选型时应重点询问的问题
选择支付服务商时,以下问题比单纯比较 API 更值得关注:
- 是否支持 marketplace、connected accounts 或 sub-merchants;
- 是否覆盖平台和商户所在的国家或地区;
- 商户能否直接结算到自己的银行账户;
- KYC/KYB 由谁完成;
- 平台是否会接触或控制资金;
- 支付手续费由平台还是商户承担;
- 退款、部分退款和拒付由谁处理;
- 是否支持将单笔订单分账给多个商户;
- 是否支持平台佣金;
- 商户退出或账户受限时,未完成订单如何处理;
- 是否提供托管式开户页面和托管式收银台;
- 是否满足 PCI DSS、强客户认证和当地监管要求。
减少支付问题的建议
优先使用支付服务商提供的托管式商户开户和托管式收银台,不要自行采集身份材料或银行卡数据。这样可以缩小平台需要承担的安全和合规范围。
平台仍然需要维护订单与支付状态的映射,并处理重复回调、支付超时、退款、拒付和商户账户暂停等异常。支付服务商可以代管资金并完成账户验证,但无法替代平台自身的订单管理。
因此,合适的做法不是寻找一个能够“自动把钱转给任意商户”的普通网关,而是接入正规的 Marketplace Payment 产品。最终选择取决于业务所在地区、商户类型、多商户购物车需求,以及合同约定的责任归属。
备注:内容仅供参考。
