微信支付调用手册

查询已有退款单并验证状态

读取自己已申请退款的状态,区分处理中、成功、关闭和异常。

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

接入准备

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

准备环境变量

示例值需要替换为自己的凭证或资源 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_REFUND_NO
原申请退款时由自己商户系统生成的退款单号;不是微信 refund_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_REFUND_NO='DEMO_REFUND_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

查询单笔退款

通过 out_refund_no 查询,不在 URL 额外拼支付订单号或商户号;认证商户身份来自 Authorization。

GEThttps://api.mch.weixin.qq.com/v3/refund/domestic/refunds/${WX_OUT_REFUND_NO}

请求头

Accept
application/json

参数说明

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

字段 / 位置类型 / 必填说明
out_refund_noPathstring必填原申请退款时的商户退款单号,最长 64 字符,必须属于当前认证商户。
AuthorizationHeaderstring必填商户私钥生成的 API v3 请求认证,详见完整 Node 代码。

调用代码

替换示例 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 outRefundNo = required('WX_OUT_REFUND_NO');
if (!/^[A-Za-z0-9_\-*|@]{1,64}$/.test(outRefundNo)) throw new Error('请填写自己的合法商户退款单号');
const url = new URL('https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/' + encodeURIComponent(outRefundNo));

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.out_refund_no !== outRefundNo) throw new Error('返回的商户退款单号不匹配');
console.log(JSON.stringify({ out_refund_no: data.out_refund_no, refund_id: data.refund_id,
  status: data.status, amount: data.amount }, null, 2));
// 正式业务须核对原支付单和退款金额,再幂等更新本地退款记录。

返回示例

按官方结构整理的节选示意,非实测结果。status 包括 SUCCESS、CLOSED、PROCESSING、ABNORMAL;HTTP 200 只代表查询完成。amount.refund、payer_refund 为分,业务应与本地退款记录核对。 以下为结构示意,非本站实测结果。

JSON
{
  "refund_id": "50000000000000000000000000000",
  "out_refund_no": "DEMO_REFUND_20261015",
  "out_trade_no": "DEMO_ORDER_20261015",
  "status": "PROCESSING",
  "amount": {
    "total": 100,
    "refund": 100,
    "payer_total": 100,
    "payer_refund": 100,
    "currency": "CNY"
  }
}

常见错误与排查

401 / SIGN_ERROR请求签名错误
确认商户证书序列号与私钥匹配,GET 的空 body 仍保留结尾换行。
404 / RESOURCE_NOT_EXISTS退款单不存在
核对 out_refund_no 是否属于该商户,以及原退款是否已被受理。
500 / SYSTEM_ERROR系统异常或超时
稍后用同一查询单号与参数重试,不由查询失败触发新退款。

调用注意

  • PROCESSING 不等于已退款到账;业务须结合可信退款通知或后续查单更新。
  • 查询不发起退款,也不改变退款金额;不要因为查询超时而重新生成另一个退款单。
  • 验签公钥只接受事先可信配置的文件与 ID,发生轮换时先核对新材料,不能信任响应里任意外部地址。

注意事项

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

核验来源

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

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

微信支付的其他调用手册

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