安全提示:本平台是支付机构代理商,不涉及资金清算,不触碰用户资金。资金由持牌支付机构与您直接清算,望知晓!
协议规则
| 请求数据格式 | application/x-www-form-urlencoded |
| 返回数据格式 | JSON |
| 签名算法 | MD5(结果为32位小写) |
| 字符编码 | UTF-8 |
接入安全须知(必读)
1、回调必须验签:收到异步通知先校验 sign,不一致直接丢弃,不做任何入账处理。
2、入账必须二次确认:验签通过后,务必再调用查询单个订单接口,返回 status=1(已支付)才允许入账。回调只能当提醒,不能当支付凭证。
3、金额/单号比对:回调 money 必须等于你下单时的金额;同一 out_trade_no 只允许入账一次(幂等)。
4、通知送达确认:处理成功后必须输出 success 字样,平台才会停止重试;验签失败请勿返回 success。
5、密钥保密:商户密钥只存放于服务端,严禁出现在URL、前端页面或日志中;一旦疑似泄露,请立即登录商户后台重置密钥。
测试账号
说明:
1、测试金额应为小额,建议单笔测试交易 0.01 元以内;
2、测试交易完成后,如需退款应当日(通过 API 提交订单退款);
3、测试账号仅供测试使用,请勿用在自己正式运营的网站上;
4、本平台兼容易支付接口,无需额外开发,可直接使用。
API接口统一下单支付(推荐)
此接口可用于服务器后端发起支付请求,会返回支付跳转url。(此url是自适应页面,包含手机端H5唤起支付、PC端扫码支付、微信内支付等等。例如:付款方如果在手机浏览器打开这个URL是H5唤起支付,如果在PC电脑端打开这个URL是PC扫码支付,如果在APP内打开是APP支付)
注:1、实际要以ASCII码从小到大排序,具体详细请查看下方 MD5签名算法;
注:2、若使用POST报错,请用GET测试。
请求参数说明:
| 字段名 | 变量名 | 必填 | 类型 | 示例值 | 描述 |
|---|---|---|---|---|---|
| 商户ID | pid | 是 | Int | 1001 | |
| 支付方式 | type | 是 | String | alipay | alipay:支付宝,wxpay:微信支付 |
| 商户订单号 | out_trade_no | 是 | String | 20160806151343349 | 此单号对应的支付方式是唯一的,也就是微信一套单号、支付宝一套单号,万不可混用 |
| 异步通知地址 | notify_url | 是 | String | http://www.pay.com/notify_url.php | 服务器异步通知地址,支付结果通知 |
| 跳转通知地址 | return_url | 是 | String | http://www.pay.com/return_url.php | 页面跳转通知地址 |
| 商品名称 | name | 是 | String | VIP会员 | 如超过127个字节会自动截取 |
| 商品金额 | money | 是 | String | 1.00 | 单位:元,最大2位小数 |
| 用户IP地址 | clientip | 是 | String | 192.168.1.100 | 不强求真实,可随意传入一个IP |
| 设备类型 | device | 是 | String | jump | 根据传入的设备类型参数判断返回的是二维码链接或其它支付跳转URL等,设备类型列表 |
| 业务扩展参数 | param | 否 | String | 没有请留空 | 支付后原样返回 |
| 签名字符串 | sign | 是 | String | 202cb962ac59075b964b07152d234b70 | 签名算法点此查看 |
| 签名类型 | sign_type | 是 | String | MD5 | 默认为MD5 |
返回结果(json):
| 字段名 | 变量名 | 类型 | 示例值 | 描述 |
|---|---|---|---|---|
| 返回状态码 | code | Int | 1 | 1为成功,其它值为失败 |
| 返回信息 | msg | String | 失败时返回原因 | |
| 订单号 | trade_no | String | 20160806151343349 | 支付订单号 |
| 支付跳转URL | payurl | String | https://api.payqixiang.cn/pay/submit/202312311388/ | 直接获取json返回值,引导客户跳转到该url支付链接支付 |
| 二维码链接 | qrcode | String | 默认:https://api.payqixiang.cn/pay/wxjspay/ 原生:weixin://wxpay/bizpayurl?pr=l1zE22Nz3 | 如果返回该字段,则根据该url自行生成二维码 |
{
"code": 1,
"msg": "",
"trade_no": "20260806151343349",
"payurl": "https://api.payqixiang.cn/pay/submit/202312311388/",
"qrcode": ""
}
<?php
// ===== 商户配置 =====
$pid = '1001'; // 商户ID
$key = '89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i'; // 商户密钥
$api = 'https://api.payqixiang.cn/mapi.php'; // 支付网关地址(建议设置为可配置变量)
// ===== 请求参数 =====
$data = array(
'pid' => $pid,
'type' => 'alipay', // 支付方式:alipay 支付宝 / wxpay 微信支付
'out_trade_no' => date('YmdHis') . rand(1000, 9999), // 商户订单号,需保证唯一
'notify_url' => 'https://www.example.com/notify_url.php', // 异步通知地址
'return_url' => 'https://www.example.com/return_url.php', // 页面跳转通知地址
'name' => 'VIP会员', // 商品名称
'money' => '1.00', // 商品金额,单位:元,最大2位小数
'clientip' => '192.168.1.100', // 用户IP,不强求真实
'device' => 'jump', // 设备类型:jump 返回自适应支付页(推荐)
);
// ===== 生成签名(详细算法见下方「MD5签名算法」)=====
unset($data['sign'], $data['sign_type']);
ksort($data);
$str = urldecode(http_build_query(array_filter($data, function ($v) { return $v !== '' && $v !== null; })));
$data['sign'] = md5($str . $key); // MD5 结果为32位小写
$data['sign_type'] = 'MD5';
// ===== 发起请求 =====
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $api);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
// ===== 处理返回结果 =====
$res = json_decode($result, true);
if (isset($res['code']) && $res['code'] == 1) {
// 下单成功,引导用户跳转到支付链接
header('Location: ' . $res['payurl']);
exit;
} else {
exit('下单失败:' . (isset($res['msg']) ? $res['msg'] : '未知错误'));
}// 需引入 Hutool 工具库,Maven 依赖:cn.hutool:hutool-all
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpRequest;
import java.util.Map;
import java.util.TreeMap;
public class PayDemo {
public static void main(String[] args) {
String pid = "1001"; // 商户ID
String key = "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i"; // 商户密钥
String api = "https://api.payqixiang.cn/mapi.php"; // 支付网关地址
// 请求参数(TreeMap 自动按参数名 ASCII 码从小到大排序)
TreeMap<String, Object> params = new TreeMap<>();
params.put("pid", pid);
params.put("type", "alipay"); // 支付方式:alipay / wxpay
params.put("out_trade_no", "20260929123456789"); // 商户订单号,需保证唯一
params.put("notify_url", "https://www.example.com/notify_url.php");
params.put("return_url", "https://www.example.com/return_url.php");
params.put("name", "VIP会员"); // 商品名称
params.put("money", "1.00"); // 金额,单位:元,最大2位小数
params.put("clientip", "192.168.1.100");
params.put("device", "jump"); // 设备类型:jump 返回自适应支付页(推荐)
// 生成签名:拼接 a=b&c=d 后接商户密钥,MD5 为32位小写
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, Object> e : params.entrySet()) {
if (e.getValue() == null || e.getValue().toString().isEmpty()) continue;
if (sb.length() > 0) sb.append('&');
sb.append(e.getKey()).append('=').append(e.getValue());
}
params.put("sign", DigestUtil.md5Hex(sb.toString() + key));
params.put("sign_type", "MD5");
// 发起请求并获取返回 JSON
String result = HttpRequest.post(api).form(params).execute().body();
System.out.println(result);
// 返回 JSON 中 code=1 表示成功,引导用户跳转 payurl 支付即可
}
}# pip install requests
import hashlib
import requests
# 商户配置
PID = '1001'
KEY = '89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i'
API = 'https://api.payqixiang.cn/mapi.php'
# 请求参数
params = {
'pid': PID,
'type': 'alipay', # 支付方式:alipay / wxpay
'out_trade_no': '20260929123456789', # 商户订单号,需保证唯一
'notify_url': 'https://www.example.com/notify_url.php',
'return_url': 'https://www.example.com/return_url.php',
'name': 'VIP会员', # 商品名称
'money': '1.00', # 金额,单位:元,最大2位小数
'clientip': '192.168.1.100',
'device': 'jump', # 设备类型:jump 返回自适应支付页(推荐)
}
# 生成签名:参数按 ASCII 码从小到大排序,拼接 a=b&c=d 后接商户密钥,MD5 为32位小写
query = '&'.join(f'{k}={params[k]}' for k in sorted(params) if params[k] not in ('', None))
params['sign'] = hashlib.md5((query + KEY).encode('utf-8')).hexdigest()
params['sign_type'] = 'MD5'
# 发起请求
res = requests.post(API, data=params).json()
if res.get('code') == 1:
# 下单成功,引导用户跳转到支付链接
print(res['payurl'])
else:
print('下单失败:', res.get('msg'))// Node.js 18+ 内置 fetch,无需额外依赖
const crypto = require('crypto');
// 商户配置
const PID = '1001';
const KEY = '89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i';
const API = 'https://api.payqixiang.cn/mapi.php';
// 请求参数
const params = {
pid: PID,
type: 'alipay', // 支付方式:alipay / wxpay
out_trade_no: '20260929123456789', // 商户订单号,需保证唯一
notify_url: 'https://www.example.com/notify_url.php',
return_url: 'https://www.example.com/return_url.php',
name: 'VIP会员', // 商品名称
money: '1.00', // 金额,单位:元,最大2位小数
clientip: '192.168.1.100',
device: 'jump', // 设备类型:jump 返回自适应支付页(推荐)
};
// 生成签名:参数按 ASCII 码从小到大排序,拼接 a=b&c=d 后接商户密钥,MD5 为32位小写
const query = Object.keys(params)
.filter(k => params[k] !== '' && params[k] !== undefined)
.sort()
.map(k => `${k}=${params[k]}`)
.join('&');
params.sign = crypto.createHash('md5').update(query + KEY).digest('hex');
params.sign_type = 'MD5';
// 发起请求
const res = await fetch(API, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams(params).toString(),
}).then(r => r.json());
if (res.code === 1) {
// 下单成功,引导用户跳转到支付链接
console.log(res.payurl);
} else {
console.log('下单失败:', res.msg);
}// Go 标准库示例,无需第三方依赖
package main
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"net/http"
"net/url"
"sort"
"strings"
)
func main() {
// 商户配置
key := "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i"
api := "https://api.payqixiang.cn/mapi.php"
// 请求参数
params := map[string]string{
"pid": "1001", // 商户ID
"type": "alipay", // 支付方式:alipay / wxpay
"out_trade_no": "20260929123456789", // 商户订单号,需保证唯一
"notify_url": "https://www.example.com/notify_url.php",
"return_url": "https://www.example.com/return_url.php",
"name": "VIP会员", // 商品名称
"money": "1.00", // 金额,单位:元,最大2位小数
"clientip": "192.168.1.100",
"device": "jump", // 设备类型:jump 返回自适应支付页(推荐)
}
// 生成签名:参数按 ASCII 升序拼接 a=b&c=d 后接商户密钥,MD5 为32位小写
keys := make([]string, 0, len(params))
for k, v := range params {
if v != "" {
keys = append(keys, k)
}
}
sort.Strings(keys)
pairs := make([]string, 0, len(keys))
for _, k := range keys {
pairs = append(pairs, k+"="+params[k])
}
sum := md5.Sum([]byte(strings.Join(pairs, "&") + key))
params["sign"] = hex.EncodeToString(sum[:]) // 32位小写
params["sign_type"] = "MD5"
// 发起请求
form := url.Values{}
for k, v := range params {
form.Set(k, v)
}
resp, err := http.PostForm(api, form)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
// 返回 JSON 中 code=1 表示成功,引导用户跳转 payurl 支付即可
}// .NET 6+ 示例,使用 HttpClient
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
var api = "https://api.payqixiang.cn/mapi.php";
var key = "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i";
// 请求参数
var data = new Dictionary<string, string>
{
["pid"] = "1001", // 商户ID
["type"] = "alipay", // 支付方式:alipay / wxpay
["out_trade_no"] = "20260929123456789", // 商户订单号,需保证唯一
["notify_url"] = "https://www.example.com/notify_url.php",
["return_url"] = "https://www.example.com/return_url.php",
["name"] = "VIP会员", // 商品名称
["money"] = "1.00", // 金额,单位:元,最大2位小数
["clientip"] = "192.168.1.100",
["device"] = "jump", // 设备类型:jump 返回自适应支付页(推荐)
};
// 生成签名:参数按 ASCII 升序拼接 a=b&c=d 后接商户密钥,MD5 为32位小写
var pairs = data.Where(p => !string.IsNullOrEmpty(p.Value))
.OrderBy(p => p.Key, StringComparer.Ordinal)
.Select(p => $"{p.Key}={p.Value}");
data["sign"] = Convert.ToHexString(
MD5.HashData(Encoding.UTF8.GetBytes(string.Join("&", pairs) + key))).ToLower();
data["sign_type"] = "MD5";
// 发起请求
using var client = new HttpClient();
var resp = await client.PostAsync(api, new FormUrlEncodedContent(data));
using var doc = JsonDocument.Parse(await resp.Content.ReadAsStringAsync());
var json = doc.RootElement;
if (json.GetProperty("code").GetInt32() == 1)
{
// 下单成功,引导用户跳转到支付链接
Console.WriteLine(json.GetProperty("payurl").GetString());
}
else
{
Console.WriteLine("下单失败:" + (json.TryGetProperty("msg", out var msg) ? msg.GetString() : "未知错误"));
}// 安卓示例,需引入 OkHttp:implementation("com.squareup.okhttp3:okhttp:4.12.0")
// 网络请求需在子线程执行(如协程 withContext(Dispatchers.IO))
import okhttp3.FormBody
import okhttp3.OkHttpClient
import okhttp3.Request
import java.security.MessageDigest
fun createOrder() {
val key = "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i"
val api = "https://api.payqixiang.cn/mapi.php"
// 请求参数(sortedMapOf 保证参数按 ASCII 升序)
val params = sortedMapOf(
"pid" to "1001", // 商户ID
"type" to "alipay", // 支付方式:alipay / wxpay
"out_trade_no" to "20260929123456789", // 商户订单号,需保证唯一
"notify_url" to "https://www.example.com/notify_url.php",
"return_url" to "https://www.example.com/return_url.php",
"name" to "VIP会员", // 商品名称
"money" to "1.00", // 金额,单位:元,最大2位小数
"clientip" to "192.168.1.100",
"device" to "jump", // 设备类型:jump 返回自适应支付页(推荐)
)
// 生成签名:参数按 ASCII 升序拼接 a=b&c=d 后接商户密钥,MD5 为32位小写
val query = params.entries.joinToString("&") { "${it.key}=${it.value}" }
val sign = MessageDigest.getInstance("MD5").digest((query + key).toByteArray())
.joinToString("") { "%02x".format(it) }
params["sign"] = sign
params["sign_type"] = "MD5"
// 发起请求
val form = FormBody.Builder().apply {
params.forEach { (k, v) -> add(k, v) }
}.build()
val request = Request.Builder().url(api).post(form).build()
val body = OkHttpClient().newCall(request).execute().body?.string()
println(body) // 解析 JSON:code=1 表示成功,跳转 payurl 拉起支付
}// iOS 示例(Swift 5+),使用 URLSession,无需第三方库
import Foundation
import CryptoKit
func createOrder() {
let key = "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i"
let api = "https://api.payqixiang.cn/mapi.php"
// 请求参数
var params: [String: String] = [
"pid": "1001", // 商户ID
"type": "alipay", // 支付方式:alipay / wxpay
"out_trade_no": "20260929123456789", // 商户订单号,需保证唯一
"notify_url": "https://www.example.com/notify_url.php",
"return_url": "https://www.example.com/return_url.php",
"name": "VIP会员", // 商品名称
"money": "1.00", // 金额,单位:元,最大2位小数
"clientip": "192.168.1.100",
"device": "jump", // 设备类型:jump 返回自适应支付页(推荐)
]
// 生成签名:参数按 ASCII 升序拼接 a=b&c=d 后接商户密钥,MD5 为32位小写
let query = params.filter { !$0.value.isEmpty }
.sorted { $0.key < $1.key }
.map { "\($0.key)=\($0.value)" }
.joined(separator: "&")
let digest = Insecure.MD5.hash(data: Data((query + key).utf8))
params["sign"] = digest.map { String(format: "%02x", $0) }.joined()
params["sign_type"] = "MD5"
// 发起请求(POST form 表单)
let form = params.map { "\($0.key)=\($0.value)" }.joined(separator: "&")
var request = URLRequest(url: URL(string: api)!)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpBody = form.data(using: .utf8)
URLSession.shared.dataTask(with: request) { data, _, _ in
guard let data = data,
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let code = json["code"] as? Int else { return }
if code == 1, let payurl = json["payurl"] as? String {
// 下单成功,跳转 payurl 拉起支付(UI 操作需回主线程)
print(payurl)
} else {
print("下单失败:\(json["msg"] ?? "未知错误")")
}
}.resume()
}注:返回的参数中到底是二维码链接还是支付跳转url,其实是根据你设备类型device传入的值来决定的。例如设备类型device参数值传入"pc"则只返回qrcode二维码链接,需自行包装转换成二维码。如果不懂怎么展示支付页面,可在设备类型device值中传入"jump",这样就只会返回支付跳转url,此url是自适应页面,包含手机端H5唤起支付、PC端扫码支付等,直接前台跳转到这个url链接支付即可。
2、如果对接过程中出现异步参数名被转义成"¬ify url"这样会导致接口报错,请自行百度解决;
3、APP对接的话微信支付需要在app内调用webview组件跳转支付链接,然后需要在webview中手动设置referer,如 (Map extraHeaders = new HashMap();extraHeaders.put("Referer", "https://api.payqixiang.cn")) 可直接吊起。支付宝不需要,直接webview组件跳转支付链接即可;
4、pc返回的二维码链接一般默认不是微信原生二维码链接及支付页面,若需原生链接页面请联系客服。
页面跳转支付
此接口可用于用户前台直接发起支付,使用form表单跳转或拼接成url跳转。
注:实际要以ASCII码从小到大排序,具体详细请查看下方 MD5签名算法。
请求参数说明:
| 字段名 | 变量名 | 必填 | 类型 | 示例值 | 描述 |
|---|---|---|---|---|---|
| 商户ID | pid | 是 | Int | 1001 | |
| 支付方式 | type | 否 | String | alipay | alipay:支付宝,wxpay:微信支付 |
| 商户订单号 | out_trade_no | 是 | String | 20160806151343349 | |
| 异步通知地址 | notify_url | 是 | String | http://www.pay.com/notify_url.php | 服务器异步通知地址 |
| 跳转通知地址 | return_url | 是 | String | http://www.pay.com/return_url.php | 页面跳转通知地址 |
| 商品名称 | name | 是 | String | VIP会员 | 如超过127个字节会自动截取 |
| 商品金额 | money | 是 | String | 1.00 | 单位:元,最大2位小数 |
| 业务扩展参数 | param | 否 | String | 没有请留空 | 支付后原样返回 |
| 签名字符串 | sign | 是 | String | 202cb962ac59075b964b07152d234b70 | 签名算法点此查看 |
| 签名类型 | sign_type | 是 | String | MD5 | 默认为MD5 |
<!-- sign 需在服务器端按「MD5签名算法」生成后再输出到表单,不可在前端计算 -->
<form id="payform" action="https://api.payqixiang.cn/submit.php" method="post">
<input type="hidden" name="pid" value="1001" />
<input type="hidden" name="type" value="alipay" />
<input type="hidden" name="out_trade_no" value="20260929123456789" />
<input type="hidden" name="notify_url" value="https://www.example.com/notify_url.php" />
<input type="hidden" name="return_url" value="https://www.example.com/return_url.php" />
<input type="hidden" name="name" value="VIP会员" />
<input type="hidden" name="money" value="1.00" />
<input type="hidden" name="sign" value="127d5a7f5d5a5b1c9f3c1f8f8c8c8a8a" />
<input type="hidden" name="sign_type" value="MD5" />
</form>
<script>document.getElementById('payform').submit();</script>
注:1、支付方式参数不传会跳转到聚合收银台支付;
注:2、如果对接过程中出现异步参数名被转义成"¬ify url"这样会导致接口报错,请自行百度解决;
注:3、APP对接的话微信支付需要在app内调用webview组件跳转支付链接,然后需要在webview中手动设置referer,如 (Map extraHeaders = new HashMap();extraHeaders.put("Referer", "https://api.payqixiang.cn")) 可直接吊起。支付宝不需要,直接webview组件跳转支付链接即可。
支付结果通知
通知机制:用户付款成功后,我们会向您在发起付款接口传入的notify_url网址发送通知。您的服务器只要返回内容:success,就表示回调已收到。如果返回内容不是success,我们会再尝试回调5次。
请求参数说明:
| 字段名 | 变量名 | 必填 | 类型 | 示例值 | 描述 |
|---|---|---|---|---|---|
| 商户ID | pid | 是 | Int | 1001 | |
| 七相系统订单号 | trade_no | 是 | String | 20160806151343349021 | 七相系统订单号 |
| 商户订单号 | out_trade_no | 是 | String | 20160806151343349 | 商户系统内部的订单号 |
| 支付方式 | type | 是 | String | alipay | 支付方式列表 |
| 商品名称 | name | 是 | String | VIP会员 | |
| 商品金额 | money | 是 | String | 1.00 | 格式统一为两位小数 |
| 支付状态 | trade_status | 是 | String | TRADE_SUCCESS | 只有TRADE_SUCCESS是成功 |
| 业务扩展参数 | param | 否 | String | ||
| 签名字符串 | sign | 是 | String | 202cb962ac59075b964b07152d234b70 | 签名算法点此查看 |
| 签名类型 | sign_type | 是 | String | MD5 | 默认为MD5 |
<?php
// notify_url.php —— 支付结果异步通知处理示例
// 建议:先记录回调日志,便于排查问题
file_put_contents(__DIR__ . '/notify.log', date('Y-m-d H:i:s') . ' ' . http_build_query($_GET) . PHP_EOL, FILE_APPEND);
$key = '89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i'; // 商户密钥
// 1、验证签名:必须使用回调收到的参数参与验签(不要使用本地存储的值)
$sign = $_GET['sign'];
$check = $_GET;
unset($check['sign'], $check['sign_type']);
$check = array_filter($check, function ($v) { return $v !== '' && $v !== null; });
ksort($check);
$str = urldecode(http_build_query($check));
if (md5($str . $key) !== $sign) {
exit('fail'); // 验签失败,可能是伪造通知,拒绝处理
}
// 2、校验金额:回调金额格式统一为两位小数(如 1.00),需与商户本地订单金额比对
// $order = 查询本地订单($_GET['out_trade_no']);
// if (number_format(floatval($_GET['money']), 2, '.', '') !== number_format(floatval($order['money']), 2, '.', '')) exit('fail');
// 3、处理业务:更新本地订单为已支付(务必做幂等处理,防止重复回调重复入账)
// ...... 你的业务逻辑(发货、开通会员等)
// 4、返回 success 表示回调处理成功,否则平台会间隔重试 5 次
echo 'success';// Spring Boot 示例,需引入 Hutool:cn.hutool:hutool-all
import cn.hutool.crypto.digest.DigestUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.TreeMap;
@RestController
public class NotifyController {
/** 支付结果异步通知处理(验签 + 金额校验) */
@RequestMapping("/notify_url.php")
public String notify(HttpServletRequest request) {
String key = "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i"; // 商户密钥
// 1、验证签名:必须使用回调收到的参数参与验签(不要使用本地存储的值)
// TreeMap 自动按参数名 ASCII 码从小到大排序
TreeMap<String, String> params = new TreeMap<>();
for (Map.Entry<String, String[]> e : request.getParameterMap().entrySet()) {
String v = e.getValue()[0];
if (!"sign".equals(e.getKey()) && !"sign_type".equals(e.getKey())
&& v != null && !v.isEmpty()) {
params.put(e.getKey(), v);
}
}
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> e : params.entrySet()) {
if (sb.length() > 0) sb.append('&');
sb.append(e.getKey()).append('=').append(e.getValue());
}
if (!DigestUtil.md5Hex(sb.toString() + key).equals(request.getParameter("sign"))) {
return "fail"; // 验签失败,可能是伪造通知,拒绝处理
}
// 2、校验金额:回调金额格式统一为两位小数(如 1.00),需与商户本地订单金额比对
// Order order = orderService.getByOutTradeNo(request.getParameter("out_trade_no"));
// if (new java.math.BigDecimal(request.getParameter("money"))
// .compareTo(new java.math.BigDecimal(order.getMoney())) != 0) return "fail";
// 3、处理业务:更新本地订单为已支付(务必做幂等处理,防止重复回调重复入账)
// ...... 你的业务逻辑(发货、开通会员等)
// 4、返回 success 表示回调处理成功,否则平台会间隔重试 5 次
return "success";
}
}# -*- coding: utf-8 -*-
# Flask 示例:pip install flask
import hashlib
from flask import Flask, request
app = Flask(__name__)
KEY = '89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i' # 商户密钥
@app.route('/notify_url.php')
def notify():
# 1、验证签名:必须使用回调收到的参数参与验签(不要使用本地存储的值)
sign = request.args.get('sign', '')
check = {k: v for k, v in request.args.items()
if k not in ('sign', 'sign_type') and v not in ('', None)}
query = '&'.join(f'{k}={check[k]}' for k in sorted(check))
if hashlib.md5((query + KEY).encode('utf-8')).hexdigest() != sign:
return 'fail' # 验签失败,可能是伪造通知,拒绝处理
# 2、校验金额:回调金额格式统一为两位小数(如 1.00),需与商户本地订单金额比对
# order = Order.query.filter_by(out_trade_no=request.args.get('out_trade_no')).first()
# if f"{float(request.args.get('money')):.2f}" != f"{float(order.money):.2f}":
# return 'fail'
# 3、处理业务:更新本地订单为已支付(务必做幂等处理,防止重复回调重复入账)
# ...... 你的业务逻辑(发货、开通会员等)
# 4、返回 success 表示回调处理成功,否则平台会间隔重试 5 次
return 'success'
if __name__ == '__main__':
app.run(port=80)// Express 示例:npm install express
const crypto = require('crypto');
const express = require('express');
const app = express();
const KEY = '89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i'; // 商户密钥
// 支付结果异步通知处理(验签 + 金额校验)
app.get('/notify_url.php', (req, res) => {
// 1、验证签名:必须使用回调收到的参数参与验签(不要使用本地存储的值)
const sign = req.query.sign;
const check = {};
for (const k of Object.keys(req.query)) {
if (k === 'sign' || k === 'sign_type') continue;
if (req.query[k] === '' || req.query[k] === undefined) continue;
check[k] = req.query[k];
}
const query = Object.keys(check).sort()
.map(k => `${k}=${check[k]}`).join('&');
const mySign = crypto.createHash('md5').update(query + KEY).digest('hex');
if (mySign !== sign) {
return res.send('fail'); // 验签失败,可能是伪造通知,拒绝处理
}
// 2、校验金额:回调金额格式统一为两位小数(如 1.00),需与商户本地订单金额比对
// const order = await db.getOrder(req.query.out_trade_no);
// if (Number(req.query.money).toFixed(2) !== Number(order.money).toFixed(2)) return res.send('fail');
// 3、处理业务:更新本地订单为已支付(务必做幂等处理,防止重复回调重复入账)
// ...... 你的业务逻辑(发货、开通会员等)
// 4、返回 success 表示回调处理成功,否则平台会间隔重试 5 次
res.send('success');
});
app.listen(80);// Go 标准库示例(net/http):notify_url 处理器
package main
import (
"crypto/md5"
"encoding/hex"
"fmt"
"net/http"
"sort"
"strings"
)
// 支付结果异步通知处理示例(验签 + 金额校验)
func notify(w http.ResponseWriter, r *http.Request) {
key := "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i" // 商户密钥
r.ParseForm()
data := map[string]string{}
for k, v := range r.Form {
if len(v) > 0 {
data[k] = v[0]
}
}
// 1、验证签名:必须使用回调收到的参数参与验签(不要使用本地存储的值)
sign := data["sign"]
keys := make([]string, 0, len(data))
for k, v := range data {
if v == "" || k == "sign" || k == "sign_type" {
continue
}
keys = append(keys, k)
}
sort.Strings(keys)
pairs := make([]string, 0, len(keys))
for _, k := range keys {
pairs = append(pairs, k+"="+data[k])
}
sum := md5.Sum([]byte(strings.Join(pairs, "&") + key))
if hex.EncodeToString(sum[:]) != sign {
fmt.Fprint(w, "fail") // 验签失败,可能是伪造通知,拒绝处理
return
}
// 2、校验金额:回调金额格式统一为两位小数(如 1.00),需与商户本地订单金额比对
// order := queryLocalOrder(data["out_trade_no"])
// if data["money"] != fmt.Sprintf("%.2f", order.Money) {
// fmt.Fprint(w, "fail"); return
// }
// 3、处理业务:更新本地订单为已支付(务必做幂等处理,防止重复回调重复入账)
// ...... 你的业务逻辑(发货、开通会员等)
// 4、返回 success 表示回调处理成功,否则平台会间隔重试 5 次
fmt.Fprint(w, "success")
}// ASP.NET Core 示例(Controller)
using Microsoft.AspNetCore.Mvc;
using System.Security.Cryptography;
using System.Text;
[ApiController]
public class NotifyController : ControllerBase
{
// 支付结果异步通知处理(验签 + 金额校验)
[HttpGet("/notify_url.php")]
public IActionResult Notify()
{
string key = "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i"; // 商户密钥
// 1、验证签名:必须使用回调收到的参数参与验签(不要使用本地存储的值)
var data = Request.Query.ToDictionary(x => x.Key, x => x.Value.ToString());
string sign = data["sign"];
var pairs = data.Where(p => p.Key != "sign" && p.Key != "sign_type" && !string.IsNullOrEmpty(p.Value))
.OrderBy(p => p.Key, StringComparer.Ordinal)
.Select(p => $"{p.Key}={p.Value}");
string md5 = Convert.ToHexString(
MD5.HashData(Encoding.UTF8.GetBytes(string.Join("&", pairs) + key))).ToLower();
if (md5 != sign)
{
return Content("fail"); // 验签失败,可能是伪造通知,拒绝处理
}
// 2、校验金额:回调金额格式统一为两位小数(如 1.00),需与商户本地订单金额比对
// var order = db.GetOrder(data["out_trade_no"]);
// if (decimal.Parse(data["money"]).ToString("0.00") != decimal.Parse(order.Money).ToString("0.00"))
// return Content("fail");
// 3、处理业务:更新本地订单为已支付(务必做幂等处理,防止重复回调重复入账)
// ...... 你的业务逻辑(发货、开通会员等)
// 4、返回 success 表示回调处理成功,否则平台会间隔重试 5 次
return Content("success");
}
}// 说明:异步通知(notify_url)必须是公网可访问的服务端地址,App 客户端不直接接收通知。
// App 内常用做法:用户回到支付结果页后,轮询「查询单个订单」接口确认支付状态。
// 以下为 Kotlin(服务端 Ktor / Spring 通用)的验签处理逻辑:
import java.security.MessageDigest
fun handleNotify(data: Map<String, String>): String {
val key = "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i" // 商户密钥
// 1、验证签名:必须使用回调收到的参数参与验签(不要使用本地存储的值)
val query = data.filterKeys { it != "sign" && it != "sign_type" }
.filterValues { it.isNotEmpty() }
.toSortedMap() // 参数按 ASCII 升序
.entries.joinToString("&") { "${it.key}=${it.value}" }
val mySign = MessageDigest.getInstance("MD5").digest((query + key).toByteArray())
.joinToString("") { "%02x".format(it) }
if (mySign != data["sign"]) {
return "fail" // 验签失败,可能是伪造通知,拒绝处理
}
// 2、校验金额:回调金额格式统一为两位小数(如 1.00),需与商户本地订单金额比对
// val order = db.getOrderByOutTradeNo(data["out_trade_no"])
// if (data["money"] != String.format("%.2f", order.money)) return "fail"
// 3、处理业务:更新本地订单为已支付(务必做幂等处理,防止重复回调重复入账)
// ...... 你的业务逻辑(发货、开通会员等)
// 4、返回 success 表示回调处理成功,否则平台会间隔重试 5 次
return "success"
}// 说明:异步通知(notify_url)必须是公网可访问的服务端地址,App 客户端不直接接收通知。
// App 内常用做法:用户回到支付结果页后,轮询「查询单个订单」接口确认支付状态。
// 以下为 Swift(服务端 Vapor 通用)的验签处理逻辑:
import Foundation
import CryptoKit
func handleNotify(_ data: [String: String]) -> String {
let key = "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i" // 商户密钥
// 1、验证签名:必须使用回调收到的参数参与验签(不要使用本地存储的值)
let query = data.filter { $0.key != "sign" && $0.key != "sign_type" && !$0.value.isEmpty }
.sorted { $0.key < $1.key } // 参数按 ASCII 升序
.map { "\($0.key)=\($0.value)" }
.joined(separator: "&")
let mySign = Insecure.MD5.hash(data: Data((query + key).utf8))
.map { String(format: "%02x", $0) }.joined()
if mySign != data["sign"] {
return "fail" // 验签失败,可能是伪造通知,拒绝处理
}
// 2、校验金额:回调金额格式统一为两位小数(如 1.00),需与商户本地订单金额比对
// let order = try db.getOrder(outTradeNo: data["out_trade_no"] ?? "")
// if data["money"] != String(format: "%.2f", order.money) { return "fail" }
// 3、处理业务:更新本地订单为已支付(务必做幂等处理,防止重复回调重复入账)
// ...... 你的业务逻辑(发货、开通会员等)
// 4、返回 success 表示回调处理成功,否则平台会间隔重试 5 次
return "success"
}1、商户系统对于支付结果通知,一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,防止数据泄漏导致出现"假通知",造成资金损失;
2、请使用回调收到的参数参与验签(金额、订单号等均以回调参数为准),不要使用本地存储的值;
3、注意支付状态的参数返回来的如果是大写就要是大写的(TRADE_SUCCESS),不要转成小写;
4、验签时请使用回调收到的全部非空参数参与计算(除 sign、sign_type 外),name 只要收到且非空就必须参与签名,不要自行剔除某个字段;
5、部分境外服务器以及加了cdn或者防御的可能被屏蔽导致回调通知失败,请自行检查原因,建议用大厂服务器比如腾讯云阿里云等也有香港或境外服务器比较稳定,也可以直接通过调用查单接口来达到回调的目的;
6、商户系统不能仅依赖回调通知获取结果,尤其业务使用的服务器在境外的商户,需结合主动查询订单接口使用,避免遗漏或延迟问题,查询订单接口。
回调安全警示
提醒:验签通过不代表订单真的支付成功,回调只能当提醒,不能当支付凭证。
正确做法:
1、收到回调先验签;
2、回调参数白名单:回调只接受平台标准参数,标准字段为 pid、trade_no、out_trade_no、type、name、money、trade_status、sign、sign_type(param 可选),具体分三步校验:
① 字段名单校验:在验签之前,先遍历回调收到的所有参数,凡是不在标准字段列表里的,一律视为可疑回调,直接拒绝、不入账、不返回 success;
② 重复字段校验:每个标准字段只允许出现一次。攻击者常把 trade_status=TRADE_SUCCESS 等参数夹带在其它参数值里,使其与真实参数重复出现,遇到重复字段同样直接拒绝;
③ 最后再验签:确认参数集合合法后,再按MD5签名算法计算签名比对,验签失败直接拒绝。
3、入账前调用查询单个订单,返回 status=1 才入账;
4、金额必须与下单一致,同一订单号只入账一次。
MD5签名算法
1、将发送或接收到的所有参数按照参数名ASCII码从小到大排序(a-z),sign、sign_type、和空值不参与签名!
2、将排序后的参数拼接成URL键值对的格式,例如 a=b&c=d&e=f,参数值不要进行url编码;
3、再将拼接好的字符串与商户密钥KEY进行MD5加密得出sign签名参数,sign = md5 ( a=b&c=d&e=f + KEY )(注意:+ 为各语言的拼接符,不是字符!),md5结果为小写;
4、具体详细的签名教程点此查看。
<?php
/**
* 生成MD5签名
* @param array $data 参与签名的所有参数
* @param string $key 商户密钥
* @return string 签名结果(32位小写)
*/
function getSign($data, $key)
{
// 1、去除 sign、sign_type 以及空值参数(均不参与签名)
unset($data['sign'], $data['sign_type']);
$data = array_filter($data, function ($v) { return $v !== '' && $v !== null; });
// 2、按参数名 ASCII 码从小到大排序(a-z)
ksort($data);
// 3、拼接成 URL 键值对格式:a=b&c=d&e=f(参数值不进行url编码)
$str = urldecode(http_build_query($data));
// 4、拼接商户密钥后进行 MD5 加密(结果为小写)
return md5($str . $key);
}
// 使用示例:
$data = array('pid' => 1001, 'money' => '1.00', 'name' => 'VIP会员');
echo getSign($data, '89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i');
// 输出:32位小写MD5字符串// 需引入 Hutool 工具库,Maven 依赖:cn.hutool:hutool-all
import cn.hutool.crypto.digest.DigestUtil;
import java.util.Map;
import java.util.TreeMap;
public class SignUtil {
/**
* 生成MD5签名
* @param data 参与签名的所有参数
* @param key 商户密钥
* @return 签名结果(32位小写)
*/
public static String getSign(Map<String, String> data, String key) {
// 1、去除 sign、sign_type 以及空值参数(均不参与签名)
data.remove("sign");
data.remove("sign_type");
data.values().removeIf(v -> v == null || v.isEmpty());
// 2、按参数名 ASCII 码从小到大排序(a-z)
TreeMap<String, String> sorted = new TreeMap<>(data);
// 3、拼接成 URL 键值对格式:a=b&c=d&e=f(参数值不进行url编码)
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> e : sorted.entrySet()) {
if (sb.length() > 0) sb.append('&');
sb.append(e.getKey()).append('=').append(e.getValue());
}
// 4、拼接商户密钥后进行 MD5 加密(结果为小写)
return DigestUtil.md5Hex(sb.toString() + key);
}
}# -*- coding: utf-8 -*-
import hashlib
def get_sign(data: dict, key: str) -> str:
"""生成MD5签名
:param data: 参与签名的所有参数
:param key: 商户密钥
:return: 签名结果(32位小写)
"""
# 1、去除 sign、sign_type 以及空值参数(均不参与签名)
data = {k: v for k, v in data.items()
if k not in ('sign', 'sign_type') and v not in ('', None)}
# 2、按参数名 ASCII 码从小到大排序(a-z),拼接成 a=b&c=d&e=f
query = '&'.join(f'{k}={data[k]}' for k in sorted(data))
# 3、拼接商户密钥后进行 MD5 加密(结果为小写)
return hashlib.md5((query + key).encode('utf-8')).hexdigest()
# 使用示例:
data = {'pid': 1001, 'money': '1.00', 'name': 'VIP会员'}
print(get_sign(data, '89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i'))
# 输出:32位小写MD5字符串const crypto = require('crypto');
/**
* 生成MD5签名
* @param {Object} data 参与签名的所有参数
* @param {string} key 商户密钥
* @returns {string} 签名结果(32位小写)
*/
function getSign(data, key) {
// 1、去除 sign、sign_type 以及空值参数(均不参与签名)
const entries = Object.entries(data).filter(
([k, v]) => k !== 'sign' && k !== 'sign_type' && v !== '' && v !== undefined && v !== null
);
// 2、按参数名 ASCII 码从小到大排序(a-z),拼接成 a=b&c=d&e=f
const query = entries.sort((a, b) => a[0].localeCompare(b[0]))
.map(([k, v]) => `${k}=${v}`).join('&');
// 3、拼接商户密钥后进行 MD5 加密(结果为小写)
return crypto.createHash('md5').update(query + key).digest('hex');
}
// 使用示例:
const data = { pid: 1001, money: '1.00', name: 'VIP会员' };
console.log(getSign(data, '89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i'));
// 输出:32位小写MD5字符串// Go 标准库示例,无需第三方依赖
import (
"crypto/md5"
"encoding/hex"
"sort"
"strings"
)
// 生成MD5签名(结果为32位小写)
// data: 参与签名的所有参数;key: 商户密钥
func getSign(data map[string]string, key string) string {
// 1、去除 sign、sign_type 以及空值参数(均不参与签名)
keys := make([]string, 0, len(data))
for k, v := range data {
if v == "" || k == "sign" || k == "sign_type" {
continue
}
keys = append(keys, k)
}
// 2、按参数名 ASCII 码从小到大排序(a-z)
sort.Strings(keys)
// 3、拼接成 URL 键值对格式:a=b&c=d&e=f(参数值不进行url编码)
pairs := make([]string, 0, len(keys))
for _, k := range keys {
pairs = append(pairs, k+"="+data[k])
}
// 4、拼接商户密钥后进行 MD5 加密(结果为小写)
sum := md5.Sum([]byte(strings.Join(pairs, "&") + key))
return hex.EncodeToString(sum[:])
}
// 使用示例:
// data := map[string]string{"pid": "1001", "money": "1.00", "name": "VIP会员"}
// fmt.Println(getSign(data, "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i"))
// 输出:32位小写MD5字符串// .NET 6+ 示例
using System.Security.Cryptography;
using System.Text;
public class SignUtil
{
/// <summary>
/// 生成MD5签名(结果为32位小写)
/// </summary>
/// <param name="data">参与签名的所有参数</param>
/// <param name="key">商户密钥</param>
public static string GetSign(Dictionary<string, string> data, string key)
{
// 1、去除 sign、sign_type 以及空值参数(均不参与签名)
var filtered = data.Where(p => p.Key != "sign" && p.Key != "sign_type" && !string.IsNullOrEmpty(p.Value));
// 2、按参数名 ASCII 码从小到大排序(a-z),拼接成 a=b&c=d&e=f
var query = string.Join("&", filtered
.OrderBy(p => p.Key, StringComparer.Ordinal)
.Select(p => $"{p.Key}={p.Value}"));
// 3、拼接商户密钥后进行 MD5 加密(结果为小写)
return Convert.ToHexString(
MD5.HashData(Encoding.UTF8.GetBytes(query + key))).ToLower();
}
}
// 使用示例:
// var data = new Dictionary<string, string> { ["pid"] = "1001", ["money"] = "1.00", ["name"] = "VIP会员" };
// Console.WriteLine(SignUtil.GetSign(data, "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i"));
// 输出:32位小写MD5字符串// Kotlin 示例(安卓 / 服务端通用)
import java.security.MessageDigest
/**
* 生成MD5签名(结果为32位小写)
* @param data 参与签名的所有参数
* @param key 商户密钥
*/
fun getSign(data: Map<String, String>, key: String): String {
// 1、去除 sign、sign_type 以及空值参数(均不参与签名)
val filtered = data.filterKeys { it != "sign" && it != "sign_type" }
.filterValues { it.isNotEmpty() }
// 2、按参数名 ASCII 码从小到大排序(a-z),拼接成 a=b&c=d&e=f
val query = filtered.toSortedMap()
.entries.joinToString("&") { "${it.key}=${it.value}" }
// 3、拼接商户密钥后进行 MD5 加密(结果为小写)
return MessageDigest.getInstance("MD5").digest((query + key).toByteArray())
.joinToString("") { "%02x".format(it) }
}
// 使用示例:
// val data = mapOf("pid" to "1001", "money" to "1.00", "name" to "VIP会员")
// println(getSign(data, "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i"))
// 输出:32位小写MD5字符串// iOS 示例(Swift 5+),使用系统 CryptoKit,无需第三方库
import Foundation
import CryptoKit
/// 生成MD5签名(结果为32位小写)
/// - Parameters:
/// - data: 参与签名的所有参数
/// - key: 商户密钥
func getSign(_ data: [String: String], key: String) -> String {
// 1、去除 sign、sign_type 以及空值参数(均不参与签名)
let filtered = data.filter { $0.key != "sign" && $0.key != "sign_type" && !$0.value.isEmpty }
// 2、按参数名 ASCII 码从小到大排序(a-z),拼接成 a=b&c=d&e=f
let query = filtered.sorted { $0.key < $1.key }
.map { "\($0.key)=\($0.value)" }
.joined(separator: "&")
// 3、拼接商户密钥后进行 MD5 加密(结果为小写)
let digest = Insecure.MD5.hash(data: Data((query + key).utf8))
return digest.map { String(format: "%02x", $0) }.joined()
}
// 使用示例:
// let data = ["pid": "1001", "money": "1.00", "name": "VIP会员"]
// print(getSign(data, key: "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i"))
// 输出:32位小写MD5字符串支付方式列表
| 调用值 | 描述 |
|---|---|
alipay | 支付宝 |
wxpay | 微信支付 |
设备类型列表
| 调用值 | 描述 |
|---|---|
pc | 二维码链接-返回的是二维码链接(自行转换成二维码),默认不是微信原生二维码链接,若需原生链接请联系客服 |
mobile | H5调起支付/APP支付-返回的是跳转URL(中间页跳转模式/仅支持手机端访问) |
wechat | 微信内支付-返回的是跳转URL(JSAPI公众号支付/仅支持手机微信内支付) |
jump | 仅返回支付跳转url(自适应页面,推荐) |
提示1:若微信的H5调起支付不想用中间页模式的请换"jump"自适应的方法可直接跳转唤起;
提示2:如需开启微信内支付完成同步跳转你的页面功能,既"点金计划",请联系客服开通;
提示3:微信内支付建议直接跳转支付链接付款即可,不要转成二维码长按识别付款,容易风控;
提示4:pc返回的二维码链接一般默认不是微信原生二维码链接及支付页面,若需原生链接页面请联系客服。
[API]查询商户信息
请求参数说明:
| 字段名 | 变量名 | 必填 | 类型 | 示例值 | 描述 |
|---|---|---|---|---|---|
| 操作类型 | act | 是 | String | query | 此API固定值 |
| 商户ID | pid | 是 | Int | 1001 | |
| 商户密钥 | key | 是 | String | 89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i |
返回结果:
| 字段名 | 变量名 | 类型 | 示例值 | 描述 |
|---|---|---|---|---|
| 返回状态码 | code | Int | 1 | 1为成功,其它值为失败 |
| 商户ID | pid | Int | 1001 | 商户ID |
| 商户密钥 | key | String(32) | 89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i | 商户密钥 |
| 商户状态 | active | Int | 1 | 1为正常,0为封禁 |
| 商户手续费余额 | money | String | 0.00 | 商户所拥有的手续费余额 |
| 用不到忽略即可 | type | Int | 用不到忽略即可 | 用不到忽略即可 |
| 用不到忽略即可 | account | String | 用不到忽略即可 | 用不到忽略即可 |
| 用不到忽略即可 | username | String | 用不到忽略即可 | 用不到忽略即可 |
| 订单总数 | orders | Int | 30 | 订单总数统计 |
| 今日订单 | order_today | Int | 15 | 今日订单数量 |
| 昨日订单 | order_lastday | Int | 15 | 昨日订单数量 |
<?php
// 查询商户信息(GET请求)
$url = 'https://api.payqixiang.cn/api.php?act=query&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i';
$res = json_decode(file_get_contents($url), true);
if (isset($res['code']) && $res['code'] == 1) {
echo '商户状态:' . ($res['active'] == 1 ? '正常' : '封禁');
echo ',订单总数:' . $res['orders'] . ',今日订单:' . $res['order_today'];
} else {
echo '查询失败:' . $res['msg'];
}// 需引入 Hutool 工具库,Maven 依赖:cn.hutool:hutool-all
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
public class QueryDemo {
public static void main(String[] args) {
// 查询商户信息(GET请求)
String url = "https://api.payqixiang.cn/api.php?act=query&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i";
JSONObject res = JSONUtil.parseObj(HttpUtil.get(url));
if (res.getInt("code") == 1) {
System.out.println("商户状态:" + (res.getInt("active") == 1 ? "正常" : "封禁"));
System.out.println("订单总数:" + res.getInt("orders") + ",今日订单:" + res.getInt("order_today"));
} else {
System.out.println("查询失败:" + res.getStr("msg"));
}
}
}# pip install requests
import requests
# 查询商户信息(GET请求)
url = 'https://api.payqixiang.cn/api.php'
params = {
'act': 'query',
'pid': '1001',
'key': '89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i',
}
res = requests.get(url, params=params).json()
if res.get('code') == 1:
print('商户状态:', '正常' if res['active'] == 1 else '封禁')
print('订单总数:', res['orders'], ',今日订单:', res['order_today'])
else:
print('查询失败:', res.get('msg'))// Node.js 18+ 内置 fetch,无需额外依赖
const url = 'https://api.payqixiang.cn/api.php' +
'?act=query&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i';
// 查询商户信息(GET请求)
const res = await fetch(url).then(r => r.json());
if (res.code === 1) {
console.log('商户状态:', res.active === 1 ? '正常' : '封禁');
console.log('订单总数:', res.orders, ',今日订单:', res.order_today);
} else {
console.log('查询失败:', res.msg);
}// Go 标准库示例,无需第三方依赖
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
// 查询商户信息(GET请求)
url := "https://api.payqixiang.cn/api.php?act=query&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i"
resp, _ := http.Get(url)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var res map[string]interface{}
json.Unmarshal(body, &res)
if res["code"] == float64(1) {
status := "封禁"
if res["active"] == float64(1) {
status = "正常"
}
fmt.Println("商户状态:", status, ",订单总数:", res["orders"], ",今日订单:", res["order_today"])
} else {
fmt.Println("查询失败:", res["msg"])
}
}// .NET 6+ 示例,使用 HttpClient
using System.Text.Json;
// 查询商户信息(GET请求)
using var client = new HttpClient();
var url = "https://api.payqixiang.cn/api.php?act=query&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i";
using var doc = JsonDocument.Parse(await client.GetStringAsync(url));
var res = doc.RootElement;
if (res.GetProperty("code").GetInt32() == 1)
{
var status = res.GetProperty("active").GetInt32() == 1 ? "正常" : "封禁";
Console.WriteLine("商户状态:" + status);
Console.WriteLine("订单总数:" + res.GetProperty("orders").GetInt32()
+ ",今日订单:" + res.GetProperty("order_today").GetInt32());
}
else
{
Console.WriteLine("查询失败:" + (res.TryGetProperty("msg", out var msg) ? msg.GetString() : "未知错误"));
}// 安卓示例,需引入 OkHttp:implementation("com.squareup.okhttp3:okhttp:4.12.0")
// org.json 已内置于 Android 系统,无需额外引入
import okhttp3.OkHttpClient
import okhttp3.Request
import org.json.JSONObject
fun queryMerchantInfo() {
// 查询商户信息(GET请求)
val url = "https://api.payqixiang.cn/api.php?act=query&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i"
val request = Request.Builder().url(url).build()
val body = OkHttpClient().newCall(request).execute().body?.string()
val res = JSONObject(body)
if (res.optInt("code") == 1) {
val status = if (res.optInt("active") == 1) "正常" else "封禁"
println("商户状态:$status,订单总数:${res.optInt("orders")},今日订单:${res.optInt("order_today")}")
} else {
println("查询失败:" + res.optString("msg"))
}
}// iOS 示例(Swift 5+),使用 URLSession,无需第三方库
import Foundation
func queryMerchantInfo() {
// 查询商户信息(GET请求)
let url = "https://api.payqixiang.cn/api.php?act=query&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i"
let request = URLRequest(url: URL(string: url)!)
URLSession.shared.dataTask(with: request) { data, _, _ in
guard let data = data,
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let code = json["code"] as? Int else { return }
if code == 1 {
let active = (json["active"] as? Int) == 1 ? "正常" : "封禁"
print("商户状态:\(active),订单总数:\(json["orders"] ?? 0),今日订单:\(json["order_today"] ?? 0)")
} else {
print("查询失败:\(json["msg"] ?? "")")
}
}.resume()
}[API]查询单个订单
请求参数说明:
| 字段名 | 变量名 | 必填 | 类型 | 示例值 | 描述 |
|---|---|---|---|---|---|
| 操作类型 | act | 是 | String | order | 此API固定值 |
| 商户ID | pid | 是 | Int | 1001 | |
| 商户密钥 | key | 是 | String | 89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i | |
| 系统订单号 | trade_no | 选择 | String | 20160806151343312 | |
| 商户订单号 | out_trade_no | 选择 | String | 20160806151343349 |
提示:系统订单号 和 商户订单号 二选一传入即可,如果都传入以系统订单号为准!
返回结果:
| 字段名 | 变量名 | 类型 | 示例值 | 描述 |
|---|---|---|---|---|
| 返回状态码 | code | Int | 1 | 1为成功,其它值为失败 |
| 返回信息 | msg | String | 查询订单号成功! | |
| 七相支付订单号 | trade_no | String | 2016080622555342651 | 七相支付订单号 |
| 商户订单号 | out_trade_no | String | 20160806151343349 | 商户系统内部的订单号 |
| 第三方订单号 | api_trade_no | String | 20160806151343349 | 支付宝微信等接口方订单号 |
| 支付方式 | type | String | alipay | 支付方式列表 |
| 商户ID | pid | Int | 1001 | 发起支付的商户ID |
| 创建订单时间 | addtime | String | 2016-08-06 22:55:52 | |
| 完成交易时间 | endtime | String | 2016-08-06 22:55:52 | |
| 商品名称 | name | String | VIP会员 | |
| 商品金额 | money | String | 1.00 | |
| 支付状态 | status | Int | 0 | 1为支付成功,0为未支付 |
| 业务扩展参数 | param | String | 默认留空 | |
| 支付者账号(OpenID) | buyer | String | 默认留空 |
<?php
// 查询单个订单(GET请求,trade_no 与 out_trade_no 二选一传入)
$url = 'https://api.payqixiang.cn/api.php?act=order&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i&out_trade_no=20260929123456789';
$res = json_decode(file_get_contents($url), true);
if (isset($res['code']) && $res['code'] == 1) {
echo '订单状态:' . ($res['status'] == 1 ? '已支付' : '未支付');
echo ',订单金额:' . $res['money'];
} else {
echo '查询失败:' . $res['msg'];
}// 需引入 Hutool 工具库,Maven 依赖:cn.hutool:hutool-all
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
public class OrderQueryDemo {
public static void main(String[] args) {
// 查询单个订单(trade_no 与 out_trade_no 二选一传入)
String url = "https://api.payqixiang.cn/api.php?act=order"
+ "&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i"
+ "&out_trade_no=20260929123456789";
JSONObject res = JSONUtil.parseObj(HttpUtil.get(url));
if (res.getInt("code") == 1) {
System.out.println("订单状态:" + (res.getInt("status") == 1 ? "已支付" : "未支付"));
System.out.println("订单金额:" + res.getStr("money"));
} else {
System.out.println("查询失败:" + res.getStr("msg"));
}
}
}# pip install requests
import requests
# 查询单个订单(trade_no 与 out_trade_no 二选一传入)
url = 'https://api.payqixiang.cn/api.php'
params = {
'act': 'order',
'pid': '1001',
'key': '89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i',
'out_trade_no': '20260929123456789',
}
res = requests.get(url, params=params).json()
if res.get('code') == 1:
print('订单状态:', '已支付' if res['status'] == 1 else '未支付')
print('订单金额:', res['money'])
else:
print('查询失败:', res.get('msg'))// Node.js 18+ 内置 fetch,无需额外依赖
const url = 'https://api.payqixiang.cn/api.php' +
'?act=order&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i' +
'&out_trade_no=20260929123456789';
// 查询单个订单(trade_no 与 out_trade_no 二选一传入)
const res = await fetch(url).then(r => r.json());
if (res.code === 1) {
console.log('订单状态:', res.status === 1 ? '已支付' : '未支付');
console.log('订单金额:', res.money);
} else {
console.log('查询失败:', res.msg);
}// Go 标准库示例,无需第三方依赖
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
// 查询单个订单(GET请求,trade_no 与 out_trade_no 二选一传入)
url := "https://api.payqixiang.cn/api.php?act=order&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i&out_trade_no=20260929123456789"
resp, _ := http.Get(url)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var res map[string]interface{}
json.Unmarshal(body, &res)
if res["code"] == float64(1) {
status := "未支付"
if res["status"] == float64(1) {
status = "已支付"
}
fmt.Println("订单状态:", status, ",订单金额:", res["money"])
} else {
fmt.Println("查询失败:", res["msg"])
}
}// .NET 6+ 示例,使用 HttpClient
using System.Text.Json;
// 查询单个订单(GET请求,trade_no 与 out_trade_no 二选一传入)
using var client = new HttpClient();
var url = "https://api.payqixiang.cn/api.php?act=order&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i&out_trade_no=20260929123456789";
using var doc = JsonDocument.Parse(await client.GetStringAsync(url));
var res = doc.RootElement;
if (res.GetProperty("code").GetInt32() == 1)
{
var status = res.GetProperty("status").GetInt32() == 1 ? "已支付" : "未支付";
Console.WriteLine("订单状态:" + status + ",订单金额:" + res.GetProperty("money").GetString());
}
else
{
Console.WriteLine("查询失败:" + (res.TryGetProperty("msg", out var msg) ? msg.GetString() : "未知错误"));
}// 安卓示例,需引入 OkHttp:implementation("com.squareup.okhttp3:okhttp:4.12.0")
import okhttp3.OkHttpClient
import okhttp3.Request
import org.json.JSONObject
fun queryOrder() {
// 查询单个订单(GET请求,trade_no 与 out_trade_no 二选一传入)
val url = "https://api.payqixiang.cn/api.php?act=order&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i&out_trade_no=20260929123456789"
val request = Request.Builder().url(url).build()
val body = OkHttpClient().newCall(request).execute().body?.string()
val res = JSONObject(body)
if (res.optInt("code") == 1) {
val status = if (res.optInt("status") == 1) "已支付" else "未支付"
println("订单状态:$status,订单金额:${res.optString("money")}")
} else {
println("查询失败:" + res.optString("msg"))
}
}// iOS 示例(Swift 5+),使用 URLSession,无需第三方库
import Foundation
func queryOrder() {
// 查询单个订单(GET请求,trade_no 与 out_trade_no 二选一传入)
let url = "https://api.payqixiang.cn/api.php?act=order&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i&out_trade_no=20260929123456789"
let request = URLRequest(url: URL(string: url)!)
URLSession.shared.dataTask(with: request) { data, _, _ in
guard let data = data,
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let code = json["code"] as? Int else { return }
if code == 1 {
let status = (json["status"] as? Int) == 1 ? "已支付" : "未支付"
print("订单状态:\(status),订单金额:\(json["money"] ?? "")")
} else {
print("查询失败:\(json["msg"] ?? "")")
}
}.resume()
}[API]批量查询订单
请求参数说明:
| 字段名 | 变量名 | 必填 | 类型 | 示例值 | 描述 |
|---|---|---|---|---|---|
| 操作类型 | act | 是 | String | orders | 此API固定值 |
| 商户ID | pid | 是 | Int | 1001 | |
| 商户密钥 | key | 是 | String | 89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i | |
| 查询订单数量 | limit | 否 | Int | 20 | 返回的订单数量,最大50 |
| 页码 | page | 否 | Int | 1 | 当前查询的页码 |
返回结果:
| 字段名 | 变量名 | 类型 | 示例值 | 描述 |
|---|---|---|---|---|
| 返回状态码 | code | Int | 1 | 1为成功,其它值为失败 |
| 返回信息 | msg | String | 查询订单记录成功! | |
| 订单列表 | data | Array | 订单列表 |
<?php
// 批量查询订单(GET请求)
$url = 'https://api.payqixiang.cn/api.php?act=orders&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i&limit=20&page=1';
$res = json_decode(file_get_contents($url), true);
if (isset($res['code']) && $res['code'] == 1) {
foreach ($res['data'] as $order) {
echo $order['out_trade_no'] . ' - ' . $order['money'] . '元 - ' . ($order['status'] == 1 ? '已支付' : '未支付') . PHP_EOL;
}
} else {
echo '查询失败:' . $res['msg'];
}// 需引入 Hutool 工具库,Maven 依赖:cn.hutool:hutool-all
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
public class OrdersQueryDemo {
public static void main(String[] args) {
// 批量查询订单(GET请求)
String url = "https://api.payqixiang.cn/api.php?act=orders"
+ "&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i&limit=20&page=1";
JSONObject res = JSONUtil.parseObj(HttpUtil.get(url));
if (res.getInt("code") == 1) {
JSONArray list = res.getJSONArray("data");
for (Object o : list) {
JSONObject order = (JSONObject) o;
System.out.println(order.getStr("out_trade_no") + " - "
+ order.getStr("money") + "元 - "
+ (order.getInt("status") == 1 ? "已支付" : "未支付"));
}
} else {
System.out.println("查询失败:" + res.getStr("msg"));
}
}
}# pip install requests
import requests
# 批量查询订单(GET请求)
url = 'https://api.payqixiang.cn/api.php'
params = {
'act': 'orders',
'pid': '1001',
'key': '89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i',
'limit': 20,
'page': 1,
}
res = requests.get(url, params=params).json()
if res.get('code') == 1:
for order in res['data']:
print(order['out_trade_no'], '-', order['money'], '元 -',
'已支付' if order['status'] == 1 else '未支付')
else:
print('查询失败:', res.get('msg'))// Node.js 18+ 内置 fetch,无需额外依赖
const url = 'https://api.payqixiang.cn/api.php' +
'?act=orders&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i&limit=20&page=1';
// 批量查询订单(GET请求)
const res = await fetch(url).then(r => r.json());
if (res.code === 1) {
for (const order of res.data) {
console.log(`${order.out_trade_no} - ${order.money}元 - ${order.status === 1 ? '已支付' : '未支付'}`);
}
} else {
console.log('查询失败:', res.msg);
}// Go 标准库示例,无需第三方依赖
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
// 批量查询订单(GET请求)
url := "https://api.payqixiang.cn/api.php?act=orders&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i&limit=20&page=1"
resp, _ := http.Get(url)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var res map[string]interface{}
json.Unmarshal(body, &res)
if res["code"] == float64(1) {
if list, ok := res["data"].([]interface{}); ok {
for _, item := range list {
order := item.(map[string]interface{})
status := "未支付"
if order["status"] == float64(1) {
status = "已支付"
}
fmt.Println(order["out_trade_no"], "-", order["money"], "元 -", status)
}
}
} else {
fmt.Println("查询失败:", res["msg"])
}
}// .NET 6+ 示例,使用 HttpClient
using System.Text.Json;
// 批量查询订单(GET请求)
using var client = new HttpClient();
var url = "https://api.payqixiang.cn/api.php?act=orders&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i&limit=20&page=1";
using var doc = JsonDocument.Parse(await client.GetStringAsync(url));
var res = doc.RootElement;
if (res.GetProperty("code").GetInt32() == 1)
{
foreach (var order in res.GetProperty("data").EnumerateArray())
{
var status = order.GetProperty("status").GetInt32() == 1 ? "已支付" : "未支付";
Console.WriteLine(order.GetProperty("out_trade_no").GetString() + " - "
+ order.GetProperty("money").GetString() + "元 - " + status);
}
}
else
{
Console.WriteLine("查询失败:" + (res.TryGetProperty("msg", out var msg) ? msg.GetString() : "未知错误"));
}// 安卓示例,需引入 OkHttp:implementation("com.squareup.okhttp3:okhttp:4.12.0")
import okhttp3.OkHttpClient
import okhttp3.Request
import org.json.JSONObject
fun queryOrders() {
// 批量查询订单(GET请求)
val url = "https://api.payqixiang.cn/api.php?act=orders&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i&limit=20&page=1"
val request = Request.Builder().url(url).build()
val body = OkHttpClient().newCall(request).execute().body?.string()
val res = JSONObject(body)
if (res.optInt("code") == 1) {
val orders = res.optJSONArray("data") ?: return
for (i in 0 until orders.length()) {
val order = orders.optJSONObject(i) ?: continue
val status = if (order.optInt("status") == 1) "已支付" else "未支付"
println("${order.optString("out_trade_no")} - ${order.optString("money")}元 - $status")
}
} else {
println("查询失败:" + res.optString("msg"))
}
}// iOS 示例(Swift 5+),使用 URLSession,无需第三方库
import Foundation
func queryOrders() {
// 批量查询订单(GET请求)
let url = "https://api.payqixiang.cn/api.php?act=orders&pid=1001&key=89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i&limit=20&page=1"
let request = URLRequest(url: URL(string: url)!)
URLSession.shared.dataTask(with: request) { data, _, _ in
guard let data = data,
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let code = json["code"] as? Int else { return }
if code == 1, let orders = json["data"] as? [[String: Any]] {
for order in orders {
let status = (order["status"] as? Int) == 1 ? "已支付" : "未支付"
print("\(order["out_trade_no"] ?? "") - \(order["money"] ?? "")元 - \(status)")
}
} else {
print("查询失败:\(json["msg"] ?? "")")
}
}.resume()
}[API]提交订单退款
注意:需要先在商户后台开启订单退款API接口开关,才能调用该接口发起订单退款。
请求参数说明:
| 字段名 | 变量名 | 必填 | 类型 | 示例值 | 描述 |
|---|---|---|---|---|---|
| 商户ID | pid | 是 | Int | 1001 | |
| 商户密钥 | key | 是 | String | 89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i | |
| 七相系统订单号 | trade_no | 特殊可选 | String | 20160806151343349021 | 七相系统订单号 |
| 商户订单号 | out_trade_no | 特殊可选 | String | 20160806151343349 | 订单支付时传入的商户订单号,商家自定义且保证商家系统中唯一 |
| 退款金额 | money | 是 | String | 1.50 | 少数通道需要与原订单金额一致 |
注:trade_no、out_trade_no 不能同时为空,如果都传了以trade_no为准。
返回结果:
| 字段名 | 变量名 | 类型 | 示例值 | 描述 |
|---|---|---|---|---|
| 返回状态码 | code | Int | 1 | 1或0为成功,其它值为失败 |
| 返回信息 | msg | String | 退款成功 |
<?php
// 提交订单退款(POST请求,需先在商户后台开启订单退款API接口开关)
$api = 'https://api.payqixiang.cn/api.php?act=refund';
$data = array(
'pid' => '1001',
'key' => '89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i',
'out_trade_no' => '20260929123456789', // 与 trade_no 二选一
'money' => '1.00', // 退款金额
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $api);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
$res = json_decode($result, true);
if (isset($res['code']) && ($res['code'] == 1 || $res['code'] == 0)) {
echo '退款成功';
} else {
echo '退款失败:' . (isset($res['msg']) ? $res['msg'] : '未知错误');
}// 需引入 Hutool 工具库,Maven 依赖:cn.hutool:hutool-all
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
public class RefundDemo {
public static void main(String[] args) {
// 提交订单退款(POST请求,需先在商户后台开启订单退款API接口开关)
String api = "https://api.payqixiang.cn/api.php?act=refund";
String result = HttpRequest.post(api)
.form("pid", "1001")
.form("key", "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i")
.form("out_trade_no", "20260929123456789") // 与 trade_no 二选一
.form("money", "1.00") // 退款金额
.execute()
.body();
JSONObject res = JSONUtil.parseObj(result);
int code = res.getInt("code");
if (code == 1 || code == 0) { // 1或0均为成功
System.out.println("退款成功");
} else {
System.out.println("退款失败:" + res.getStr("msg", "未知错误"));
}
}
}# pip install requests
import requests
# 提交订单退款(POST请求,需先在商户后台开启订单退款API接口开关)
api = 'https://api.payqixiang.cn/api.php?act=refund'
data = {
'pid': '1001',
'key': '89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i',
'out_trade_no': '20260929123456789', # 与 trade_no 二选一
'money': '1.00', # 退款金额
}
res = requests.post(api, data=data).json()
if res.get('code') in (0, 1): # 1或0均为成功
print('退款成功')
else:
print('退款失败:', res.get('msg', '未知错误'))
// Node.js 18+ 内置 fetch,无需额外依赖
// 提交订单退款(POST请求,需先在商户后台开启订单退款API接口开关)
const api = 'https://api.payqixiang.cn/api.php?act=refund';
const body = new URLSearchParams({
pid: '1001',
key: '89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i',
out_trade_no: '20260929123456789', // 与 trade_no 二选一
money: '1.00', // 退款金额
});
const res = await fetch(api, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body,
}).then(r => r.json());
if (res.code === 1 || res.code === 0) { // 1或0均为成功
console.log('退款成功');
} else {
console.log('退款失败:', res.msg || '未知错误');
}// Go 标准库示例,无需第三方依赖
package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
func main() {
// 提交订单退款(POST请求,需先在商户后台开启订单退款API接口开关)
api := "https://api.payqixiang.cn/api.php?act=refund"
form := url.Values{
"pid": {"1001"},
"key": {"89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i"},
"out_trade_no": {"20260929123456789"}, // 与 trade_no 二选一
"money": {"1.00"}, // 退款金额
}
resp, err := http.PostForm(api, form)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body)) // 解析 JSON:code 为 1 或 0 均为退款成功
}// .NET 6+ 示例,使用 HttpClient
using System.Text.Json;
// 提交订单退款(POST请求,需先在商户后台开启订单退款API接口开关)
using var client = new HttpClient();
var api = "https://api.payqixiang.cn/api.php?act=refund";
var form = new Dictionary<string, string>
{
["pid"] = "1001",
["key"] = "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i",
["out_trade_no"] = "20260929123456789", // 与 trade_no 二选一
["money"] = "1.00", // 退款金额
};
var resp = await client.PostAsync(api, new FormUrlEncodedContent(form));
using var doc = JsonDocument.Parse(await resp.Content.ReadAsStringAsync());
var res = doc.RootElement;
int code = res.GetProperty("code").GetInt32();
if (code == 1 || code == 0) // 1或0均为成功
{
Console.WriteLine("退款成功");
}
else
{
Console.WriteLine("退款失败:" + (res.TryGetProperty("msg", out var msg) ? msg.GetString() : "未知错误"));
}// 安卓示例,需引入 OkHttp:implementation("com.squareup.okhttp3:okhttp:4.12.0")
// 网络请求需在子线程执行(如协程 withContext(Dispatchers.IO))
import okhttp3.FormBody
import okhttp3.OkHttpClient
import okhttp3.Request
import org.json.JSONObject
fun refundOrder() {
// 提交订单退款(POST请求,需先在商户后台开启订单退款API接口开关)
val api = "https://api.payqixiang.cn/api.php?act=refund"
val form = FormBody.Builder()
.add("pid", "1001")
.add("key", "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i")
.add("out_trade_no", "20260929123456789") // 与 trade_no 二选一
.add("money", "1.00") // 退款金额
.build()
val request = Request.Builder().url(api).post(form).build()
val body = OkHttpClient().newCall(request).execute().body?.string()
val res = JSONObject(body)
val code = res.optInt("code", -1)
if (code == 1 || code == 0) { // 1或0均为成功
println("退款成功")
} else {
println("退款失败:" + res.optString("msg", "未知错误"))
}
}// iOS 示例(Swift 5+),使用 URLSession,无需第三方库
import Foundation
func refundOrder() {
// 提交订单退款(POST请求,需先在商户后台开启订单退款API接口开关)
let api = "https://api.payqixiang.cn/api.php?act=refund"
let form = [
"pid": "1001",
"key": "89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i",
"out_trade_no": "20260929123456789", // 与 trade_no 二选一
"money": "1.00", // 退款金额
]
var request = URLRequest(url: URL(string: api)!)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpBody = form.map { "\($0.key)=\($0.value)" }
.joined(separator: "&").data(using: .utf8)
URLSession.shared.dataTask(with: request) { data, _, _ in
guard let data = data,
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let code = json["code"] as? Int else { return }
if code == 1 || code == 0 { // 1或0均为成功
print("退款成功")
} else {
print("退款失败:\(json["msg"] ?? "未知错误")")
}
}.resume()
}注意:退款是从当天未结算的款项里面退的,退款是扣不了已经提现到你银行卡里面的款项。如果当天收款小于本次退款的金额,请在自己业务网站系统里自己下单支付一笔,再来提交本次退款。例如:当天只收了100块钱,但是要退200块钱,就需要自己去自己业务网站系统里自己下单支付一笔,只要大于等于退款的金额即可。
SDK下载
SDK/DEMO语言:JAVA / PHP / ASP / Python / C# / JavaScript-Node.js
注意:注意查看DEMO里面的支付网关地址是否与开发文档上面的支付网关地址一致,若不一致请以开发文档上面地址为准!!!
你也可以把以上开发文档所有的文字复制到豆包AI或者其他AI上面,告诉AI你的要求,让AI帮你生成你对应语言的支付接口代码。