支付宝老版即时到账接口返回 ILLEGAL_PARTNER 如何解决?
结论
ILLEGAL_PARTNER 表示支付宝无法将请求中的 partner 识别为当前接口的合法签约主体。
如果已经确认 partner 和 seller_email 填写无误,最常见的原因并非签名或回调地址,而是该 PID 未签约相关产品、没有调用权限,或已无法继续使用 create_direct_pay_by_user 这项旧版即时到账产品。签名有误时,支付宝通常会返回与签名有关的错误。重新生成 RSA 签名无法解决产品权限问题。
create_direct_pay_by_user 是旧 MAPI 接口,不适合新接入或已经迁移的商户。PC 网站支付通常应改用开放平台接口:
alipay.trade.page.pay
新接口以 app_id 标识应用,并通过以下网关调用:
https://openapi.alipay.com/gateway.do
某个历史 PID 能否继续调用旧接口,取决于商户原有合约、产品状态以及支付宝对存量接口的安排,不能只看账号是否正常。请以支付宝商家平台或开放平台后台显示的签约状态为准。
为什么会返回 ILLEGAL_PARTNER
旧 MAPI 网关收到请求后,会根据 partner 查询商户及其产品权限。以下情况都可能导致校验失败:
partner不是有效 PID,例如误填了开放平台的app_id、登录账号、商户号或其他编号。- PID 曾经有效,但没有签约“即时到账”产品。
- 即时到账合约已经失效、终止或迁移,旧接口权限也随之关闭。
- 请求混用了其他支付宝账号、应用或环境的密钥和 PID。
partner与seller_email不属于同一个支付宝收款主体。- 商户主体状态正常,但具体支付产品已被停用或限制。
- 测试环境参数被发往生产网关,或者生产参数被发往沙箱环境。
- 请求在拼接、编码或跳转时丢失、截断或重复传入了
partner参数。 - 使用服务商或子商户模式时,混淆了服务商 PID、商户 PID 和收款账号。
所以,支付宝账号能够正常登录或商户没有被冻结,并不代表该主体拥有 create_direct_pay_by_user 的调用权限。
与签名、回调地址的关系
notify_url 和 return_url 能否访问,通常不会引发 ILLEGAL_PARTNER。这两个地址主要影响支付完成后的异步通知和页面跳转。
RSA 签名问题需要单独排查,常见情况包括:
- 使用了错误的商户私钥;
- 支付宝后台配置的公钥与私钥不匹配;
- 完成签名后又修改了请求参数;
- 待签名字符串的排序、字符集或 URL 编码有误;
- 混用了应用公钥证书、公钥模式参数或支付宝公钥;
sign_type声明的算法与实际签名算法不一致。
不过,页面明确返回 ILLEGAL_PARTNER 时,应先核对 PID 和产品权限,不必把排查重点放在 notify_url、端口号或业务订单字段上。
建议按以下顺序排查
1. 确认 partner 的真实类型
旧接口中的 partner 应填写旧版合作伙伴身份 ID,也就是通常所说的 PID。不要填写:
app_id
支付宝登录邮箱
支付宝登录手机号
商户订单号
应用编号
还要检查最终发往支付宝的原始请求,确认:
- 请求中只有一个
partner; - 参数值前后没有空格;
- 没有使用脱敏值或配置占位符;
- 配置覆盖没有导致程序读取另一套环境参数。
2. 查询旧产品签约状态
进入支付宝商家平台或开放平台后台,检查对应主体的产品签约情况,主要确认:
- 是否签约过即时到账产品;
- 当前合约是否有效;
- 是否仍可调用
create_direct_pay_by_user; - 是否已经迁移到电脑网站支付;
- 收款主体是否与当前 PID 一致。
如果后台找不到旧产品,或者只能看到“电脑网站支付”,通常应直接迁移到新版接口。
3. 核对生产与沙箱环境
生产环境常用网关是:
https://openapi.alipay.com/gateway.do
开放平台沙箱有独立的沙箱网关、沙箱 app_id、沙箱账号和密钥,不能与生产环境参数混用。
旧 MAPI 请求使用的:
https://mapi.alipay.com/gateway.do
也不能仅替换为 OpenAPI 网关,然后继续发送 create_direct_pay_by_user。迁移时需要一并更换 API、参数体系和签名配置。
4. 核对收款方
旧接口中的 seller_email 必须属于对应的签约主体。如果商户后台提供了 PID、卖家账号或收款账号,应以后台信息为准,不要根据登录账号自行推断。
如果业务采用服务商代商户调用、子商户收款或特殊资金模式,还要确认接口是否要求额外的授权参数或收款参数。普通直连示例不能直接用于这些模式。
5. 检查实际发送内容
不要只查看代码中的参数对象,还要记录签名前的参数以及最终发出的请求参数。日志需要对敏感信息脱敏,但至少应保留:
service
partner 或 app_id
seller_email
out_trade_no
total_fee
sign_type
charset
gateway
还需留意 URL 中的中文、空格和特殊字符。参数应先参与签名,再按规则进行 URL 编码,不要对同一个参数重复编码。
6. 联系支付宝技术支持确认权限
如果 PID、收款账号和环境都没有问题,可向支付宝技术支持提供:
- 完整错误码;
- 请求时间;
- PID 的脱敏值;
- 接口名;
- 网关地址;
- 支付宝返回的请求流水号或错误页面截图;
- 商户后台显示的产品签约状态。
支付宝侧的产品权限、合约状态和存量接口白名单无法仅靠本地代码判断。
推荐迁移到 alipay.trade.page.pay
新版电脑网站支付以开放平台应用的 app_id 作为主要身份参数,不再主要依赖 partner 和 seller_email。接入前需要完成:
- 在支付宝开放平台创建应用。
- 为应用签约并开通“电脑网站支付”。
- 配置应用公钥或应用公钥证书。
- 保存对应的应用私钥。
- 使用
alipay.trade.page.pay创建支付页面。 - 在异步通知中验签,并在查询订单状态后更新业务订单。
常见的公共请求参数包括:
app_id
method=alipay.trade.page.pay
format=JSON
charset=utf-8
sign_type=RSA2
timestamp
version=1.0
notify_url
return_url
biz_content
sign
业务参数通常包括:
{
"out_trade_no": "20260518000027",
"total_amount": "100.00",
"subject": "账户充值",
"product_code": "FAST_INSTANT_TRADE_PAY"
}
金额建议使用十进制字符串。业务系统应使用最小货币单位或 BigDecimal 处理金额,不要直接用 double 计算。
Java SDK 示例
下面是常见的公钥模式写法。支付宝 SDK 的具体坐标、类名和构造方法可能随版本调整,请以当前官方 SDK 文档为准。
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.request.AlipayTradePagePayRequest;
public class AlipayPagePayExample {
private static final String GATEWAY =
"https://openapi.alipay.com/gateway.do";
private static final String APP_ID =
"你的应用APP_ID";
private static final String APP_PRIVATE_KEY =
"你的应用私钥";
private static final String ALIPAY_PUBLIC_KEY =
"支付宝公钥";
public static String createPayForm() throws Exception {
AlipayClient client = new DefaultAlipayClient(
GATEWAY,
APP_ID,
APP_PRIVATE_KEY,
"json",
"UTF-8",
ALIPAY_PUBLIC_KEY,
"RSA2"
);
AlipayTradePagePayRequest request =
new AlipayTradePagePayRequest();
request.setNotifyUrl(
"https://www.example.com/payment/alipay/notify"
);
request.setReturnUrl(
"https://www.example.com/payment/alipay/return"
);
AlipayTradePagePayModel model =
new AlipayTradePagePayModel();
model.setOutTradeNo("20260518000027");
model.setTotalAmount("100.00");
model.setSubject("账户充值");
model.setProductCode("FAST_INSTANT_TRADE_PAY");
request.setBizModel(model);
return client.pageExecute(request).getBody();
}
}
返回值通常是一段会自动提交到支付宝的 HTML 表单。服务端可以将其作为 HTML 响应返回给浏览器:
@GetMapping(value = "/pay", produces = "text/html;charset=UTF-8")
@ResponseBody
public String pay() throws Exception {
return AlipayPagePayExample.createPayForm();
}
应用私钥不能保存在浏览器端,也不能交给前端生成签名。
异步通知验签示例
支付结果应以服务端异步通知和主动查询为准,不能只依赖 return_url。
import com.alipay.api.internal.util.AlipaySignature;
import jakarta.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
public boolean verifyNotify(HttpServletRequest request) throws Exception {
Map<String, String> params = new HashMap<>();
for (Map.Entry<String, String[]> entry
: request.getParameterMap().entrySet()) {
String[] values = entry.getValue();
params.put(
entry.getKey(),
values == null ? "" : String.join(",", values)
);
}
return AlipaySignature.rsaCheckV1(
params,
ALIPAY_PUBLIC_KEY,
"UTF-8",
"RSA2"
);
}
验签通过后,还需要校验:
app_id 是否等于本系统配置的应用 ID
out_trade_no 是否存在且属于当前业务
total_amount 是否与本地订单金额一致
seller_id 是否为预期收款主体
trade_status 是否为允许入账的状态
订单是否已经处理,避免重复入账
业务处理成功后,按照支付宝协议返回:
success
如果业务处理失败,应返回失败结果,由支付宝按照通知机制重试。具体响应格式和重试规则请以当前官方文档为准。
迁移时容易遗漏的问题
partner不能直接作为app_id使用。- 不能假设旧版 RSA 密钥可以直接用于新应用。
- 新接口通常使用
RSA2,但必须与应用后台的实际配置一致。 seller_email一般不再是电脑网站支付的必填参数。- 旧接口的
total_fee在新版接口中改为total_amount。 - 不要把旧接口参数原样放入新版
biz_content。 out_trade_no必须在商户侧保持唯一。return_url只负责用户浏览器跳转,不能作为可靠的支付成功依据。- 异步通知可能重复到达,充值入账必须具备幂等性。
- 充值类业务还要确认其业务性质符合支付宝当前的产品和资金管理规则。
如果 PID 没有旧版即时到账权限,无论怎样调整签名、URL 编码或回调地址,都无法解决 ILLEGAL_PARTNER。应先确认旧产品合约。旧权限无法恢复或项目属于新接入时,应开通电脑网站支付并迁移到 alipay.trade.page.pay。
备注:内容仅供参考。
