支付API文档

1. 概述

支付网关API为商户提供在线支付能力。商户通过HTTP POST方式提交支付请求,系统返回支付链接或二维码,用户完成支付后系统通过异步通知和同步跳转两种方式通知商户支付结果。

接口基础地址: https://您的域名/pay
请求方式: POST(除特别说明外)
数据格式: application/x-www-form-urlencoded
签名算法: MD5(大写)

2. 签名规则

所有需要签名的接口使用相同的签名算法,步骤如下:

签名步骤:
1. 将所有非空参数按照参数名ASCII码从小到大排序(字典序)
2. 使用URL键值对格式拼接,如:key1=value1&key2=value2&...
3. 在拼接字符串末尾连接商户APIKEY:...&key=商户APIKEY
4. 对整个字符串进行MD5加密,得到32位大写签名值
注意:

各语言签名示例

PHP
Python
Java
Go
Node.js
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();
}

3. 支付接口(下单)

POST /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": []
}

4. 订单查询接口

POST /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=未支付
    }
}

各语言查询示例

PHP
Python
Java
Go
Node.js
// 订单查询示例
$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();

5. 异步通知

用户支付成功后,系统会向商户提交的 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 比对。

各语言通知处理示例

PHP
Python
Java
Go
Node.js
 $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');
    }
});

6. 同步回调

支付完成后,系统通过页面跳转方式将支付结果发送到商户的 pay_callbackurl。

同步回调参数与异步通知相同,但同步回调不需要返回 success。

注意:同步回调可能被用户关闭浏览器导致无法收到,请以异步通知为准。

7. 错误码

错误码/状态 说明
200成功
error请求失败
不存在的商户编号!pay_memberid 参数错误或商户不存在
金额不能为空pay_amount 参数为空或为0
不存在的银行编码!pay_bankcode 参数错误
订单号不合法!pay_orderid 参数为空
签名验证失败签名错误,请检查APIKEY和签名算法
商户已被冻结商户账号已被禁用
未开通该支付通道商户未开通该支付方式
订单已支付,请勿重复提交订单号已存在且已支付
订单号已存在,请更换订单号订单号重复
商户今日交易额已达上限触发用户风控
通道今日交易额已达上限触发通道风控

8. 完整代码示例

各语言下单示例

PHP
Python
Java
Go
Node.js
 $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

查看代付API文档 →