微信支付调用手册

按商户订单号查单并验证响应

用自己的商户订单号取得支付状态,完整演示 RSA 请求签名与响应验签。

官方资料核对 2026-10-15示例代码,未进行真实接口实测
← 返回平台功能

接入准备

  • 已完成中国大陆普通商户入驻、签约与对应支付产品配置,且查询自己的已有订单或退款单。
  • 管理员在商户平台 账户中心 → API 安全 申请商户 API 证书并保管私钥,记录对应证书序列号。
  • 本例使用微信支付公钥模式:在同一 API 安全页面申请并下载公钥,记录 PUB_KEY_ID;平台证书模式不能直接套用本例。
  • 安装 Node.js 22,把密钥与公钥材料放在服务端受保护目录;不要上传到本网站或浏览器。

准备环境变量

示例值需要替换为自己的凭证或资源 ID。代码在本机或服务端运行;密钥不应放进公开网页。

WX_MCH_ID
普通商户号,在商户平台获取;不是 AppID。
WX_MCH_SERIAL
商户 API 证书序列号,对应下方私钥;不是微信支付公钥 ID。
WX_PRIVATE_KEY_PATH
自己服务器上商户 API 证书私钥 apiclient_key.pem 路径。
WX_PAY_PUBLIC_KEY_ID
API 安全页申请下载的微信支付公钥 ID,必须匹配当前验签公钥。
WX_PAY_PUBLIC_KEY_PATH
同一 API 安全页下载的微信支付公钥文件路径,事先可信配置。
WX_OUT_TRADE_NO
自己下单时保存的 out_trade_no,不是微信 transaction_id。
终端
export WX_MCH_ID='1900000001'
export WX_MCH_SERIAL='REPLACE_WITH_MERCHANT_CERT_SERIAL'
export WX_PRIVATE_KEY_PATH='/secure/apiclient_key.pem'
export WX_PAY_PUBLIC_KEY_ID='PUB_KEY_ID_replace_me'
export WX_PAY_PUBLIC_KEY_PATH='/secure/wechatpay_public_key.pem'
export WX_OUT_TRADE_NO='DEMO_ORDER_20261015'

以上 export 适用于 macOS / Linux 的终端,在同一终端内运行后续代码。Python 示例保存为 request.py 后执行 python3 request.py。

调用步骤

  1. 01

    准备自己的商户号、商户 API 证书序列号及对应私钥,设置 WX_MCH_ID、WX_MCH_SERIAL、WX_PRIVATE_KEY_PATH。

  2. 02

    在商户平台下载可信微信支付公钥,设置 WX_PAY_PUBLIC_KEY_ID 和 WX_PAY_PUBLIC_KEY_PATH;这两个参数负责验签,不参与商户请求签名。

  3. 03

    设置该场景的商户订单号或退款单号;必须是自己业务后台创建时保存的值,不能用页面里的示意值作为真实资源。

  4. 04

    把完整 JavaScript 保存为 request.mjs,使用 node request.mjs 运行。代码会生成当次 RSA 请求签名、验证原始响应再解析 JSON。

  5. 05

    只有已验签的业务状态才能更新自己的订单;查询程序本身不会发起下单、退款、关单或付款。

调用 01

查询订单

普通商户路径不带 /partner;请求不需要 body,mchid 在 query 中并参与签名。

GEThttps://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/${WX_OUT_TRADE_NO}?mchid=${WX_MCH_ID}

请求头

Accept
application/json

参数说明

参数表可左右滑动,查看完整说明。

字段 / 位置类型 / 必填说明
out_trade_noPathstring必填原支付下单时的商户订单号,最长 32 字符;本例限定为 URL 安全的常用合法字符。
mchidQuerystring必填该原订单所属的普通商户号。
AuthorizationHeaderstring必填WECHATPAY2-SHA256-RSA2048 认证串;由完整代码按当次时间戳、随机串及实际 URL 计算。
Wechatpay-SerialHeaderstring可选本例指定已配置的微信支付公钥 ID,并核对响应使用同一 ID。

调用代码

替换示例 ID 与请求体内容后运行。

Node.js
import { readFileSync } from 'node:fs';
import { constants, randomBytes, sign, verify } from 'node:crypto';
const required = (name) => {
  const value = process.env[name];
  if (!value) throw new Error(`缺少环境变量 ${name}`);
  return value;
};
const mchid = required('WX_MCH_ID');
const mchSerial = required('WX_MCH_SERIAL');
const payPublicKeyId = required('WX_PAY_PUBLIC_KEY_ID');
if (!/^\d+$/.test(mchid)) throw new Error('商户号应为数字字符串');
if (!/^[A-Fa-f0-9]+$/.test(mchSerial)) throw new Error('请填写真实商户 API 证书序列号');
if (!/^PUB_KEY_ID_\d+$/.test(payPublicKeyId)) throw new Error('本例仅支持已配置的微信支付公钥模式');
const privateKey = readFileSync(required('WX_PRIVATE_KEY_PATH'));
const payPublicKey = readFileSync(required('WX_PAY_PUBLIC_KEY_PATH'));

const outTradeNo = required('WX_OUT_TRADE_NO');
if (!/^[A-Za-z0-9_\-*|@]{6,32}$/.test(outTradeNo)) throw new Error('请填写自己的合法商户订单号');
const url = new URL('https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/' + encodeURIComponent(outTradeNo));
url.searchParams.set('mchid', mchid);

const timestamp = String(Math.floor(Date.now() / 1000));
const nonce = randomBytes(16).toString('hex');
// 五行都以换行结束;GET 的最后一行是空 body,仍保留末尾换行。
const message = `GET\n${url.pathname}${url.search}\n${timestamp}\n${nonce}\n\n`;
const signature = sign('RSA-SHA256', Buffer.from(message), {
  key: privateKey, padding: constants.RSA_PKCS1_PADDING,
}).toString('base64');
const authorization = `WECHATPAY2-SHA256-RSA2048 mchid="${mchid}",nonce_str="${nonce}",timestamp="${timestamp}",serial_no="${mchSerial}",signature="${signature}"`;
const response = await fetch(url, {
  method: 'GET', redirect: 'error', signal: AbortSignal.timeout(20000),
  headers: { Authorization: authorization, Accept: 'application/json',
    'Wechatpay-Serial': payPublicKeyId, 'User-Agent': 'MerchantReadOnlyExample/1.0' },
});
const raw = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
  // 非 2xx 只作为错误提示,不将错误体作为可信业务结果。
  throw new Error(`HTTP ${response.status}: ${raw.toString('utf8')}`);
}
const respSerial = response.headers.get('Wechatpay-Serial');
const respTimestamp = response.headers.get('Wechatpay-Timestamp') || '';
const respNonce = response.headers.get('Wechatpay-Nonce');
const respSignature = response.headers.get('Wechatpay-Signature');
if (respSerial !== payPublicKeyId) throw new Error('验签公钥 ID 不匹配,请从可信渠道核对轮换材料');
if (!/^\d+$/.test(respTimestamp) || !respNonce || !respSignature) throw new Error('响应缺少有效签名头');
if (Math.abs(Date.now() / 1000 - Number(respTimestamp)) > 300) throw new Error('响应时间偏差超过 5 分钟');
// 验签使用收到的原始字节;不能 JSON.parse 后重新序列化再验签。
const verificationMessage = Buffer.concat([
  Buffer.from(`${respTimestamp}\n${respNonce}\n`), raw, Buffer.from('\n'),
]);
const verified = verify('RSA-SHA256', verificationMessage, {
  key: payPublicKey, padding: constants.RSA_PKCS1_PADDING,
}, Buffer.from(respSignature, 'base64'));
if (!verified) throw new Error('响应验签失败,丢弃响应,不更新业务状态');
const data = JSON.parse(raw.toString('utf8'));

if (data.mchid !== mchid || data.out_trade_no !== outTradeNo) throw new Error('返回的商户号或订单号不匹配');
console.log(JSON.stringify({ out_trade_no: data.out_trade_no, transaction_id: data.transaction_id,
  trade_state: data.trade_state, amount: data.amount }, null, 2));
// 正式业务还必须核对 AppID、订单金额和币种,再幂等更新本地订单。

返回示例

按官方结构整理的节选示意,非实测结果。trade_state=SUCCESS 才表示支付成功;NOTPAY 是未支付。核对 amount.total(分)、currency、商户号、AppID 与本地订单后再处理。 以下为结构示意,非本站实测结果。

JSON
{
  "mchid": "1900000001",
  "appid": "wx_example_appid",
  "out_trade_no": "DEMO_ORDER_20261015",
  "transaction_id": "4200000000000000000000000000",
  "trade_state": "SUCCESS",
  "trade_state_desc": "支付成功",
  "amount": {
    "total": 100,
    "payer_total": 100,
    "currency": "CNY",
    "payer_currency": "CNY"
  }
}

常见错误与排查

401 / SIGN_ERROR请求签名未通过
核对商户私钥、商户证书序列号、五行换行和实际发送的 path+query。
404 / ORDER_NOT_EXIST订单不存在
检查原商户订单号、商户号,以及之前是否成功下单。
429 / FREQUENCY_LIMITED请求频率超限
降低查单频率,依据服务端结果合理退避。

调用注意

  • 先验证原始响应签名,再解析和使用业务结果;错误的探测签名也应失败,不可旁路。
  • 查询成功不一定已支付。未支付订单只能按商户订单号查询;本例不会替你创建订单。
  • 示例代码完整包含本次 GET 认证与验签;仅展示 Node.js 22,避免把无签名 cURL 误当成可用调用。

注意事项

  • 这些是正式 API 的只读查询,必须有自己的商户和已有业务资源;本例不是通用免资金沙盒,也不创建测试支付。
  • 本页无统一查单单价承诺;正式收款手续费、退款费用处理按经营类目和商户签约规则,查询示例不代表减免交易费用。
  • 商户请求签名使用商户私钥,响应验签使用微信支付公钥;API v3 密钥用于其他需要对称解密的场景,不能替代任何一方。

核验来源

本站按官方资料整理本场景的必要调用步骤与代码,覆盖范围以本页列出的接口为准。官方资料用于追溯规范及查看变更。

  1. 01
    普通商户开发必要参数核验日期 2026-10-15
  2. 02
  3. 03
    微信支付公钥验签核验日期 2026-10-15
  4. 04
  5. 05

微信支付的其他调用手册

← 返回微信支付的全部功能