移动应用中有哪些支持 P2P 支付的 REST API 服务?
先区分两种 P2P 支付
支持 REST API 的支付服务不少,但选择之前要先确认所说的”P2P 支付”是哪一种:
- 平台型付款:乘客向司机付款,房客向房东付款。平台撮合交易,再向收款方分账或打款。Uber 和 Airbnb 主要采用这种模式。
- 个人之间直接转账:任意用户可以互相转账,功能类似电子钱包。这类业务通常涉及资金托管、余额账户、KYC、AML 和支付牌照,普通支付网关无法直接满足要求。
如果移动应用采用平台型付款,可以考虑以下服务:
| 服务 | 适合场景 | REST API 能力 |
|---|---|---|
| Stripe Connect | 市场平台、司机和房东结算 | 收款、分账、关联账户、提现、退款 |
| Adyen for Platforms | 跨地区大型平台 | 收款、账户验证、余额管理、分账和打款 |
| PayPal Commerce Platform | 商家平台、跨境付款 | 收款、合作方入驻、订单和退款 |
| PayPal Payouts | 平台向个人批量付款 | 单笔或批量打款 |
| Braintree | 移动端收款、PayPal 支付 | 支付方式保存、交易、退款 |
| Dwolla | 美国境内银行账户转账 | ACH 转账、客户验证、资金流转 |
| Wise Platform | 跨境汇款和多币种付款 | 收款人管理、报价、转账和状态查询 |
这些产品的开放范围、支持国家和准入条件可能发生变化。接入时应以服务商的当前文档和商务审核结果为准。
Uber、Hailo 和 Airbnb 使用什么服务
仅凭应用界面无法准确判断其支付服务商。大型平台通常也不会只使用一家供应商,而是根据国家、币种、支付方式和业务环节接入不同的支付渠道。
不同时期的公开资料曾把 Uber、Airbnb 等平台与 Braintree、Adyen 等支付服务联系起来,但这并不表示它们目前在所有地区都使用同一套方案。Hailo 后来还经历了品牌和业务调整,历史资料更不适合直接作为当前选型依据。
这类公司的支付系统一般包括:
- 用户付款;
- 平台计算佣金;
- 验证收款方身份;
- 记录司机或房东的余额;
- 延迟结算或按条件释放款项;
- 处理退款、拒付和争议;
- 支持多币种及本地支付渠道;
- 完成财务对账和税务报告。
支付服务商通常只负责其中一部分。订单、账本和风控系统仍然需要由平台自己维护。
推荐的实现方式
如果业务是”消费者付款,服务提供者收款”,应优先考虑 Stripe Connect 或 Adyen for Platforms 这类平台支付产品,不宜将交易设计为两个普通用户之间的直接转账。
常见流程是:
- 为司机、房东或其他服务提供者创建平台关联账户。
- 收集身份资料并完成 KYC。
- 由服务端创建支付订单。
- 移动端只负责确认支付,不保存密钥。
- 支付完成后,服务端根据订单计算平台佣金。
- 将应付金额记入内部账本,再通过服务商分账或打款。
- 使用 Webhook 更新支付、退款、争议和提现状态。
- 定期核对订单、内部账本和服务商账单。
如果应用允许用户向任意联系人转账,应先咨询支付机构或法律顾问。这类业务可能被认定为电子货币、汇款或资金转移服务,接入一个 REST API 并不能解决全部问题。
REST API 调用示例
以下是 Stripe Connect 的服务端请求示例。它会创建 PaymentIntent,并将部分信息关联到平台账户。具体应采用直接收款、目标账户收款,还是”先收款后转账”,需要根据业务责任、退款方式和账户所在地区决定。
curl https://api.stripe.com/v1/payment_intents \
-u "$STRIPE_SECRET_KEY:" \
-d amount=10000 \
-d currency=usd \
-d "automatic_payment_methods[enabled]"=true \
-d application_fee_amount=1500 \
-d "transfer_data[destination]"="$CONNECTED_ACCOUNT_ID" \
-d "metadata[order_id]"="order_123"
各字段的含义如下:
amount=10000表示 100.00 USD,金额以最小货币单位表示;application_fee_amount=1500表示平台收取 15.00 USD;transfer_data[destination]用来指定关联账户;metadata[order_id]用来关联业务订单。
服务端还需要验证 Webhook 签名,不能只相信移动端返回的”支付成功”状态:
import express from "express";
import Stripe from "stripe";
const app = express();
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
app.post(
"/webhooks/stripe",
express.raw({ type: "application/json" }),
(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(`Webhook Error: ${error.message}`);
}
if (event.type === "payment_intent.succeeded") {
const paymentIntent = event.data.object;
// 使用 paymentIntent.id 和 metadata.order_id 幂等更新订单状态
}
res.sendStatus(200);
}
);
具体字段和账户能力可能随 API 版本、国家及 Connect 收款模式而变化。正式开发时,应按照所选服务商当前的 API 文档进行调整。
选型时需要确认的问题
资金是否经过平台
如果平台先收款,之后再决定付给谁,这种资金路径可能构成资金托管。需要确认服务商是否允许这样处理资金,以及平台是否需要取得相应许可。
是否支持收款方所在国家
能够支持消费者付款,不代表当地个人也能成为收款方。以下条件需要分别核实:
- 付款人国家;
- 收款人国家;
- 结算币种;
- 银行账户类型;
- KYC 文件要求;
- 最长持款时间。
API 是否支持平台分账
普通的 Checkout、Payment 或 Card API 通常只能向一个商户收款。涉及司机、房东等多个收款方时,需要使用 Connect、Platforms、Marketplace 或 Payouts 类产品。
移动端如何保证安全
Secret API Key 只能保存在服务端。移动端应使用服务商提供的 SDK、短期令牌或 client secret,不能直接调用需要平台密钥的 REST API。
如何处理异步状态
银行卡支付、ACH 转账、提现和争议都可能异步完成。订单状态应由 Webhook 驱动,同时实现签名校验、事件去重、失败重试和幂等处理。
内部账本不能省略
支付服务商的余额不能替代业务账本。账本至少要记录:
- 应收金额;
- 平台佣金;
- 应付金额;
- 退款和拒付;
- 已结算与待结算金额;
- 服务费及汇率差额。
因此,类似 Uber 或 Airbnb 的应用更适合采用”平台支付产品 + 自有订单和账本系统”,而不是寻找一个通用的”P2P 转账 API”。对于多数初创项目,Stripe Connect、Adyen for Platforms、PayPal Commerce Platform 和 Dwolla 都是常见候选方案。最终应根据目标国家、资金路径、结算周期和合规责任作出选择。
备注:内容仅供参考。
