PAYATHON 2026

服务商支付模式sdk与普通商户支付sdk是否相同?

支付老李

结论

服务商支付模式和普通商户支付模式通常可以共用一套前端、后端 SDK,无需因模式切换重新安装或完整重做 SDK 集成。

需要调整的主要是后端,包括身份配置、下单接口参数、签名和证书配置、回调处理及账务归属。前端是否需要修改,取决于支付平台是否改变了调起支付所需的参数结构。多数情况下,前端仍然只使用后端返回的支付参数,改动不大。

不同支付平台、支付产品和 SDK 版本可能有不同要求,具体应以对应平台的服务商模式接入文档为准。

为什么 SDK 通常可以复用

SDK 主要负责封装请求、签名、验签、序列化和网络通信。普通商户模式与服务商模式一般使用相同的通信协议,因此往往不需要更换 SDK 软件包。

两种模式的主要区别是交易主体:

  • 普通商户模式:商户使用自己的商户身份直接发起交易。
  • 服务商模式:服务商代表特约商户发起交易,请求中需要同时携带服务商和特约商户的身份信息。
  • 交易资金、账单、退款和回调通常归属于指定的特约商户。
  • 服务商需要使用平台分配的服务商凭证完成签名或鉴权。

所以,SDK 可以共用,并不代表代码和配置都能原样保留。

后端需要调整的内容

1. 更换服务商身份配置

将普通商户配置切换为服务商配置,例如服务商商户号、应用标识、私钥、证书或 API 密钥。具体字段名称由支付平台决定。

建议保留原有配置,并按支付模式分别管理:

payment:
  mode: service_provider

  direct:
    merchant_id: ${DIRECT_MERCHANT_ID}
    app_id: ${DIRECT_APP_ID}

  service_provider:
    provider_id: ${PROVIDER_ID}
    app_id: ${PROVIDER_APP_ID}
    private_key_path: ${PROVIDER_PRIVATE_KEY_PATH}

私钥、证书密码和 API 密钥不应写入代码仓库。

2. 改用服务商下单流程

服务商下单通常需要额外传入特约商户标识。下面的代码只用于说明组织方式,其中的字段名不能直接当作某个平台的真实 API 参数:

PaymentRequest request = new PaymentRequest();

request.setOrderNo(order.getOrderNo());
request.setAmount(order.getAmount());
request.setDescription(order.getDescription());

if (paymentMode == PaymentMode.SERVICE_PROVIDER) {
    request.setProviderId(config.getProviderId());
    request.setSubMerchantId(order.getSubMerchantId());
} else {
    request.setMerchantId(config.getMerchantId());
}

PaymentResponse response = paymentClient.createPayment(request);

需要逐项确认:

  • 服务商模式应使用哪个下单接口。
  • 是否必须传入特约商户号或子商户号。
  • 使用服务商应用标识还是特约商户应用标识。
  • 用户标识是否必须与指定应用身份匹配。
  • 使用服务商凭证还是特约商户凭证生成签名。

这些规则不能根据普通商户代码直接推断。

3. 调整回调验签与订单归属校验

切换模式后,回调验签使用的证书或密钥可能不同。验证签名后,还要检查回调中的商户身份是否与订单记录一致,防止不同特约商户之间串单。

public void handlePaymentNotify(String body, Map<String, String> headers) {
    PaymentNotification notification =
        paymentClient.verifyAndParseNotification(body, headers);

    Order order = orderRepository.findByOrderNo(notification.getOrderNo());

    if (order == null) {
        throw new IllegalArgumentException("Order not found");
    }

    if (!order.getSubMerchantId().equals(notification.getSubMerchantId())) {
        throw new SecurityException("Sub-merchant mismatch");
    }

    if (notification.isPaid()) {
        orderService.markPaidIdempotently(
            order.getOrderNo(),
            notification.getTransactionId()
        );
    }
}

示例中的类名和方法名仅表示代码结构,实际实现应使用目标支付平台 SDK 提供的接口。

4. 同步修改退款、查询和关单逻辑

改造范围不能只覆盖支付下单。以下操作通常也要使用相同的特约商户身份:

  • 查询订单
  • 关闭订单
  • 发起退款
  • 查询退款
  • 下载账单
  • 处理支付和退款通知

建议在本地订单中保存支付模式、服务商标识、特约商户标识和平台交易号。后续操作统一从订单记录中读取这些信息,不要依赖当前的全局配置。

前端是否需要重新集成

多数情况下,前端无需重新安装 SDK。前端仍然向业务后端请求支付参数,再调用原有的支付方法:

async function pay(orderNo) {
  const response = await fetch(`/api/payment/prepare?orderNo=${orderNo}`);
  const paymentParams = await response.json();

  return paymentSdk.pay(paymentParams);
}

服务商号、特约商户号和签名都应由后端处理,前端不应自行拼接或生成。

以下情况可能需要修改前端:

  • 服务商模式改用了不同的支付产品或调起接口。
  • 后端返回的支付参数结构发生变化。
  • 应用标识或用户授权主体发生变化。
  • 前端 SDK 版本过旧,不支持目标接口。
  • 支付场景从网页切换到小程序、App 或其他形式。

即使前端调用代码没有变化,也要验证后端生成的签名参数是否与当前应用、特约商户和用户身份匹配。

推荐切换步骤

  1. 确认服务商和特约商户已经完成平台要求的签约、授权或绑定。
  2. 检查现有 SDK 版本是否支持服务商模式使用的接口。
  3. 单独配置服务商凭证,不要与普通商户凭证混用。
  4. 修改下单、查询、关单、退款和账单接口中的商户身份参数。
  5. 更新回调验签配置,并校验特约商户归属。
  6. 保持前端只使用后端返回的支付参数。
  7. 在测试环境验证支付成功、取消支付、重复回调、退款和跨商户串单等场景。
  8. 上线时保留普通商户模式的回滚配置,不要一次性删除原有逻辑。

注意事项

  • 使用相同的 SDK 包,不代表普通商户接口可以原样用于服务商模式。
  • 服务商号和特约商户号不能互换。
  • 应用标识、用户标识和商户身份通常存在绑定关系,组合错误可能导致下单或调起支付失败。
  • 支付回调必须完成验签、金额校验、商户归属校验和幂等处理。
  • 多个特约商户共用一套系统时,应根据订单选择对应的商户配置,避免使用单一的全局商户号。
  • 是否需要升级 SDK,取决于当前版本是否包含服务商模式所需的 API,与 SDK 名称是否相同无关。

简而言之,切换到服务商支付模式通常可以复用 SDK,但需要调整业务接入。改造重点在后端,前端多数时候只需配合验证。是否完全不需要修改,仍要根据具体的支付平台和支付场景确认。

备注:内容仅供参考。