PAYATHON 2026

支付宝小程序能否使用扫一扫扫描付款码并调起支付?

支付小周

结论

支付宝小程序可以用 my.scan 扫码,也可以通过 my.tradePay 调起支付,但不能把扫描得到的付款码直接传入支付接口完成付款。

二维码中应只包含订单号、商品标识或一次性业务令牌。小程序扫码后,将相关信息发送给商户服务端。服务端创建支付宝交易并返回 trade_no,小程序再调用 my.tradePay 调起收银台。

为什么扫码结果不能直接用于支付

my.scan 只负责识别二维码或条形码,返回的是一段字符串,不会自动将扫码内容转换成可支付的订单。

my.tradePay 用于调起已经创建的支付宝交易。通常,服务端需要先通过支付宝开放平台接口创建订单,再把交易号返回给小程序。客户端不能根据任意二维码内容自行生成可信的交易。

这里还需要区分两种“付款码”:

  • 如果是用户支付宝中的付款条码,它通常由商户的收银设备扫描,再由商户服务端完成付款码支付。小程序不应扫描、保存或自行处理这类敏感付款凭证。
  • 如果是商户收款码或订单二维码,小程序可以读取其中的信息,但不能直接将扫码结果交给 my.tradePay。服务端应先验证二维码类型和业务数据,再创建对应的交易。

推荐实现流程

  1. 商户生成业务二维码,其中只包含订单标识或短期有效的随机令牌。
  2. 小程序调用 my.scan 获取扫码结果。
  3. 小程序将令牌发送到商户服务端。
  4. 服务端检查令牌的有效期、使用状态、金额及当前用户权限。
  5. 服务端调用支付宝交易创建接口,取得 trade_no。
  6. 小程序通过 my.tradePay 调起支付宝收银台。
  7. 支付结果以支付宝服务端异步通知或主动查询结果为准。

小程序端示例

以下示例中的接口地址、扫码结果字段和错误处理,需要根据实际项目以及当前支付宝小程序 API 文档进行调整:

Page({
  async scanAndPay() {
    my.scan({
      type: 'qr',
      success: async (scanResult) => {
        const token = scanResult.code;

        if (!token) {
          my.showToast({
            content: '未识别到有效二维码'
          });
          return;
        }

        try {
          const response = await this.createTrade(token);
          const tradeNO = response.tradeNO;

          if (!tradeNO) {
            throw new Error('服务端未返回交易号');
          }

          my.tradePay({
            tradeNO,
            success: (payResult) => {
              if (payResult.resultCode === '9000') {
                // 此处只能作为前端提示,不能作为最终入账依据
                my.showToast({
                  content: '支付已完成'
                });
              } else {
                my.showToast({
                  content: '支付未完成'
                });
              }
            },
            fail: () => {
              my.showToast({
                content: '支付调用失败'
              });
            }
          });
        } catch (error) {
          my.showToast({
            content: error.message || '订单创建失败'
          });
        }
      },
      fail: () => {
        my.showToast({
          content: '扫码失败或已取消'
        });
      }
    });
  },

  createTrade(token) {
    return new Promise((resolve, reject) => {
      my.request({
        url: 'https://api.example.com/payments/create',
        method: 'POST',
        data: {
          scanToken: token
        },
        success: (res) => {
          if (res.status === 200 && res.data && res.data.tradeNO) {
            resolve(res.data);
          } else {
            reject(new Error(
              (res.data && res.data.message) || '创建交易失败'
            ));
          }
        },
        fail: () => {
          reject(new Error('网络请求失败'));
        }
      });
    });
  }
});

服务端接口可返回如下结果:

{
  "tradeNO": "支付宝交易创建接口返回的交易号"
}

服务端不能直接采用客户端上传的金额。金额、商品信息和收款主体都应由服务端根据已经验证的订单或二维码令牌确定。

注意事项

  • 不要将用户付款码作为普通二维码采集、记录或上传。付款码是高敏感支付凭证。
  • 不要在扫描任意二维码后直接创建支付。应限制二维码的格式、签名、来源和有效期。
  • 业务令牌应设置较短的有效期,并且只能使用一次,以免因截图传播造成重复支付。
  • my.tradePay 的前端回调只表示客户端调用结果,不能作为发货、记账或发放权益的唯一依据。
  • 最终支付状态应通过支付宝异步通知并验签确认,必要时再调用交易查询接口核对。
  • 创建交易、私钥签名和异步通知验签都必须在服务端完成,不能把应用私钥写入小程序代码。
  • my.scan 和 my.tradePay 的具体参数及适用范围可能随基础库、应用类目和支付宝开放平台规则变化。接入时应以当前官方文档和应用的实际权限为准。

备注:内容仅供参考。