支付网关API为商户提供在线支付能力。商户通过HTTP POST方式提交支付请求,系统返回支付链接或二维码,用户完成支付后系统通过异步通知和同步跳转两种方式通知商户支付结果。
https://您的域名/pay所有需要签名的接口使用相同的签名算法,步骤如下:
key1=value1&key2=value2&......&key=商户APIKEYpay_md5sign 参数本身不参与签名&key=APIKEY 结尾,不要漏掉 &function createSign($params, $apikey) {
ksort($params); // 按键名字典序排序
$md5str = "";
foreach ($params as $key => $val) {
if (!empty($val)) { // 空值不参与签名
$md5str .= $key . "=" . $val . "&";
}
}
$sign = strtoupper(md5($md5str . "key=" . $apikey));
return $sign;
}
import hashlib
def create_sign(params, apikey):
# 按键名字典序排序
sorted_params = sorted(params.items())
# 拼接字符串
parts = [f'{k}={v}' for k, v in sorted_params if v]
sign_str = '&'.join(parts) + '&key=' + apikey
# MD5 大写
return hashlib.md5(sign_str.encode()).hexdigest().upper()
import java.security.MessageDigest;
import java.util.Map;
import java.util.TreeMap;
public static String createSign(Map params, String apikey)
throws Exception {
// 使用 TreeMap 按键名字典序排序
Map sortedParams = new TreeMap<>(params);
StringBuilder sb = new StringBuilder();
for (Map.Entry entry : sortedParams.entrySet()) {
String val = entry.getValue();
if (val != null && !val.isEmpty()) {
sb.append(entry.getKey()).append("=").append(val).append("&");
}
}
sb.append("key=").append(apikey);
// MD5 大写
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(sb.toString().getBytes("UTF-8"));
StringBuilder hexString = new StringBuilder();
for (byte b : digest) {
hexString.append(String.format("%02X", b));
}
return hexString.toString();
}
import (
"crypto/md5"
"encoding/hex"
"sort"
"strings"
)
func createSign(params map[string]string, apikey string) string {
// 按键名字典序排序
keys := make([]string, 0, len(params))
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
// 拼接字符串
parts := make([]string, 0)
for _, k := range keys {
v := params[k]
if v != "" {
parts = append(parts, k+"="+v)
}
}
signStr := strings.Join(parts, "&") + "&key=" + apikey
// MD5 大写
hash := md5.Sum([]byte(signStr))
return strings.ToUpper(hex.EncodeToString(hash[:]))
}
const crypto = require('crypto');
function createSign(params, apikey) {
// 按键名字典序排序
const sortedKeys = Object.keys(params).sort();
// 拼接字符串
const parts = [];
sortedKeys.forEach(key => {
if (params[key]) {
parts.push(`${key}=${params[key]}`);
}
});
const signStr = parts.join('&') + '&key=' + apikey;
// MD5 大写
return crypto.createHash('md5')
.update(signStr)
.digest('hex')
.toUpperCase();
}
/pay/index/index
商户提交支付订单,系统返回支付页面链接。
| 参数名 | 必填 | 类型 | 说明 |
|---|---|---|---|
| pay_memberid | 是 | String | 商户号(后台获取,如10001) |
| pay_orderid | 是 | String | 商户订单号(唯一,32字符以内) |
| pay_amount | 是 | String | 支付金额(元,如100.00) |
| pay_applydate | 是 | String | 提交时间(格式:Y-m-d H:i:s) |
| pay_bankcode | 是 | String | 支付通道编号(后台通道费率页面获取) |
| pay_notifyurl | 是 | String | 异步通知地址(支付结果异步回调) |
| pay_callbackurl | 是 | String | 同步跳转地址(支付完成后页面跳转) |
| pay_md5sign | 是 | String | MD5签名(32位大写) |
| pay_attach | 否 | String | 附加数据(原样返回,不参与签名) |
| pay_productname | 否 | String | 商品名称 |
pay_memberid, pay_orderid, pay_amount, pay_applydate,
pay_bankcode, pay_notifyurl, pay_callbackurl, pay_attach
根据商户配置的返回格式(JSON/XML/重定向),系统返回支付链接:
// JSON格式响应
{
"status": "200",
"msg": "成功",
"data": {
"url": "https://支付页面地址"
}
}
{
"status": "error",
"msg": "错误描述",
"data": []
}
/pay/trade/query
商户主动查询订单支付状态。
| 参数名 | 必填 | 类型 | 说明 |
|---|---|---|---|
| pay_memberid | 是 | String | 商户号 |
| pay_orderid | 是 | String | 商户订单号 |
| pay_md5sign | 是 | String | MD5签名 |
pay_memberid, pay_orderid
{
"status": 200,
"msg": "查询成功",
"data": {
"memberid": "10001", // 商户号
"orderid": "202401010001", // 商户订单号
"amount": "100.00", // 支付金额
"time_end": "2024-01-01 12:00:00", // 支付完成时间
"transaction_id": "A0101120000...", // 系统流水号
"returncode": "00", // 00=成功 1=未支付
"trade_state": "SUCCESS" // SUCCESS=已支付 NOTPAY=未支付
}
}
// 订单查询示例
$params = [
'pay_memberid' => '10001',
'pay_orderid' => '202401010001',
];
$params['pay_md5sign'] = createSign($params, $apikey);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://您的域名/pay/trade/query');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
if ($result['status'] == 200) {
echo '支付状态:' . $result['data']['trade_state'];
} else {
echo '查询失败:' . $result['msg'];
}
import hashlib
import requests
# 商户配置
mchid = '10001'
apikey = '您的APIKEY'
gateway = 'https://您的域名/pay/trade/query'
# 查询参数
params = {
'pay_memberid': mchid,
'pay_orderid': '202401010001',
}
# 生成签名
def create_sign(params, apikey):
sorted_params = sorted(params.items())
parts = [f'{k}={v}' for k, v in sorted_params if v and k != 'pay_md5sign']
sign_str = '&'.join(parts) + '&key=' + apikey
return hashlib.md5(sign_str.encode()).hexdigest().upper()
params['pay_md5sign'] = create_sign(params, apikey)
# 发送请求
response = requests.post(gateway, data=params)
result = response.json()
if result.get('status') == 200:
print('支付状态:', result['data']['trade_state'])
else:
print('查询失败:', result.get('msg'))
import java.io.*;
import java.net.*;
import java.security.MessageDigest;
import java.util.*;
public class PayQueryDemo {
public static void main(String[] args) throws Exception {
String mchid = "10001";
String apikey = "您的APIKEY";
String gateway = "https://您的域名/pay/trade/query";
// 查询参数
Map params = new TreeMap<>();
params.put("pay_memberid", mchid);
params.put("pay_orderid", "202401010001");
// 生成签名
params.put("pay_md5sign", createSign(params, apikey));
// 构建请求体
StringBuilder postData = new StringBuilder();
for (Map.Entry entry : params.entrySet()) {
if (postData.length() > 0) postData.append("&");
postData.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
postData.append("=");
postData.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}
// 发送请求
URL url = new URL(gateway);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
try (OutputStream os = conn.getOutputStream()) {
os.write(postData.toString().getBytes("UTF-8"));
}
// 读取响应
try (BufferedReader br = new BufferedReader(
new InputStreamReader(conn.getInputStream(), "UTF-8"))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
response.append(line);
}
System.out.println("响应:" + response);
}
}
public static String createSign(Map params, String apikey)
throws Exception {
StringBuilder sb = new StringBuilder();
for (Map.Entry entry : params.entrySet()) {
String val = entry.getValue();
if (val != null && !val.isEmpty() && !"pay_md5sign".equals(entry.getKey())) {
sb.append(entry.getKey()).append("=").append(val).append("&");
}
}
sb.append("key=").append(apikey);
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(sb.toString().getBytes("UTF-8"));
StringBuilder hexString = new StringBuilder();
for (byte b : digest) {
hexString.append(String.format("%02X", b));
}
return hexString.toString();
}
}
package main
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"net/http"
"net/url"
"sort"
"strings"
)
func main() {
mchid := "10001"
apikey := "您的APIKEY"
gateway := "https://您的域名/pay/trade/query"
// 查询参数
params := url.Values{}
params.Set("pay_memberid", mchid)
params.Set("pay_orderid", "202401010001")
// 生成签名
sign := createSign(params, apikey)
params.Set("pay_md5sign", sign)
// 发送请求
resp, err := http.PostForm(gateway, params)
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println("响应:", string(body))
}
func createSign(params url.Values, apikey string) string {
keys := make([]string, 0)
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
parts := make([]string, 0)
for _, k := range keys {
v := params.Get(k)
if v != "" && k != "pay_md5sign" {
parts = append(parts, k+"="+v)
}
}
signStr := strings.Join(parts, "&") + "&key=" + apikey
hash := md5.Sum([]byte(signStr))
return strings.ToUpper(hex.EncodeToString(hash[:]))
}
const crypto = require('crypto');
const https = require('https');
// 商户配置
const mchid = '10001';
const apikey = '您的APIKEY';
const gateway = '您的域名';
const path = '/pay/trade/query';
// 查询参数
const params = {
pay_memberid: mchid,
pay_orderid: '202401010001',
};
// 生成签名
function createSign(params, apikey) {
const sortedKeys = Object.keys(params).sort();
const parts = [];
sortedKeys.forEach(key => {
if (params[key] && key !== 'pay_md5sign') {
parts.push(`${key}=${params[key]}`);
}
});
const signStr = parts.join('&') + '&key=' + apikey;
return crypto.createHash('md5').update(signStr).digest('hex').toUpperCase();
}
params.pay_md5sign = createSign(params, apikey);
// 发送请求
const postData = new URLSearchParams(params).toString();
const options = {
hostname: gateway,
path: path,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('响应:', data);
});
});
req.on('error', (e) => {
console.error('请求失败:', e);
});
req.write(postData);
req.end();
用户支付成功后,系统会向商户提交的 pay_notifyurl 发送POST请求。
success,否则系统会重复通知(最多5次)。
| 参数名 | 类型 | 说明 |
|---|---|---|
| memberid | String | 商户号 |
| orderid | String | 商户订单号 |
| transaction_id | String | 系统流水号 |
| amount | String | 支付金额 |
| datetime | String | 交易时间(YmdHis) |
| returncode | String | 交易状态(00=成功) |
| attach | String | 附加数据(原样返回) |
| sign | String | MD5签名(32位大写) |
参与签名的参数:memberid, orderid, transaction_id, amount, datetime, returncode, attach
使用商户APIKEY按照 签名规则 生成签名,与通知中的 sign 比对。
$params['memberid'],
'orderid' => $params['orderid'],
'transaction_id' => $params['transaction_id'],
'amount' => $params['amount'],
'datetime' => $params['datetime'],
'returncode' => $params['returncode'],
'attach' => $params['attach'],
];
$sign = createSign($signParams, $apikey);
if ($sign === $params['sign'] && $params['returncode'] === '00') {
// 支付成功,处理业务逻辑
updateOrderStatus($params['orderid'], 'paid', $params['amount']);
// 必须返回 success
echo 'success';
} else {
echo 'fail';
}
?>
from flask import Flask, request
app = Flask(__name__)
@app.route('/pay_notify', methods=['POST'])
def pay_notify():
params = request.form.to_dict()
# 参与签名的参数
sign_params = {
'memberid': params.get('memberid', ''),
'orderid': params.get('orderid', ''),
'transaction_id': params.get('transaction_id', ''),
'amount': params.get('amount', ''),
'datetime': params.get('datetime', ''),
'returncode': params.get('returncode', ''),
'attach': params.get('attach', ''),
}
# 验证签名
check_sign = create_sign(sign_params, apikey)
if check_sign != params.get('sign', ''):
return 'fail'
if params.get('returncode') == '00':
# 支付成功,处理业务逻辑
update_order_status(params['orderid'], 'paid', params['amount'])
# 必须返回 success
return 'success'
else:
return 'fail'
// Spring Boot 控制器示例
@RestController
public class PayNotifyController {
private String apikey = "商户APIKEY";
@PostMapping("/pay_notify")
public String payNotify(@RequestBody Map params) {
// 参与签名的参数
Map signParams = new TreeMap<>();
signParams.put("memberid", params.get("memberid"));
signParams.put("orderid", params.get("orderid"));
signParams.put("transaction_id", params.get("transaction_id"));
signParams.put("amount", params.get("amount"));
signParams.put("datetime", params.get("datetime"));
signParams.put("returncode", params.get("returncode"));
signParams.put("attach", params.get("attach"));
// 验证签名
String checkSign = createSign(signParams, apikey);
if (!checkSign.equals(params.get("sign"))) {
return "fail";
}
if ("00".equals(params.get("returncode"))) {
// 支付成功,处理业务逻辑
updateOrderStatus(params.get("orderid"), "paid",
params.get("amount"));
// 必须返回 success
return "success";
} else {
return "fail";
}
}
}
package main
import (
"net/http"
"net/url"
)
func payNotify(w http.ResponseWriter, r *http.Request) {
// 解析表单
r.ParseForm()
params := make(map[string]string)
for k := range r.PostForm {
params[k] = r.PostForm.Get(k)
}
// 参与签名的参数
signParams := map[string]string{
"memberid": params["memberid"],
"orderid": params["orderid"],
"transaction_id": params["transaction_id"],
"amount": params["amount"],
"datetime": params["datetime"],
"returncode": params["returncode"],
"attach": params["attach"],
}
// 验证签名
checkSign := createSign(signParams, apikey)
if checkSign != params["sign"] {
w.Write([]byte("fail"))
return
}
if params["returncode"] == "00" {
// 支付成功,处理业务逻辑
updateOrderStatus(params["orderid"], "paid", params["amount"])
// 必须返回 success
w.Write([]byte("success"))
} else {
w.Write([]byte("fail"))
}
}
const express = require('express');
const app = express();
const crypto = require('crypto');
const apikey = '商户APIKEY';
app.post('/pay_notify', (req, res) => {
const params = req.body;
// 参与签名的参数
const signParams = {
memberid: params.memberid,
orderid: params.orderid,
transaction_id: params.transaction_id,
amount: params.amount,
datetime: params.datetime,
returncode: params.returncode,
attach: params.attach,
};
// 验证签名
const checkSign = createSign(signParams, apikey);
if (checkSign !== params.sign) {
return res.send('fail');
}
if (params.returncode === '00') {
// 支付成功,处理业务逻辑
updateOrderStatus(params.orderid, 'paid', params.amount);
// 必须返回 success
res.send('success');
} else {
res.send('fail');
}
});
支付完成后,系统通过页面跳转方式将支付结果发送到商户的 pay_callbackurl。
同步回调参数与异步通知相同,但同步回调不需要返回 success。
| 错误码/状态 | 说明 |
|---|---|
| 200 | 成功 |
| error | 请求失败 |
| 不存在的商户编号! | pay_memberid 参数错误或商户不存在 |
| 金额不能为空 | pay_amount 参数为空或为0 |
| 不存在的银行编码! | pay_bankcode 参数错误 |
| 订单号不合法! | pay_orderid 参数为空 |
| 签名验证失败 | 签名错误,请检查APIKEY和签名算法 |
| 商户已被冻结 | 商户账号已被禁用 |
| 未开通该支付通道 | 商户未开通该支付方式 |
| 订单已支付,请勿重复提交 | 订单号已存在且已支付 |
| 订单号已存在,请更换订单号 | 订单号重复 |
| 商户今日交易额已达上限 | 触发用户风控 |
| 通道今日交易额已达上限 | 触发通道风控 |
$mchid,
'pay_orderid' => date('YmdHis') . rand(1000, 9999),
'pay_amount' => '100.00',
'pay_applydate' => date('Y-m-d H:i:s'),
'pay_bankcode' => '903', // 支付通道编号
'pay_notifyurl' => 'https://您的域名/notify.php',
'pay_callbackurl' => 'https://您的域名/callback.php',
'pay_productname' => '测试商品',
];
// 生成签名
$params['pay_md5sign'] = createSign($params, $apikey);
// 发送请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $gateway);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);
// 解析响应
$result = json_decode($response, true);
if ($result['status'] == '200') {
// 跳转到支付页面
header('Location: ' . $result['data']['url']);
} else {
echo '下单失败:' . $result['msg'];
}
/**
* 生成MD5签名
*/
function createSign($params, $apikey) {
ksort($params);
$md5str = "";
foreach ($params as $key => $val) {
if (!empty($val) && $key != 'pay_md5sign') {
$md5str .= $key . "=" . $val . "&";
}
}
return strtoupper(md5($md5str . "key=" . $apikey));
}
?>
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
支付下单示例 - Python
"""
import hashlib
import time
import random
import requests
# 商户配置
MCHID = '10001' # 商户号
APIKEY = '您的APIKEY' # 商户APIKEY
GATEWAY = 'https://您的域名/pay/index/index'
# 生成MD5签名
def create_sign(params, apikey):
sorted_params = sorted(params.items())
sign_str = '&'.join([f'{k}={v}' for k, v in sorted_params
if v and k != 'pay_md5sign'])
sign_str += '&key=' + apikey
return hashlib.md5(sign_str.encode()).hexdigest().upper()
# 主程序
def main():
# 订单参数
params = {
'pay_memberid': MCHID,
'pay_orderid': time.strftime('%Y%m%d%H%M%S') + str(random.randint(1000, 9999)),
'pay_amount': '100.00',
'pay_applydate': time.strftime('%Y-%m-%d %H:%M:%S'),
'pay_bankcode': '903', # 支付通道编号
'pay_notifyurl': 'https://您的域名/notify.py',
'pay_callbackurl': 'https://您的域名/callback.py',
'pay_productname': '测试商品',
}
# 生成签名
params['pay_md5sign'] = create_sign(params, APIKEY)
# 发送请求
response = requests.post(GATEWAY, data=params)
result = response.json()
if result.get('status') == '200':
print('支付链接:', result['data']['url'])
# 可选择跳转到支付页面
# webbrowser.open(result['data']['url'])
else:
print('下单失败:', result.get('msg'))
if __name__ == '__main__':
main()
import java.io.*;
import java.net.*;
import java.security.MessageDigest;
import java.util.*;
/**
* 支付下单示例 - Java
*/
public class PayDemo {
private static final String MCHID = "10001"; // 商户号
private static final String APIKEY = "您的APIKEY"; // 商户APIKEY
private static final String GATEWAY = "https://您的域名/pay/index/index";
public static void main(String[] args) throws Exception {
// 订单参数
Map params = new HashMap<>();
params.put("pay_memberid", MCHID);
params.put("pay_orderid", new Timestamp(System.currentTimeMillis())
.toString().replaceAll("[^0-9]", "") +
String.format("%04d", new Random().nextInt(10000)));
params.put("pay_amount", "100.00");
params.put("pay_applydate", new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.format(new java.util.Date()));
params.put("pay_bankcode", "903"); // 支付通道编号
params.put("pay_notifyurl", "https://您的域名/notify");
params.put("pay_callbackurl", "https://您的域名/callback");
params.put("pay_productname", "测试商品");
// 生成签名
params.put("pay_md5sign", createSign(params, APIKEY));
// 构建请求体
StringBuilder postData = new StringBuilder();
for (Map.Entry entry : params.entrySet()) {
if (postData.length() > 0) postData.append("&");
postData.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
postData.append("=");
postData.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}
// 发送请求
URL url = new URL(GATEWAY);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
try (OutputStream os = conn.getOutputStream()) {
os.write(postData.toString().getBytes("UTF-8"));
}
// 解析响应
try (BufferedReader br = new BufferedReader(
new InputStreamReader(conn.getInputStream(), "UTF-8"))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
response.append(line);
}
System.out.println("响应:" + response);
}
}
/**
* 生成MD5签名
*/
public static String createSign(Map params, String apikey)
throws Exception {
Map sortedParams = new TreeMap<>(params);
StringBuilder sb = new StringBuilder();
for (Map.Entry entry : sortedParams.entrySet()) {
String key = entry.getKey();
String val = entry.getValue();
if (val != null && !val.isEmpty() && !key.equals("pay_md5sign")) {
sb.append(key).append("=").append(val).append("&");
}
}
sb.append("key=").append(apikey);
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(sb.toString().getBytes("UTF-8"));
StringBuilder hexString = new StringBuilder();
for (byte b : digest) {
hexString.append(String.format("%02X", b));
}
return hexString.toString();
}
}
package main
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"math/rand"
"net/http"
"net/url"
"sort"
"strings"
"time"
)
const (
MCHID = "10001" // 商户号
APIKEY = "您的APIKEY" // 商户APIKEY
GATEWAY = "https://您的域名/pay/index/index"
)
func main() {
// 订单参数
orderID := time.Now().Format("20060102150405") +
fmt.Sprintf("%04d", rand.Intn(10000))
applyDate := time.Now().Format("2006-01-02 15:04:05")
params := url.Values{}
params.Set("pay_memberid", MCHID)
params.Set("pay_orderid", orderID)
params.Set("pay_amount", "100.00")
params.Set("pay_applydate", applyDate)
params.Set("pay_bankcode", "903") // 支付通道编号
params.Set("pay_notifyurl", "https://您的域名/notify")
params.Set("pay_callbackurl", "https://您的域名/callback")
params.Set("pay_productname", "测试商品")
// 生成签名
params.Set("pay_md5sign", createSign(params, APIKEY))
// 发送请求
resp, err := http.PostForm(GATEWAY, params)
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println("响应:", string(body))
}
// createSign 生成MD5签名
func createSign(params url.Values, apikey string) string {
keys := make([]string, 0)
for k := range params {
if k != "pay_md5sign" {
keys = append(keys, k)
}
}
sort.Strings(keys)
parts := make([]string, 0)
for _, k := range keys {
v := params.Get(k)
if v != "" {
parts = append(parts, k+"="+v)
}
}
signStr := strings.Join(parts, "&") + "&key=" + apikey
hash := md5.Sum([]byte(signStr))
return strings.ToUpper(hex.EncodeToString(hash[:]))
}
const crypto = require('crypto');
const https = require('https');
// 商户配置
const MCHID = '10001'; // 商户号
const APIKEY = '您的APIKEY'; // 商户APIKEY
const GATEWAY = '您的域名';
const PATH = '/pay/index/index';
// 生成MD5签名
function createSign(params, apikey) {
const sortedKeys = Object.keys(params)
.filter(k => k !== 'pay_md5sign' && params[k])
.sort();
const parts = sortedKeys.map(k => `${k}=${params[k]}`);
const signStr = parts.join('&') + '&key=' + apikey;
return crypto.createHash('md5')
.update(signStr)
.digest('hex')
.toUpperCase();
}
// 主程序
function main() {
const orderId = new Date().toISOString().replace(/[-T:.Z]/g, '') +
Math.floor(Math.random() * 10000).toString().padStart(4, '0');
const applyDate = new Date().toISOString()
.replace('T', ' ').substring(0, 19);
// 订单参数
const params = {
pay_memberid: MCHID,
pay_orderid: orderId,
pay_amount: '100.00',
pay_applydate: applyDate,
pay_bankcode: '903', // 支付通道编号
pay_notifyurl: 'https://您的域名/notify',
pay_callbackurl: 'https://您的域名/callback',
pay_productname: '测试商品',
};
// 生成签名
params.pay_md5sign = createSign(params, APIKEY);
// 发送请求
const postData = new URLSearchParams(params).toString();
const options = {
hostname: GATEWAY,
path: PATH,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const result = JSON.parse(data);
if (result.status === '200') {
console.log('支付链接:', result.data.url);
} else {
console.log('下单失败:', result.msg);
}
} catch (e) {
console.log('响应:', data);
}
});
});
req.on('error', (e) => {
console.error('请求失败:', e);
});
req.write(postData);
req.end();
}
main();
支付API文档 v2.0 | 支持 PHP / Python / Java / Go / Node.js