退款查询接口
接口说明
退款状态查询接口,支持通过退款单号(refundTransactionNo)查询退款的详细状态信息。
适用对象
直连商户
请求 URL
https://api.example.com/openapi/v1/refund/query请求方法
POST
接口服务名
refund.query.status
频率限制:
- 每个商户每分钟最多查询 60 次,超过限制将返回错误码 9000
- 建议商户端做好请求频率控制,避免频繁查询
- 对于退款结果,建议优先使用异步通知,查询接口作为补充手段
请求参数(bizContent)
refundTransactionNo 和 refundNo 二选一,推荐使用 refundTransactionNo(平台退款单号)进行查询。
| 参数名 | 类型 | 必填 | 参数说明 |
|---|---|---|---|
refundTransactionNo |
String | C | 平台退款单号,创建退款时返回的 refundTransactionNo,示例值:SHRF20260704123456789012 |
refundNo |
String | C | 商户退款单号,创建退款时传入的 refundNo,示例值:REF20260704001 |
请求示例
通过 refundTransactionNo 查询(推荐)
JSON
{
"open_userid": "your_open_userid",
"service": "refund.query.status",
"bizContent": "{\"refundTransactionNo\":\"SHRF20260704123456789012\"}",
"sign_type": "MD5",
"sign": "your_calculated_sign"
}
通过 refundNo 查询
JSON
{
"open_userid": "your_open_userid",
"service": "refund.query.status",
"bizContent": "{\"refundNo\":\"REF20260704001\"}",
"sign_type": "MD5",
"sign": "your_calculated_sign"
}
响应参数
外层响应结构
| 参数名 | 类型 | 必填 | 参数说明 |
|---|---|---|---|
code |
String | Y | 响应状态码,成功为 "0000" |
message |
String | Y | 响应描述 |
timestamp |
String | Y | 响应时间戳,UTC 时间,ISO 8601 格式 |
data |
Object | Y | 业务数据,无数据时返回空对象 {} |
data 退款详情
| 参数名 | 类型 | 必填 | 参数说明 |
|---|---|---|---|
| 基本信息 | |||
refundTransactionNo |
String | Y | 平台退款订单号 |
refundNo |
String | N | 商户退款订单号 |
transactionNo |
String | Y | 原平台订单号 |
orderNo |
String | N | 原商户订单号 |
orderStatus |
Integer | Y | 退款状态:0-退款中 1-退款成功 2-退款失败 |
refundAmount |
Number | Y | 退款金额(元) |
pointsDeducted |
String | N | 返还积分金额(元) |
remark |
String | N | 退款备注 |
| 商户信息 | |||
merchantId |
String | N | 商户号 |
subMerchantId |
String | N | 子商户号 |
appId |
String | N | 应用ID |
| 通知信息 | |||
notifyStatus |
Integer | N | 通知状态:0-未通知 1-通知中 2-通知成功 3-通知失败 |
notifyUrl |
String | N | 通知地址 |
notifyTime |
String | N | 通知时间 |
| 时间信息 | |||
createTime |
String | Y | 创建时间,格式:YYYY-MM-DD HH:mm:ss |
finishTime |
String | N | 退款完成时间,格式:YYYY-MM-DD HH:mm:ss |
clientIp |
String | N | 下单时传的IP地址 |
退款状态说明
| 状态值 | 状态 | 说明 |
|---|---|---|
0 |
退款中 | 退款申请已提交,正在处理中 |
1 |
退款成功 | 退款已完成,资金已退回 |
2 |
退款失败 | 退款处理失败,请检查原因或联系客服 |
响应示例
成功响应(退款中):
JSON
{
"code": "0000",
"message": "Success",
"timestamp": "2026-07-05T15:30:00.000Z",
"data": {
// 基本信息
"refundTransactionNo": "SHRF20260704123456789012",
"refundNo": "REF20260704001",
"transactionNo": "SHPAY20260704120000123456",
"orderNo": "ORD20260704001",
"orderStatus": 0,
"refundAmount": 50.00,
"pointsDeducted": "0.50",
"remark": "用户申请退款",
// 商户信息
"merchantId": "100001",
"subMerchantId": "SUB001",
"appId": "wx1234567890abcdef",
// 通知信息
"notifyStatus": 0,
"notifyUrl": "https://merchant.com/notify",
"notifyTime": "",
// 时间信息
"createTime": "2026-07-04 14:30:00",
"finishTime": "",
"clientIp": "192.168.1.100"
}
}
成功响应(退款成功):
JSON
{
"code": "0000",
"message": "Success",
"timestamp": "2026-07-05T15:30:00.000Z",
"data": {
// 基本信息
"refundTransactionNo": "SHRF20260704123456789012",
"refundNo": "REF20260704001",
"transactionNo": "SHPAY20260704120000123456",
"orderNo": "ORD20260704001",
"orderStatus": 1,
"refundAmount": 50.00,
"pointsDeducted": "0.50",
"remark": "用户申请退款",
// 商户信息
"merchantId": "100001",
"subMerchantId": "SUB001",
"appId": "wx1234567890abcdef",
// 通知信息
"notifyStatus": 2,
"notifyUrl": "https://merchant.com/notify",
"notifyTime": "2026-07-04 14:35:00",
// 时间信息
"createTime": "2026-07-04 14:30:00",
"finishTime": "2026-07-04 14:35:00",
"clientIp": "192.168.1.100"
}
}
失败响应:
JSON
// 退款记录不存在
{
"code": "4004",
"message": "Resource Not Found: 退款记录不存在",
"timestamp": "2026-07-04T15:30:00.000Z",
"data": {}
}
// 参数缺失
{
"code": "4001",
"message": "Parameter Error: 退款单号不能为空",
"timestamp": "2026-07-04T15:30:00.000Z",
"data": {}
}
// 无查询权限
{
"code": "4003",
"message": "Permission Denied: 非用户订单,无查询权限",
"timestamp": "2026-07-04T15:30:00.000Z",
"data": {}
}
代码示例
Java
import java.util.HashMap;
import java.util.Map;
import com.alibaba.fastjson.JSON;
public class RefundQueryExample {
public static void main(String[] args) {
String openUserid = "your_open_userid";
String apiKey = "your_api_key";
String apiUrl = "https://openapi.example.com";
String refundTransactionNo = "SHRF20260704123456789012";
// 构建请求参数
Map<String, String> queryParams = new HashMap<>();
queryParams.put("refundTransactionNo", refundTransactionNo);
Map<String, String> requestData = new HashMap<>();
requestData.put("open_userid", openUserid);
requestData.put("service", "refund.query.status");
requestData.put("bizContent", JSON.toJSONString(queryParams));
requestData.put("sign_type", "MD5");
String sign = SignUtil.generateSign(requestData, apiKey);
requestData.put("sign", sign);
// 发送请求
String response = HttpUtil.post(apiUrl, requestData);
System.out.println("查询结果:" + response);
// 解析响应
Map<String, Object> result = JSON.parseObject(response, Map.class);
String code = (String) result.get("code");
if ("0000".equals(code)) {
Map<String, Object> data = (Map<String, Object>) result.get("data");
Integer orderStatus = (Integer) data.get("orderStatus");
switch (orderStatus) {
case 0:
System.out.println("退款处理中");
break;
case 1:
System.out.println("退款成功,金额:" + data.get("refundAmount"));
break;
case 2:
System.out.println("退款失败");
break;
}
}
}
}
Python
import requests
import json
import hashlib
def query_refund_status(refund_transaction_no):
"""查询退款状态"""
open_userid = "your_open_userid"
api_key = "your_api_key"
api_url = "https://openapi.example.com"
query_params = {"refundTransactionNo": refund_transaction_no}
request_data = {
"open_userid": open_userid,
"service": "refund.query.status",
"bizContent": json.dumps(query_params),
"sign_type": "MD5"
}
sign = generate_sign(request_data, api_key)
request_data["sign"] = sign
try:
response = requests.post(api_url, json=request_data, timeout=30)
return response.json()
except Exception as e:
print(f"查询失败: {e}")
return None
def generate_sign(params, api_key):
sorted_params = sorted(params.items())
sign_str = "&".join([f"{k}={v}" for k, v in sorted_params if v])
sign_str += f"&key={api_key}"
return hashlib.md5(sign_str.encode()).hexdigest().upper()
# 查询退款状态
result = query_refund_status("SHRF20260704123456789012")
# 处理返回结果
if result and result.get("code") == "0000":
data = result.get("data", {})
order_status = data.get("orderStatus")
refund_amount = data.get("refundAmount")
if order_status == 0:
print("退款处理中")
elif order_status == 1:
print(f"退款成功,金额:{refund_amount}元")
elif order_status == 2:
print("退款失败")
else:
print(f"查询失败:{result.get('message')}")
PHP
<?php
class RefundQuery {
private $openUserid = 'your_open_userid';
private $apiKey = 'your_api_key';
private $apiUrl = 'https://openapi.example.com';
public function queryRefundStatus($refundTransactionNo) {
$queryParams = ['refundTransactionNo' => $refundTransactionNo];
$requestData = [
'open_userid' => $this->openUserid,
'service' => 'refund.query.status',
'bizContent' => json_encode($queryParams),
'sign_type' => 'MD5'
];
$requestData['sign'] = $this->generateSign($requestData);
$response = $this->httpPost($this->apiUrl, $requestData);
return json_decode($response, true);
}
private function generateSign($params) {
ksort($params);
$signStr = '';
foreach ($params as $key => $value) {
if ($value !== '') {
$signStr .= "{$key}={$value}&";
}
}
$signStr .= "key={$this->apiKey}";
return strtoupper(md5($signStr));
}
private function httpPost($url, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
}
// 查询退款状态
$refundQuery = new RefundQuery();
$result = $refundQuery->queryRefundStatus('SHRF20260704123456789012');
// 处理返回结果
if ($result && $result['code'] === '0000') {
$data = $result['data'] ?? [];
$orderStatus = $data['orderStatus'] ?? 0;
switch ($orderStatus) {
case 0:
echo "退款处理中\n";
break;
case 1:
echo "退款成功,金额:{$data['refundAmount']}元\n";
break;
case 2:
echo "退款失败\n";
break;
}
} else {
echo "查询失败:" . ($result['message'] ?? '未知错误') . "\n";
}
注意事项
查询限制:
- 每个商户每分钟最多查询 60 次,超过限制将返回错误码 9000
- 建议商户端做好请求频率控制,避免频繁查询
- 对于退款结果,建议优先使用异步通知,查询接口作为补充手段
退款单号说明:
- 退款单号
refundTransactionNo在创建退款时由系统生成并返回 - 退款单号格式:
SHRF+ 年月日时分秒 + 6位随机数,共20位 - 示例:
SHRF20260704123456789012 - 请妥善保存退款单号,便于后续查询和对账
最佳实践:
- 退款申请后等待异步通知,如超时未收到再发起主动查询
- 查询间隔建议:首次 5 秒,后续每隔 10 秒查询一次,最多查询 5 次
- 退款处理时间取决于支付渠道,通常在 1-3 个工作日内完成
- 如果退款状态长时间为
refunding,请联系客服处理
常见错误码:
4001- 参数错误:退款单号不能为空4003- 权限不足:非用户订单,无查询权限4004- 资源不存在:退款记录不存在5000- 系统异常:请稍后重试9000- 频率限制:查询过于频繁