Skip to content

交易查询接口(Trade Query)

接口说明

交易查询接口用于查询已创建的支付订单状态和详细信息。商户可通过商户订单号(out_trade_no)或平台交易号(trade_no)进行查询,至少提供其中一个参数。

接口信息

  • 接口地址: POST /v1/pay/tradeQuery
  • Content-Type: application/json
  • 字符编码: UTF-8
  • 签名方式: RSA-SHA256

请求参数

公共参数

参数名类型必填说明
pay_mch_idString商户号,由平台分配
timestampString时间戳(秒级),有效期 5 分钟
nonce_strString随机字符串,32 位以内
sign_typeString签名类型,固定值:RSA
signString签名值

业务参数

参数名类型必填说明
out_trade_noString二选一商户订单号,商户系统内部订单号
trade_noString二选一平台交易号,由平台生成

提示

out_trade_notrade_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": "签名值"
}

响应参数

成功响应

参数名类型说明
codeString响应码,0000 表示成功
msgString响应消息
dataObject订单详细信息
data.out_trade_noString商户订单号
data.pay_mch_idString商户号
data.trade_noString平台交易号,对应用户支付凭证里的交易号
data.transaction_idString支付宝交易号(仅支付宝渠道)
data.trade_stateString交易状态,详见 状态定义
data.total_amountInteger订单总金额,单位:分
data.pay_amountInteger实际支付金额,单位:分
data.channelString支付渠道:wechat(微信)、alipay(支付宝)
data.subjectString商品名称
data.buyer_idString买家ID
data.pay_timeString支付完成时间,格式:yyyy-MM-dd HH:mm:ss
data.create_timeString订单创建时间,格式:yyyy-MM-dd HH:mm:ss
data.time_expireString订单失效时间
data.attachString附加数据
data.trade_state_descString交易状态描述,对当前订单状态的详细说明和下一步操作指引

响应示例

支付成功的订单

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_notrade_no
1002签名验证失败检查签名算法、密钥是否正确
1003商户号不存在确认商户号是否正确
1004订单不存在检查订单号是否正确,订单是否属于该商户
1005时间戳过期检查服务器时间是否同步
1010系统繁忙稍后重试或联系客服

注意事项

  1. 查询参数: out_trade_notrade_no 至少提供一个
  2. 查询频率: 建议查询间隔不低于 1 秒,避免频繁查询
  3. 数据延迟: 支付成功后,订单数据可能有 1-2 秒延迟,建议稍后重试
  4. 权限控制: 只能查询本商户的订单,不能查询其他商户订单
  5. 订单状态: 订单状态可能随时变化,建议定时查询或依赖异步通知
  6. 金额单位: 金额单位统一为

使用场景

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: 查询返回"订单不存在"怎么办?

  1. 检查订单号是否正确
  2. 确认订单是否属于当前商户
  3. 检查是否使用了正确的查询参数(out_trade_notrade_no

Q: 支付成功后查询仍显示"支付中"?

支付数据可能有 1-2 秒延迟,建议:

  1. 等待 2-3 秒后再次查询
  2. 依赖异步通知更新订单状态
  3. 如长时间未更新,联系客服处理

Q: 如何批量查询订单?

当前接口仅支持单笔查询,如需批量查询:

  1. 循环调用查询接口
  2. 控制查询频率,避免触发限流
  3. 建议使用异步通知 + 定时查询结合的方式

Q: 查询接口有频率限制吗?

建议查询间隔不低于 1 秒,过于频繁的查询可能触发限流机制。

Copyright © 2024 米付科技