已入驻服务商账号如何签约并集成支付宝 APP 支付 SDK?
结论
如果已入驻为支付宝服务商的账号无法直接签约商户收款产品,需要改用具备商户身份、且与实际收款主体一致的支付宝账号签约 APP 支付。
签约通过后,在支付宝开放平台创建或配置应用,并将应用与签约商户绑定。商户服务端通过支付宝开放平台接口生成支付订单,再由商户 APP 调用支付宝 APP 支付 SDK 拉起支付宝完成付款。
支付完成后,SDK 会把同步结果返回商户 APP,但这个结果不能作为支付成功的最终依据。最终支付状态必须以商户服务端的查询结果或支付宝异步通知为准。
为什么服务商账号无法直接签约
服务商账号主要用于帮助其他商户开发、代运营或提供技术服务,不等同于实际收款商户。APP 支付涉及商户主体认证、收款产品签约和资金结算,通常需要由实际收款主体对应的商户账号签约。
系统提示“需要更换账号签约”,一般表示当前账号的身份或主体不符合该收款产品的签约条件。修改 SDK 参数无法解决这个问题,因为 SDK 只负责拉起支付,不能代替商户签约或应用授权。
如果服务商需要为多个商户提供支付能力,应根据实际业务模式选择普通商户直连或服务商代商户接入。这两种模式的应用关系、授权方式、资金结算和接口参数不同,不能混用。
接入流程
1. 使用实际收款商户账号签约
退出当前服务商账号,改用符合以下条件的支付宝账号登录并签约:
- 账号已经完成企业或个体工商户认证。
- 认证主体与实际收款、结算主体一致。
- 账号具备对应收款产品的签约资格。
- APP 业务、经营类目和提交资料符合签约要求。
如果目前没有符合条件的账号,应由实际经营主体注册并认证商户账号。签约入口的名称和所需审核材料可能随开放平台调整,请以签约页面的实际展示为准。
2. 创建并配置开放平台应用
在完成签约的主体下创建移动应用,取得 app_id,并完成以下配置:
- 应用公钥或支付宝公钥模式;
- 应用私钥,由商户安全保存;
- 支付宝公钥或支付宝公钥证书;
- 应用包名、签名或 Bundle Identifier 等客户端信息;
- 服务端异步通知地址
notify_url; - APP 支付产品能力。
应用还需要按平台要求提交审核并上线。签约成功不代表任意应用都能立即发起正式支付,应用主体、产品签约关系和应用配置必须相互对应。
3. 在服务端创建支付订单
支付参数和签名必须由商户服务端生成。应用私钥、订单金额计算逻辑和签名过程都不能放进 APP。
下面的 Java 示例展示了服务端生成 APP 支付订单字符串的基本结构。具体的 SDK 版本、证书模式和初始化方式,应以项目实际使用的支付宝开放平台 SDK 为准。
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipay.com/gateway.do",
APP_ID,
APP_PRIVATE_KEY,
"json",
"UTF-8",
ALIPAY_PUBLIC_KEY,
"RSA2"
);
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
request.setNotifyUrl("https://example.com/api/alipay/notify");
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setSubject("订单商品名称");
model.setOutTradeNo("ORDER_202609130001");
model.setTotalAmount("99.00");
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
if (!response.isSuccess()) {
throw new IllegalStateException(
"创建支付宝支付订单失败:" + response.getSubMsg()
);
}
String orderString = response.getBody();
需要注意:
out_trade_no在商户系统内必须唯一。total_amount应由服务端根据订单计算,不能直接采用客户端上传的金额。notify_url必须是支付宝服务器可以访问的 HTTPS 地址。orderString是已经签名的支付参数。服务端应将它返回给商户 APP,再交由 APP 支付 SDK 使用。- 正式环境使用
https://openapi.alipay.com/gateway.do。沙箱环境有不同的网关和账号体系,不能与正式环境的配置混用。
4. APP 使用 SDK 发起支付
Android 端取得服务端返回的 orderString 后,可以调用 APP 支付 SDK:
Runnable payRunnable = () -> {
PayTask payTask = new PayTask(activity);
Map<String, String> result = payTask.payV2(orderString, true);
activity.runOnUiThread(() -> {
String resultStatus = result.get("resultStatus");
if ("9000".equals(resultStatus)) {
// 仅表示客户端返回成功状态,仍需向商户服务端查询最终结果
queryOrderFromMerchantServer();
} else {
// 取消、处理中或失败等情况,也建议由服务端核实订单状态
showPaymentPendingOrFailed(resultStatus);
}
});
};
Thread payThread = new Thread(payRunnable);
payThread.start();
iOS 端通常这样调用:
[[AlipaySDK defaultService]
payOrder:orderString
fromScheme:@"merchantAppScheme"
callback:^(NSDictionary *resultDic) {
NSString *resultStatus = resultDic[@"resultStatus"];
if ([resultStatus isEqualToString:@"9000"]) {
// 客户端结果不能作为最终入账依据
[self queryOrderFromMerchantServer];
} else {
[self showPaymentPendingOrFailed:resultStatus];
}
}];
fromScheme 必须与 iOS 工程中注册的 URL Scheme 一致,否则用户从支付宝返回商户 APP 时可能失败。SDK 的具体引入方式、平台权限和回跳配置,应按照所用 SDK 版本的接入说明处理。
5. 服务端接收异步通知
支付宝会向 notify_url 发送支付状态通知。商户服务端收到通知后,应按以下顺序检查:
- 使用支付宝公钥或证书验证签名。
- 检查
app_id是否属于当前应用。 - 检查
out_trade_no是否存在,并确认它对应正确的订单。 - 核对
total_amount、币种和商户身份是否与本地订单一致。 - 判断交易状态是否符合业务定义的支付成功条件。
- 以幂等方式更新订单,避免重复通知导致重复发货。
- 按接口要求返回成功响应。
示意代码如下:
Map<String, String> params = parseRequestParams(request);
boolean valid = AlipaySignature.rsaCheckV1(
params,
ALIPAY_PUBLIC_KEY,
"UTF-8",
"RSA2"
);
if (!valid) {
response.getWriter().print("failure");
return;
}
String outTradeNo = params.get("out_trade_no");
String tradeStatus = params.get("trade_status");
String totalAmount = params.get("total_amount");
String appId = params.get("app_id");
if (!APP_ID.equals(appId)) {
response.getWriter().print("failure");
return;
}
Order order = orderService.findByOrderNo(outTradeNo);
if (order == null || !order.getAmount().toPlainString().equals(totalAmount)) {
response.getWriter().print("failure");
return;
}
if ("TRADE_SUCCESS".equals(tradeStatus)
|| "TRADE_FINISHED".equals(tradeStatus)) {
orderService.markPaidIdempotently(outTradeNo);
}
response.getWriter().print("success");
这段代码只说明处理顺序。实际项目还需要检查通知中的商户身份、交易号等重要字段,并使用与项目 SDK 相匹配的验签方法。使用证书模式时,验签的初始化方式和参数也会不同。
6. APP 展示最终结果
用户从支付宝返回 APP 后,可以先显示“支付结果确认中”,再调用商户自己的订单查询接口:
GET /api/orders/ORDER_202609130001/payment-status
商户服务端根据本地订单状态返回结果。如果异步通知还没有到达,服务端可在必要时调用支付宝交易查询接口核实,然后向 APP 返回以下状态之一:
- 支付成功;
- 支付处理中;
- 支付失败或订单已关闭。
即使遇到网络中断、用户未正常回跳、客户端结果被篡改或异步通知延迟,商户仍可通过服务端确认并维护可靠的订单状态。
服务商参与开发时如何处理账号关系
服务商可以承担 SDK 集成和服务端开发工作,但收款能力必须归属于正确的商户主体。常见接入方式有两种:
- 商户直连:由商户账号签约并创建应用,服务商取得必要的开发权限后为商户完成接入。
- 服务商代商户接入:由服务商创建第三方应用,商户完成授权后,服务商根据授权信息代商户调用接口。
服务商代商户接入需要相应的平台能力和商户授权,不能简单地把服务商账号的 app_id 与商户账号的密钥组合使用。app_id、应用私钥、支付宝公钥或证书以及商户授权关系,必须属于同一套有效配置。
注意事项
- 客户端返回的
resultStatus=9000不能单独作为发货或记账依据。 - 私钥只能保存在服务端,不能写入 Android 或 iOS 安装包。
- 不要让客户端生成
out_trade_no、决定订单金额或拼接签名参数。 - 同一订单的支付通知可能重复到达,订单更新和发货操作必须保证幂等。
- 用户取消支付不代表订单一定没有支付,最终仍应以服务端订单状态为准。
- 正式环境与沙箱环境的应用、密钥、账号和网关必须配套使用。
- 更换签约账号后,需要重新核对应用所属主体、产品签约关系和密钥配置,不能继续使用原服务商账号下与新主体不匹配的参数。
- 如果页面允许提交签约,但审核未通过,应根据页面提示的主体、类目或材料问题进行处理。如果页面明确提示服务商身份不受支持,则需要改用实际收款商户账号,或申请符合业务模式的服务商代商户能力。
备注:内容仅供参考。
