Appearance
交易查询接口(Trade Query)
接口说明
交易查询接口用于查询已创建的支付订单状态和详细信息。商户可通过商户订单号(out_trade_no)或商户单号(pay_trade_no)进行查询,至少提供其中一个参数。
接口信息
- 接口地址:
POST /v1/pay/tradeQuery - Content-Type:
application/json - 字符编码: UTF-8
- 签名方式: RSA-SHA256
请求参数
认证信息
请在 HTTP Header 中携带 Authorization 字段,格式详见 接口概览
业务参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| merchant_no | String | 是 | 商户号 |
| out_trade_no | String | 二选一 | 商户订单号,服务商自定义 |
| pay_trade_no | String | 二选一 | 商户单号,由平台生成 |
提示
out_trade_no 和 pay_trade_no 至少提供一个,优先使用 pay_trade_no 查询。
请求示例
使用商户订单号查询
http
POST /v1/pay/tradeQuery
Content-Type: application/json
Authorization: RSA service_id=SVC1234567890,timestamp=1704067200,nonce_str=abc123,sign=签名值
{
"merchant_no": "1234567890",
"out_trade_no": "ORDER20240101120000"
}使用商户单号查询
http
POST /v1/pay/tradeQuery
Content-Type: application/json
Authorization: RSA service_id=SVC1234567890,timestamp=1704067200,nonce_str=abc123,sign=签名值
{
"merchant_no": "1234567890",
"pay_trade_no": "MF20240101120000001"
}响应参数
成功响应
| 参数名 | 类型 | 说明 |
|---|---|---|
| code | String | 响应码,00000 表示成功 |
| msg | String | 响应消息 |
| data | Object | 订单详细信息 |
| data.out_trade_no | String | 商户订单号,服务商自定义 |
| data.merchant_no | String | 商户号 |
| data.pay_trade_no | String | 商户单号,对应用户支付凭证里的商户单号 |
| data.transaction_id | String | 交易单号,对应用户支付凭证里的交易单号 |
| data.trade_state | String | 交易状态,详见 状态定义 |
| data.total_amount | Integer | 订单总金额,单位:分 |
| data.pay_amount | Integer | 实际支付金额,单位:分 |
| data.pay_method | String | 支付方式:wechat(微信)、alipay(支付宝) |
| data.subject | String | 商品名称 |
| data.payer_id | String | 付款方ID |
| data.pay_time | String | 支付完成时间,格式:yyyyMMddHHmmss |
| data.create_time | String | 订单创建时间,格式:yyyyMMddHHmmss |
| data.time_expire | String | 订单失效时间,格式:yyyyMMddHHmmss |
| data.attach | String | 附加数据 |
| data.trade_state_desc | String | 交易状态描述,对当前订单状态的详细说明和下一步操作指引 |
响应示例
支付成功的订单
json
{
"code": "00000",
"msg": "success",
"data": {
"out_trade_no": "ORDER20240101120000",
"merchant_no": "1234567890",
"pay_trade_no": "WX20240101120000001",
"trade_state": "SUCCESS",
"trade_state_desc": "支付成功",
"total_amount": 100,
"pay_amount": 100,
"pay_method": "wechat",
"subject": "测试商品",
"payer_id": "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o",
"pay_time": "20240101120000",
"create_time": "20240101115950",
"time_expire": "20240101122950",
"attach": "自定义数据"
}
}已关闭的订单
json
{
"code": "00000",
"msg": "success",
"data": {
"out_trade_no": "ORDER20240101130000",
"merchant_no": "1234567890",
"pay_trade_no": "ALI20240101120000001",
"transaction_id": "2024010122001234567890",
"trade_state": "CLOSED",
"trade_state_desc": "订单已超时关闭",
"total_amount": 200,
"pay_amount": 0,
"pay_method": "alipay",
"subject": "超时订单",
"payer_id": "20881234567890",
"pay_time": "",
"create_time": "20240101110000",
"time_expire": "20240101113000",
"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("service_id", "SVC1234567890");
params.put("merchant_no", "1234567890");
params.put("out_trade_no", "ORDER20240101120000");
params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
params.put("nonce_str", generateNonceStr());
// 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.meepay.org/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 = {
service_id: 'SVC1234567890',
merchant_no: '1234567890',
out_trade_no: outTradeNo,
timestamp: String(Math.floor(Date.now() / 1000)),
nonce_str: crypto.randomBytes(16).toString('hex')
};
// 2. 生成签名
params.sign = sign(params, privateKey);
// 3. 发送请求
const options = {
hostname: 'api.meepay.org',
path: '/v1/pay/tradeQuery',
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 === '00000') {
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 = [
'service_id' => 'SVC1234567890',
'merchant_no' => '1234567890',
'out_trade_no' => $outTradeNo,
'timestamp' => time(),
'nonce_str' => bin2hex(random_bytes(16))
];
// 2. 生成签名
$params['sign'] = SignUtil::sign($params, $privateKey);
// 3. 发送请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.meepay.org/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'] === '00000') {
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;
}查询流程
错误码
| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 00000 | 成功 | - |
| 10001 | 参数错误 | 检查是否提供了 out_trade_no 或 trade_no |
| 10002 | 签名验证失败 | 检查签名算法、密钥是否正确 |
| 10003 | 服务商号不存在 | 确认 service_id 是否正确 |
| 10004 | 订单不存在 | 检查订单号是否正确,订单是否属于该商户 |
| 10005 | 时间戳过期 | 检查服务器时间是否同步 |
| 10010 | 系统繁忙 | 稍后重试或联系客服 |
注意事项
- 查询参数:
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'] === '00000') {
$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 秒,过于频繁的查询可能触发限流机制。