境外网站接入支付宝支付时API是否通用?
结论
境内版支付宝与面向境外商户的国际支付产品使用的支付 API 并不通用。
两者的签名机制、请求结构或支付流程可能相似,但产品权限、接口名称、网关地址、商户号体系、币种与结算方式、参数要求、异步通知和 SDK 配置都可能不同。境内接口代码通常不能只替换商户号,就直接用于境外网站。
国际版 API 应以支付宝国际业务的官方开发者中心为准,可从以下入口查找:
- 支付宝全球商户平台:
https://global.alipay.com/ - Alipay+ 开发者文档:
https://docs.alipayplus.com/
具体使用哪个入口,要看签约主体、收单机构和已开通的产品。如果服务商提供了专属接入门户或文档,应优先使用签约渠道提供的资料。
为什么不能直接共用
境内版与国际版主要有以下区别:
-
商户体系不同
境内接口通常面向中国境内的支付宝商户。国际业务可能使用全球商户账号、合作伙伴账号,或者由收单机构分配的商户标识。
-
支付产品不同
境内网站常用电脑网站支付、手机网站支付等产品。境外商户接入的可能是支付宝跨境支付或 Alipay+ 产品。即便用户最终通过支付宝付款,服务端调用的接口也未必相同。
-
网关与认证配置可能不同
接口域名、客户端 ID、商户私钥、平台公钥、证书和签名算法都要以对应产品文档为准,不能直接沿用境内环境的配置。
-
交易参数不同
国际业务通常还会涉及交易币种、结算币种、汇率、地区、收单市场和合规信息。境内接口中的某些参数,在国际产品中可能不存在,也可能有不同的含义。
-
退款和通知规则不同
支付查询、退款、撤销、关闭交易及异步通知的接口名称、状态值和验签方式也可能不同。
接入步骤
1. 先确认签约主体和目标市场
首先需要明确:
- 商户主体注册在哪个国家或地区;
- 网站主要面向哪些国家或地区;
- 用户使用支付宝还是其他 Alipay+ 钱包;
- 交易币种和结算币种;
- 由支付宝直接收单,还是通过第三方支付服务商收单。
这些条件决定了应该申请哪种产品,不能只看网站是否部署在境外。服务器位于境外,不代表一定要使用国际版。更重要的是商户主体、签约关系和实际业务场景。
2. 确认已经开通的支付产品
登录签约所用的商户平台,在产品列表或开发者配置中核对:
- 产品名称;
- API 文档入口;
- 测试环境和生产环境;
- 商户标识或客户端 ID;
- 支持的币种、国家和支付方式;
- SDK 及其版本要求。
如果还没有签约,应先联系支付宝国际业务或有资质的收单服务商,确认准入条件。
3. 按国际版文档创建应用
通常需要完成以下配置:
- 创建应用或商户接入项目;
- 获取商户标识;
- 配置密钥或证书;
- 设置支付结果通知地址;
- 设置支付完成后的跳转地址;
- 开通测试环境;
- 完成上线审核或申请生产权限。
不同产品的字段名称和操作流程可能不同,应以商户后台的实际页面为准。
4. 分别实现支付和回调验签
典型流程如下:
用户提交订单
↓
商户服务端创建支付请求
↓
跳转至收银台或调用支付组件
↓
用户完成付款
↓
支付平台向商户发送异步通知
↓
商户验签并主动查询交易状态
↓
更新订单并执行发货
不要只根据浏览器的跳转结果把订单标记为已支付。订单的最终状态应通过验签成功的异步通知确认,必要时还要调用交易查询接口核实。
代码示例
不同国际支付产品的接口名称和请求字段不完全一致。下面的代码只用于说明推荐的服务端结构。API_ENDPOINT、请求参数和签名规则必须替换成所签约产品文档中的实际值。
import crypto from "node:crypto";
function signPayload(payload, privateKey) {
const content = JSON.stringify(payload);
return crypto
.sign("RSA-SHA256", Buffer.from(content, "utf8"), privateKey)
.toString("base64");
}
async function createPayment(order, config) {
const payload = {
merchantOrderId: order.id,
orderAmount: {
currency: order.currency,
value: order.amount
},
paymentRedirectUrl: config.returnUrl,
paymentNotifyUrl: config.notifyUrl
};
const signature = signPayload(payload, config.privateKey);
const response = await fetch(config.apiEndpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Client-Id": config.clientId,
"Signature": signature
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`Payment API returned HTTP ${response.status}`);
}
return response.json();
}
代码中的 merchantOrderId、orderAmount、Client-Id 和 Signature 仅用于展示结构,不能据此判断它们适用于所有支付宝国际产品。开发时应直接使用官方 SDK,或者严格按照对应的 API 文档构造请求。
回调处理还需要完成验签、金额校验和幂等控制:
async function handlePaymentNotification(req, config) {
const rawBody = req.rawBody;
const signature = req.headers["signature"];
if (!verifySignature(rawBody, signature, config.alipayPublicKey)) {
throw new Error("Invalid payment notification signature");
}
const notification = JSON.parse(rawBody);
const order = await findOrder(notification.merchantOrderId);
if (!order) {
throw new Error("Order not found");
}
if (
notification.orderAmount.currency !== order.currency ||
notification.orderAmount.value !== order.amount
) {
throw new Error("Payment amount mismatch");
}
if (order.status === "PAID") {
return;
}
const payment = await queryPaymentFromProvider(notification.paymentId);
if (payment.status === "SUCCESS") {
await markOrderAsPaid(order.id, payment);
}
}
回调报文必须按照平台规定的方法验签。是否需要使用原始请求体、请求头的具体名称,以及代表交易成功的状态值,都应以实际产品文档为准。
注意事项
- 不要混用境内开放平台和国际商户平台生成的密钥、证书或商户号。
- 接口名称相似,不代表两套 API 可以互换。
- 金额应按文档规定的单位和精度处理,避免使用浮点数直接计算货币。
- 必须校验商户订单号、支付状态、金额和币种。
- 回调处理必须具备幂等性,避免重复通知导致重复发货。
- 测试环境与生产环境的网关、账号和密钥通常需要单独配置。
- 网站还要符合目标市场对隐私、税务、反洗钱和消费者保护的要求。
- 如果通过第三方收单机构接入,应使用该机构提供的 API,此时未必会直接调用支付宝官方接口。
接入时不应直接把境内版支付代码迁移到境外网站。应先确认签约产品,再根据对应的国际商户后台和官方开发者文档完成开发。
备注:内容仅供参考。
