Appearance
交易查询接口(Trade Query)
接口说明
交易查询接口用于查询已创建的支付订单状态和详细信息。商户可通过商户订单号(out_trade_no)或平台交易号(trade_no)进行查询,至少提供其中一个参数。
接口信息
- 接口地址:
POST /v1/pay/tradeQuery - Content-Type:
application/json - 字符编码: UTF-8
- 签名方式: RSA-SHA256
请求参数
公共参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| pay_mch_id | String | 是 | 商户号,由平台分配 |
| timestamp | String | 是 | 时间戳(秒级),有效期 5 分钟 |
| nonce_str | String | 是 | 随机字符串,32 位以内 |
| sign_type | String | 是 | 签名类型,固定值:RSA |
| sign | String | 是 | 签名值 |
业务参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| out_trade_no | String | 二选一 | 商户订单号,商户系统内部订单号 |
| trade_no | String | 二选一 | 平台交易号,由平台生成 |
提示
out_trade_no 和 trade_no 至少提供一个,优先使用 trade_no 查询。
请求示例
使用商户订单号查询
json
{
"pay_mch_id": "1234567890",
"out_trade_no": "ORDER20240101120000",
"timestamp": "1704067200",
"nonce_str": "5K8264ILTKCH16CQ2502SI8ZNMTM67VS",
"sign_type": "RSA",
"sign": "签名值"
}使用平台交易号查询
json
{
"pay_mch_id": "1234567890",
"trade_no": "MF20240101120000001",
"timestamp": "1704067200",
"nonce_str": "5K8264ILTKCH16CQ2502SI8ZNMTM67VS",
"sign_type": "RSA",
"sign": "签名值"
}响应参数
成功响应
| 参数名 | 类型 | 说明 |
|---|---|---|
| code | String | 响应码,0000 表示成功 |
| msg | String | 响应消息 |
| data | Object | 订单详细信息 |
| data.out_trade_no | String | 商户订单号 |
| data.pay_mch_id | String | 商户号 |
| data.trade_no | String | 平台交易号,对应用户支付凭证里的交易号 |
| data.transaction_id | String | 支付宝交易号(仅支付宝渠道) |
| data.trade_state | String | 交易状态,详见 状态定义 |
| data.total_amount | Integer | 订单总金额,单位:分 |
| data.pay_amount | Integer | 实际支付金额,单位:分 |
| data.channel | String | 支付渠道:wechat(微信)、alipay(支付宝) |
| data.subject | String | 商品名称 |
| data.buyer_id | String | 买家ID |
| data.pay_time | String | 支付完成时间,格式:yyyy-MM-dd HH:mm:ss |
| data.create_time | String | 订单创建时间,格式:yyyy-MM-dd HH:mm:ss |
| data.time_expire | String | 订单失效时间 |
| data.attach | String | 附加数据 |
| data.trade_state_desc | String | 交易状态描述,对当前订单状态的详细说明和下一步操作指引 |
响应示例
支付成功的订单
json
{
"code": "0000",
"msg": "success",
"data": {
"out_trade_no": "ORDER20240101120000",
"pay_mch_id": "1234567890",
"trade_no": "WX20240101120000001",
"trade_state": "SUCCESS",
"trade_state_desc": "支付成功",
"total_amount": 100,
"pay_amount": 100,
"channel": "wechat",
"subject": "测试商品",
"buyer_id": "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o",
"pay_time": "2024-01-01 12:00:00",
"create_time": "2024-01-01 11:59:50",
"time_expire": "2024-01-01 12:29:50",
"attach": "自定义数据"
}
}已关闭的订单
json
{
"code": "0000",
"msg": "success",
"data": {
"out_trade_no": "ORDER20240101130000",
"pay_mch_id": "1234567890",
"trade_no": "ALI20240101120000001",
"transaction_id": "2024010122001234567890",
"trade_state": "CLOSED",
"trade_state_desc": "订单已超时关闭",
"total_amount": 200,
"pay_amount": 0,
"channel": "alipay",
"subject": "超时订单",
"buyer_id": "20881234567890",
"pay_time": "",
"create_time": "2024-01-01 11:00:00",
"time_expire": "2024-01-01 11:30:00",
"attach": ""
}
}状态说明
交易状态的详细说明请查看 状态定义 文档。
代码示例
Java 示例
java
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
public class TradeQueryExample {
public static void main(String[] args) throws Exception {
// 1. 构建请求参数
Map<String, Object> params = new HashMap<>();
params.put("pay_mch_id", "1234567890");
params.put("out_trade_no", "ORDER20240101120000");
params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
params.put("nonce_str", generateNonceStr());
params.put("sign_type", "RSA");
// 2. 生成签名
String sign = SignUtil.sign(params, privateKey);
params.put("sign", sign);
// 3. 发送请求
String jsonBody = objectMapper.writeValueAsString(params);
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.mifpay.com/v1/pay/tradeQuery"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonBody))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
// 4. 处理响应
System.out.println(response.body());
}
private static String generateNonceStr() {
return UUID.randomUUID().toString().replace("-", "");
}
}Node.js 示例
javascript
const crypto = require('crypto');
const https = require('https');
async function queryTrade(outTradeNo) {
// 1. 构建请求参数
const params = {
pay_mch_id: '1234567890',
out_trade_no: outTradeNo,
timestamp: String(Math.floor(Date.now() / 1000)),
nonce_str: crypto.randomBytes(16).toString('hex'),
sign_type: 'RSA'
};
// 2. 生成签名
params.sign = sign(params, privateKey);
// 3. 发送请求
const options = {
hostname: 'api.mifpay.com',
path: '/api/v1/trade/query',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
return new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => {
resolve(JSON.parse(data));
});
});
req.on('error', reject);
req.write(JSON.stringify(params));
req.end();
});
}
// 使用示例
queryTrade('ORDER20240101120000')
.then(result => {
if (result.code === '0000') {
console.log('交易状态:', result.data.trade_state);
console.log('状态描述:', result.data.trade_state_desc);
console.log('支付金额:', result.data.pay_amount);
} else {
console.error('查询失败:', result.msg);
}
})
.catch(err => {
console.error('请求错误:', err);
});PHP 示例
php
<?php
function queryTrade($outTradeNo) {
// 1. 构建请求参数
$params = [
'pay_mch_id' => '1234567890',
'out_trade_no' => $outTradeNo,
'timestamp' => time(),
'nonce_str' => bin2hex(random_bytes(16)),
'sign_type' => 'RSA'
];
// 2. 生成签名
$params['sign'] = SignUtil::sign($params, $privateKey);
// 3. 发送请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.mifpay.com/v1/pay/tradeQuery');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json'
]);
$response = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
throw new Exception('请求失败: ' . $error);
}
return json_decode($response, true);
}
// 使用示例
try {
$result = queryTrade('ORDER20240101120000');
if ($result['code'] === '0000') {
echo "交易状态: " . $result['data']['trade_state'] . PHP_EOL;
echo "状态描述: " . $result['data']['trade_state_desc'] . PHP_EOL;
echo "支付金额: " . $result['data']['pay_amount'] . PHP_EOL;
} else {
echo "查询失败: " . $result['msg'] . PHP_EOL;
}
} catch (Exception $e) {
echo "错误: " . $e->getMessage() . PHP_EOL;
}查询流程
mermaid
sequenceDiagram
participant Backend as 商户后端
participant Platform as 米付平台
Backend->>Backend: 用户查看订单
Backend->>Backend: 构建查询参数
Backend->>Backend: 生成签名
Backend->>Platform: POST /v1/pay/tradeQuery
Platform->>Platform: 验证签名
Platform->>Platform: 查询订单
Platform-->>Backend: 返回订单信息
Backend->>Backend: 处理订单数据
Backend-->>User: 显示订单状态错误码
| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 0000 | 成功 | - |
| 1001 | 参数错误 | 检查是否提供了 out_trade_no 或 trade_no |
| 1002 | 签名验证失败 | 检查签名算法、密钥是否正确 |
| 1003 | 商户号不存在 | 确认商户号是否正确 |
| 1004 | 订单不存在 | 检查订单号是否正确,订单是否属于该商户 |
| 1005 | 时间戳过期 | 检查服务器时间是否同步 |
| 1010 | 系统繁忙 | 稍后重试或联系客服 |
注意事项
- 查询参数:
out_trade_no和trade_no至少提供一个 - 查询频率: 建议查询间隔不低于 1 秒,避免频繁查询
- 数据延迟: 支付成功后,订单数据可能有 1-2 秒延迟,建议稍后重试
- 权限控制: 只能查询本商户的订单,不能查询其他商户订单
- 订单状态: 订单状态可能随时变化,建议定时查询或依赖异步通知
- 金额单位: 金额单位统一为分
使用场景
1. 支付结果确认
用户完成支付操作后,前端可能未收到支付结果回调,此时后端应主动查询订单状态:
javascript
// 前端支付完成后,后端查询订单状态
async function checkPaymentResult(outTradeNo) {
for (let i = 0; i < 5; i++) {
const result = await queryTrade(outTradeNo);
if (result.data.trade_state === 'SUCCESS' || result.data.trade_state === 'TRADE_FINISHED') {
// 支付成功
return { success: true, data: result.data };
} else if (result.data.trade_state === 'CLOSED') {
// 订单已关闭
return { success: false, reason: result.data.trade_state_desc };
} else if (result.data.trade_state === 'PAYERROR') {
// 支付失败
return { success: false, reason: result.data.trade_state_desc };
}
// 等待 2 秒后再次查询
await sleep(2000);
}
return { success: false, reason: '查询超时' };
}2. 订单状态同步
定时查询未支付订单,更新订单状态:
java
// 定时任务:查询支付中的订单
@Scheduled(fixedRate = 60000) // 每分钟执行一次
public void syncPayingOrders() {
List<Order> payingOrders = orderService.getPayingOrders();
for (Order order : payingOrders) {
TradeQueryResult result = queryTrade(order.getOutTradeNo());
String tradeState = result.getData().getTradeState();
if ("SUCCESS".equals(tradeState) || "TRADE_FINISHED".equals(tradeState)) {
// 更新订单状态为已支付
orderService.updateOrderStatus(order.getId(), "PAID");
} else if ("CLOSED".equals(tradeState)) {
// 更新订单状态为已关闭
orderService.updateOrderStatus(order.getId(), "CLOSED");
} else if ("PAYERROR".equals(tradeState)) {
// 支付失败,记录失败信息
orderService.updateOrderStatus(order.getId(), "FAILED");
}
}
}3. 对账处理
每日对账时,查询订单详情与本地记录核对:
php
// 对账示例
$orders = getTodayOrders(); // 获取今日订单
foreach ($orders as $order) {
$result = queryTrade($order['out_trade_no']);
if ($result['code'] === '0000') {
$platformAmount = $result['data']['pay_amount'];
$localAmount = $order['pay_amount'];
if ($platformAmount != $localAmount) {
// 金额不一致,记录异常
logDiscrepancy($order['out_trade_no'], $localAmount, $platformAmount);
}
}
}常见问题
Q: 查询返回"订单不存在"怎么办?
- 检查订单号是否正确
- 确认订单是否属于当前商户
- 检查是否使用了正确的查询参数(
out_trade_no或trade_no)
Q: 支付成功后查询仍显示"支付中"?
支付数据可能有 1-2 秒延迟,建议:
- 等待 2-3 秒后再次查询
- 依赖异步通知更新订单状态
- 如长时间未更新,联系客服处理
Q: 如何批量查询订单?
当前接口仅支持单笔查询,如需批量查询:
- 循环调用查询接口
- 控制查询频率,避免触发限流
- 建议使用异步通知 + 定时查询结合的方式
Q: 查询接口有频率限制吗?
建议查询间隔不低于 1 秒,过于频繁的查询可能触发限流机制。
