PAYATHON 2026

支付宝支付接口对接后提示“支付信息未匹配”怎么办?

支付阿杰

结论

“支付信息未匹配”通常不是支付宝统一定义的标准错误码,而是接入系统或业务控制台在校验支付配置、订单参数、回调数据时给出的提示。排查时,先确认以下内容完全一致:

  • app_id 是否属于当前支付宝应用
  • 支付宝网关是否对应当前环境,即沙箱或正式环境
  • 应用私钥、支付宝公钥和 sign_type 是否配套
  • 商户支付宝账号、seller_id 是否与签约主体一致
  • 回调中的 app_id、订单号、金额、收款方是否与原订单一致
  • 是否误将应用公钥当作支付宝公钥
  • 验签前是否修改、解码或重新拼装了回调参数

不同系统可能都会使用这句提示,因此还要结合支付宝返回的 code、sub_code、sub_msg,以及本地日志记录的具体校验失败项来判断原因。

常见原因

1. 沙箱和正式环境混用

沙箱应用的 app_id、密钥和支付宝账号只能用于沙箱环境,正式应用配置则必须请求正式网关。

正式环境:https://openapi.alipay.com/gateway.do
沙箱环境:https://openapi-sandbox.dl.alipaydev.com/gateway.do

常见错误包括:

  • 使用沙箱 app_id 请求正式网关
  • 使用正式环境密钥请求沙箱网关
  • 使用沙箱买家账号在正式环境付款
  • 部署后只修改了网关,没有同步修改密钥和应用编号

最好将 app_id、网关、应用私钥、支付宝公钥和测试账号作为一整套环境配置管理,避免逐项手动切换。

2. 公钥或私钥配置错误

支付宝开放平台通常会涉及三类密钥:

  • 应用私钥:由商户自行保存,用于请求签名
  • 应用公钥:上传到支付宝开放平台
  • 支付宝公钥:从开放平台获取,用于验证支付宝响应或回调签名

支付宝公钥和应用公钥不能互换。密钥格式也要与 SDK 的初始化方式一致。例如,有些 SDK 接收纯密钥内容,有些封装则要求使用 PEM 格式。

还要检查 sign_type。如果应用配置使用 RSA2,请求中也应使用:

sign_type=RSA2

不要用一套私钥签名,再配置由另一套应用生成的支付宝公钥进行验签。

3. app_id、商户账号或 seller_id 不一致

如果业务系统保存了支付宝账号、商户 UID 或 seller_id,这些值必须与当前应用和签约主体对应。

重点排查以下情况:

  • 切换支付宝应用后,数据库中仍保存着旧 app_id
  • 更换收款账号后,后台缓存没有更新
  • 服务商模式下混用了服务商应用和商户应用
  • 回调中的 seller_id 与订单预期收款方不一致

不能只根据支付宝登录邮箱或手机号判断收款主体。涉及 seller_id 时,应使用开放平台或支付宝返回的实际商户标识进行核对。

4. 商户订单号或金额不一致

收到支付回调后,业务系统通常会检查:

  • out_trade_no 是否存在
  • 订单是否属于当前商户
  • total_amount 是否与下单金额一致
  • 订单是否已经关闭、取消或支付
  • 支付币种和商品信息是否符合业务限制

金额比较不要直接使用二进制浮点数。例如,不建议这样写:

if (orderAmount == callbackAmount) {
    // 金额一致
}

Java 中可以使用 BigDecimal:

import java.math.BigDecimal;

BigDecimal orderAmount = new BigDecimal("99.90");
BigDecimal callbackAmount = new BigDecimal("99.90");

if (orderAmount.compareTo(callbackAmount) != 0) {
    throw new IllegalStateException("支付金额不一致");
}

也可以统一换算成”分”后用整数比较,但前提是业务接口确实以人民币元为单位,而且各处采用相同的换算规则。

5. 回调验签使用了错误的数据

支付宝异步通知验签需要使用支付宝实际提交的全部通知参数,并按照当前 SDK 的要求处理。常见问题包括:

  • 验签前对参数进行 URL 编码或二次解码
  • 将参数转换成 JSON 后再验签
  • 丢失空格、加号、中文或特殊字符
  • 只选取部分参数验签
  • 将业务系统重新组装的参数传给验签方法
  • 字符集配置与通知中的 charset 不一致

下面是 Java SDK 的一种典型处理方式。具体类名和方法参数应以项目实际使用的 SDK 版本为准:

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,
        String alipayPublicKey
) 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,
        alipayPublicKey,
        "UTF-8",
        "RSA2"
    );
}

验签通过只能说明通知来自对应的支付宝应用,不能替代订单金额、商户身份和交易状态校验。

6. 支付产品未签约或应用能力未配置完成

即使接口参数没有问题,如果应用尚未开通对应的支付产品,或者应用、商户与产品之间的签约关系不完整,也可能无法正常创建交易。

可以在支付宝开放平台核对:

  • 应用是否已上线,或是否处于允许调用的状态
  • 当面付、手机网站支付、电脑网站支付或 App 支付等产品是否已经签约
  • 当前接口是否属于已开通的产品
  • 签约账号是否与应用所属主体一致

具体可用能力取决于接入模式和商户签约情况。接口能够发起请求,并不代表相关配置已经全部完成。

推荐排查步骤

第一步:获取原始错误信息

记录支付宝接口响应中的以下字段:

{
  "code": "具体返回码",
  "msg": "具体描述",
  "sub_code": "具体业务错误码",
  "sub_msg": "具体业务错误说明"
}

不要只记录”支付信息未匹配”这一层业务提示。先确认这段文字来自支付宝响应、第三方支付插件,还是项目自身的订单校验逻辑。

日志中不要输出应用私钥、完整签名值、付款人敏感信息或其他凭证。

第二步:核对环境配置

列出当前运行环境的配置,并逐项比对:

alipay:
  gateway: "https://openapi.alipay.com/gateway.do"
  app-id: "当前正式应用的 app_id"
  sign-type: "RSA2"
  charset: "UTF-8"

重点确认这些值属于同一个应用和同一个环境。修改配置后,还要检查配置中心、容器环境变量和应用缓存是否已经刷新。

第三步:验证密钥关系

发送一笔最小金额的测试订单,依次观察:

  1. 请求能否成功签名;
  2. 支付宝能否正常返回;
  3. 同步响应能否通过验签;
  4. 异步通知能否通过验签。

如果请求阶段就返回签名错误,先检查应用私钥和签名参数。如果请求成功,但回调验签失败,则优先检查支付宝公钥、回调参数的读取方式和字符集。

第四步:逐项比对订单数据

回调验签成功后,再校验订单:

void validatePayment(
        PaymentOrder order,
        Map<String, String> notifyParams,
        String expectedAppId,
        String expectedSellerId
) {
    if (!expectedAppId.equals(notifyParams.get("app_id"))) {
        throw new IllegalStateException("app_id 不匹配");
    }

    if (!order.getOrderNo().equals(notifyParams.get("out_trade_no"))) {
        throw new IllegalStateException("商户订单号不匹配");
    }

    BigDecimal callbackAmount =
        new BigDecimal(notifyParams.get("total_amount"));

    if (order.getAmount().compareTo(callbackAmount) != 0) {
        throw new IllegalStateException("支付金额不匹配");
    }

    if (expectedSellerId != null
            && !expectedSellerId.equals(notifyParams.get("seller_id"))) {
        throw new IllegalStateException("收款方不匹配");
    }
}

这段代码只展示校验思路。实际项目还需要检查交易状态、币种、订单归属,并处理重复通知。

第五步:查询支付宝交易状态

如果本地订单与回调记录无法对应,可以使用订单查询接口,根据 out_trade_no 或支付宝交易号查询实际状态。查询时仍需使用创建该交易的应用和商户配置。

在查询确认之前,不要重复创建订单,也不要直接将本地订单改成”已支付”。

回调处理注意事项

支付宝可能重复发送异步通知,因此处理逻辑必须具备幂等性。建议按以下顺序处理:

  1. 使用支付宝公钥验签;
  2. 校验 app_id 和 seller_id;
  3. 查询本地订单并核对金额;
  4. 判断交易状态;
  5. 通过数据库事务更新订单;
  6. 处理成功后,返回支付宝要求的成功响应。

示例:

if (!verifyNotify(request, alipayPublicKey)) {
    return "failure";
}

validatePayment(order, notifyParams, appId, sellerId);

String tradeStatus = notifyParams.get("trade_status");
if ("TRADE_SUCCESS".equals(tradeStatus)
        || "TRADE_FINISHED".equals(tradeStatus)) {
    paymentService.markPaidIdempotently(
        notifyParams.get("out_trade_no"),
        notifyParams.get("trade_no")
    );
    return "success";
}

return "failure";

TRADE_SUCCESS 和 TRADE_FINISHED 应如何处理,要根据接入的支付产品和业务退款要求确定,不能只根据状态名称自行判断。

仍然无法解决时

如果配置、验签和订单校验都正常,需要继续确认提示产生在哪个环节:

  • 支付宝接口返回:根据 sub_code 和 sub_msg 排查
  • 第三方支付模块返回:检查模块中的商户绑定和环境配置
  • 项目控制台返回:搜索触发”支付信息未匹配”的业务校验条件
  • 回调阶段返回:记录具体失败项,例如 app_id、金额、订单号或收款方校验失败

定位时最有用的信息包括请求时间、接口名称、app_id、脱敏后的 out_trade_no、支付宝返回码和本地失败日志。提供这些信息时,不要提交应用私钥、完整授权令牌或其他敏感凭证。

备注:内容仅供参考。