法币(泰铢) 代付下单

# 代码示例

  • 代码示例仅供参考,具体参数说明请参考请求参数说明

TopPayRequestUtil点击获取代码示例

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.util.Map;
import java.util.TreeMap;
public class TopCashDemo {

  //MCH_ID: 商户ID
  //请登录商户后台,点击 个人中心 > 个人信息 在基本信息中获取商户ID
  private static final String MCH_ID = "S820211021094748000001";
  private static final String PLAT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2JoMfFqLsSJjAiCahEnlP3aRj8yCT+WHzR+VvPBTw9S1i7iYWb+MY09CG/HYuHF4+IxshXDJygmndxKf/esuwPybS8mAd//yubHpmZsmBqg1FffT8VH1APa6ZRWASUp4U01ZrbCCp35QA8FuWrJGMJxGx4xk7KUtV2yujxC8noQIDAQAB";  // 平台公钥
  private static final String MCH_PRIVATE_KEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAJU8gKFKD0luIYx7X8+JRdCIE0UDBctS6LjXxWLEv/EO7jDBTid6zYP1KmNgpd2DAWWtBFBSQ+gcNwVZZSBHJiSDqVvvJVs2FEbeBvfdv4X93+IYRAXksBasSW5Tpdshbo82pVL4V7wuKCuFLk9UxBHbpQjWAbfyF66RmwIbZD71AgMBAAECgYBjPe7UU2nDDSfmQg0++CyjNjqKRC5QPfxhH6w1uF1kMueXKJWOj42n2RutJpJmsj31nY8m0u4xpsG4HvCu/GGSFhhKZCHLvzp41oY2ubYj9nuFNU//81LycQjulWo2y0UUBY0k2piEt+SwPaiUNbT6nMxNMjlnjRe2okp/3rw+KQJBANG3YlZWoVbCEqzy64bJJLxiPsCA5ErGB0NzRGitq44xkhqGtR8ZZQyVz40pruNa58d73O2xyJSy5+fmZGn4E+sCQQC2LBnguj0CSCKub0mPDcunTTz9V79VXBBZdlB1/YGmRUx2s4sQrJNZS7rL4EqBQ3maIRnG+s+AXCSTfsYrV6CfAkEAxugnVfpelhoGepEAgNuggyivmgfl/2Gpm/jk5l/qOjib+ZrQiQmeBPzGWX4yiSM8eMDrP2sC8r5pJFMp5DRONwJBAJ4n4XuSFJ9jgwCPy3vvzSv9SYLk6E6yM9uHdUlKgoGYzk6Lh6M9QFuY/J49plFdBDiEnj16yCU3WeXXfTJpzB8CQQDMNMR/rIOTE9xGybS3mlQbt22AUnO6XhupWcckEKW4nPGxATwYBQzCY3i/9FTGN0vA+9ZPC2cwHtNxI2kXf3Vp";  // 商户私钥
  private static final String cashUrl = "https://tl-openapi.toppay.asia/gateway/cash";
  private static final String cashNotify = "http://host:port/notify";

  public static void main(String[] args) throws Exception {
    cash();
  }
  private static void cash() throws Exception {
    Map<String, String> requestParams = new TreeMap<>();
    requestParams.put("merchantCode", MCH_ID);
    requestParams.put("orderNum", "186888188666"); // 商户订单号
    requestParams.put("method", "Disbursement"); // 收款方式(默认传Disbursement)
    requestParams.put("orderType", "0"); // 订单类型(0-法币(泰铢)交易)
    requestParams.put("money", "125.12"); // 订单金额,支持两位小数位
    requestParams.put("feeType", "0");  //  手续费类型(0-帐内扣除,1-帐外扣除)
    requestParams.put("dateTime", "20200101235959");// 时间戳 格式 yyyyMMddHHmmss
    requestParams.put("number", "2021071209403321313122");     // 客户银行卡号
    requestParams.put("bankCode", "001");       // 银行编码:参考附录I 代付
    //name原文参与签名,但是在调用API时需要进行Unicode编码
    requestParams.put("name", "จางซาน");  // 客户名称
    requestParams.put("mobile", "082122965511"); // 客户手机号,可不传
    requestParams.put("email", "[email protected]"); // 客户邮箱,可不传
    //description原文参与签名,但是在调用API时需要进行Unicode编码
    requestParams.put("description", "คำอธิบาย");    // 描述
    requestParams.put("notifyUrl", cashNotify);  // 回调地址
    List<String> paramNameList = new ArrayList<>();
    for (String key : maps.keySet()) {
        paramNameList.add(key);
    }
    Collections.sort(paramNameList);
    StringBuilder stringBuilder = new StringBuilder();
    for (String key : paramNameList) {
        stringBuilder.append(requestParams.get(key));  // 拼接参数
    }
    String keyStr = stringBuilder.toString();  // 得到待加密的字符串
    System.out.println("keyStr:" + keyStr);
    String signedStr = TopPayRequestUtil.privateEncrypt(keyStr, TopPayRequestUtil.getPrivateKey(MCH_PRIVATE_KEY));  // 私钥加密
    requestParams.put("sign", signedStr);


    //签名完成后,对name和description进行编码 UnicodeUtil示例代码参考 本节第9项 泰文Unicode
    requestParams.put("name", UnicodeUtil.toUnicode("จางซาน", true));  // 客户名称
    requestParams.put("description", UnicodeUtil.toUnicode("คำอธิบาย", true));    // 描述

    String postJson = new Gson().toJson(requestParams);
    System.out.println("Post Json Params:" + postJson);

    String responseJson = TopPayRequestUtil.doPost(cashUrl, postJson);  // 发送 post json请求
    System.out.println("Response Msg:" + responseJson);

    boolean pass = TopPayRequestUtil.verifySign(new Gson().fromJson(responseJson, JsonObject.class), PLAT_PUBLIC_KEY);  // 签名验证
    if (pass) {
      // ... 签名验证通过,执行正常的业务逻辑
    } else {
      // ... 签名验证错误
    }
  }
}

<?php
    // 平台公钥,从密钥配置中获取
    // platform public key, from Secret key config
    $platPublicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiaKBgQCcEUIvQ/5L+SWbHOeR8VFeZvLbUk7V7OeEAQlQwIVLSZMTef3KtsOKKAsUYPf/aAcKRzZZXECODsPQiDPcdZvM/rFkgrFWkR7lPjTj5SiPxGaiK2Z2sne7A8aDF7fV/D7lfmEwNdZ7FWKVEB84/81BHnlGUwb5HpRTISG+boSO6wIDAQAB';
    // 商户私钥,商户自己生成
    // private key
    $mchPrivateKey = 'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMigm7rtWnTeNagwFzGTH+Uw1ypbiy7VhIoFJbgSYSSHdCaXWdT/l2+2fQlEYgAETVZ/IXB29MCnrf3O0dwRFXiipIbsm5zyqSLiS6cKXe8zN1/PlQWUbEt5wyWm0GADB/4bV6eu6gA7sGXmjQqrzfKZkcie3aK7+7ry1NFxTI51AgMBAAECgYEAklqXQAVlt1tiSQ7L3J425jp6u6uMHN4lkYmvuleuBbfKQ1yla3wIPLYjAF+iHeEFidOz0Rb19JRdmIkHDkJoJg2W27LvO6RdUwzgRnsuA3OuNz97w08B3aXXbPmB91nTFjKSlUsbh3IQWP71noxW+iKn844EW5hC5Gvn4L3quAECQQDrz1r0VKIbBSBB2aLuz1XyD/TBT2aRhvOKf0XtTRiQhNjtJxoQmvNbbhvUwj8an7HyCuihAbdbrC2ymFFyOSDZAkEA2c4Yudi48C6COrroi1cWgPlEFeGJXP/V1k5loZ1n2vstYAGPhAB4wUnFBLDvMqaBzWJt7MRkiazT8KnBQCDY/QJAMXpNlEyZwt+deBOpO0BnwSWV7mWxmMFfImU4D+WITPbC7aexsWBBxaJh1o93XCe715RwYTAR//stj3akSDoyaQJAa4FKuxC51/Nc3Fg9R+modeiTLqmv/3NXvPvdNjRXesLX1rduex0wfVdII9ShfEKrdxDKaT9W0NyzD+r6NAkCkQJBAMAnTgPYf0f7rh417GdoP7R7Nwi8KBKwPHlmfRukibOQlKt9xjqpsKJwglLn8pcnXbYbswXIdqzuBvIGAe3OWNg=';
    //merchantCode: 商户ID
    //请登录商户后台,点击 个人中心 > 个人信息 在基本信息中获取商户ID
    $merchantCode = 'YOUR_MERCHANT_CODE_HERE';
    // 商户订单号
    // Merchant system unique order number
    $orderNum = 'T'.date("YmdHis",time());
    // 支付方式 
    // Method 
    $method = 'Disbursement';
    //订单类型(0-法币(泰铢)交易)
    $orderType = '0';
    // 出款金额 withdraw money
    $money = '20000';
    // 手续费类型(0-帐内扣除,1-帐外扣除)
    $feeType = '1';
    // 时间戳 格式 yyyyMMddHHmmss
    $dateTime = date("YmdHis",time());
    // 客户银行卡号
    $number = '123456';
    // 银行编码(详情参考文档底部)
    $bankCode = '001';
    // 在付款确认页面显示的转账对象
    // Display name on bank confirmation display
    $name = 'จางซาน';
    // 手机号码
    // Customer's mobile number
    $mobile = '082112345678';
    // 邮箱
    // Customer's email address
    $email = '[email protected]';
    // 描述
    // The virtual account description
    $description = 'คำอธิบาย';
    // 回调地址
    // url for callback
    $notifyUrl = 'http://example.com/callback';
    $params = array(
        'merchantCode' => $merchantCode,
        'orderType' => $orderType,
        'method' => $method,
        'orderNum' => $orderNum,
        'money' => $money,
        'feeType' => $feeType,
        'dateTime' => $dateTime,
        'number' => $number,
        'bankCode' => $bankCode,
        'name' => $name,
        'mobile' => $mobile,
        'email' => $email,
        'notifyUrl' => $notifyUrl,
        'description' => $description
    );

    ksort($params);
    $params_str = '';
    foreach ($params as $key => $val) {
        $params_str = $params_str . $val;
    }


    $sign = pivate_key_encrypt($params_str, $mchPrivateKey);

    $params['sign'] = $sign;

    //原文参与签名后 需要使用unicode编码 编码方式参考 本节第9项 泰文Unicode
    $params['name'] = unicode_encode($name);
    $params['description'] = unicode_encode($description);

    $params_string = json_encode($params);
    $url = 'https://tl-openapi.toppay.asia/gateway/cash';
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
    curl_setopt($ch, CURLOPT_POSTFIELDS, $params_string);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Type: application/json',
        'Content-Length: ' . strlen($params_string))
    );
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

    //execute post
    $request = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    if($httpCode == 200)
    {
        $result = json_decode($request, true);
        echo "platRespCode :". $result['platRespCode'] . "\n";
        echo "platRespMessage :". $result['platRespMessage'] . "\n";
        echo "platOrderNum :". $result['platOrderNum'] . "\n";
        echo "orderNum :". $result['orderNum'] . "\n";
        echo "status :". $result['status'] . "\n";
        echo "statusMsg :". $result['statusMsg'] . "\n";
        echo "money :". $result['money'] . "\n";
        echo "fee :". $result['fee'] . "\n";
        echo "feeType :". $result['feeType'] . "\n";
        echo "bankCode :". $result['bankCode'] . "\n";
        echo "number :". $result['number'] . "\n";
        echo "name :". $result['name'] . "\n";
        echo "description :". $result['description'] . "\n";
        echo "platSign :". $result['platSign'] . "\n";

        $decryptStr = public_key_decrypt($result['platSign'], $platPublicKey);
        echo "decryptStr :". $decryptStr . "\n";
    }
    else {
        echo $httpCode;
    }

    function pivate_key_encrypt($data, $pivate_key)
    {
        $pivate_key = '-----BEGIN PRIVATE KEY-----'."\n".$pivate_key."\n".'-----END PRIVATE KEY-----';
        $pi_key = openssl_pkey_get_private($pivate_key);
        $crypto = '';
        foreach (str_split($data, 117) as $chunk) {
            openssl_private_encrypt($chunk, $encryptData, $pi_key);
            $crypto .= $encryptData;
        }

        return base64_encode($crypto);
    }

    function public_key_decrypt($data, $public_key)
    {
        $public_key = '-----BEGIN PUBLIC KEY-----'."\n".$public_key."\n".'-----END PUBLIC KEY-----';
        $data = base64_decode($data);
        $pu_key =  openssl_pkey_get_public($public_key);
        $crypto = '';
        foreach (str_split($data, 128) as $chunk) {
            openssl_public_decrypt($chunk, $decryptData, $pu_key);
            $crypto .= $decryptData;
        }

        return $crypto;
    }
using demo.utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace demo.demos
{
    class CreateTransferDemo
    {
        //MCH_ID: 商户ID
        //请登录商户后台,点击 个人中心 > 个人信息 在基本信息中获取商户ID
        private static readonly string MCH_ID = "S820191106095842000004";
        private static readonly string PLAT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcEUIvQ/5L+SWbHOeR8VFeZvLbUk7V7OeEAQlQwIVLSZMTef3KtIOKKAsUYPf/aAcKRzZZXECODsPQiDPcdZvM/rFkgrFWkR7lPjTj5SiPxGaiK2Z2sne7A8aDF7fV/D7lfmEwNdZ7FWKVEB84/81BHnlGUwb5HpRTISG+boSO6wIDAQAB";  // 平台公钥
        private static readonly string MCH_PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMigm7rtWnTeNagwFzGTH+Uw1ypbiy7VhIoFJbgSYSSHdCaXWdT/l2+2fQlEYgAETVZ/IXB29MCnrf3O0dwRFXiipIbsm5zyqSLiS6cKXe8zN1/PlQWUbEt5wyWm0GADB/4bV6eu6gA7sGXmjQqrzfKZkcie3aK7+7ry1NFxTI51AgMBAAECgYEAklqXQAVlt1tiSQ7L3J425jp6u6uMHN4lkYmvuleuBbfKQ1yla3wIPLYjAF+iHeEFidOz0Rb19JRdmIkHDkJoJg2W27LvO6RdUwzgRnsuA3OuNz97w08B3aXXbPmB91nTFjKSlUsbh3IQWP71noxW+iKn844EW5hC5Gvn4L3quAECQQDrz1r0VKIbBSBB2aLuz1XyD/TBT2aRhvOKf0XtTRiQhNjtJxoQmvNbbhvUwj8an7HyCuihAbdbrC2ymFFyOSDZAkEA2c4Yudi48C6COrroi1cWgPlEFeGJXP/V1k5loZ1n2vstYAGPhAB4wUnFBLDvMqaBzWJt7MRkikzT8KnBQCDY/QJAMXpNlEyZwt+deBOpO0BnwSWV7mWxmMFfImU4D+WITPKC7aexsWBBxaJh1o93XCe715RwYTAR//stj3akSDoyaQJAa4FKuxC51/Nc3Fg9R+modeiTLqmv/3NXvPvdNjRXesLX1rduex0wfVdII9ShfEKrdxDKaT9W0NyzD+r6NAkCkQJBAMAnTgPYf0f7rh417GdoP7R7Nwi8KBKwPHlmfRukibOQlKt9xjqpsKJwglLn8pcnXbYbswXIdqzuBvIGAe3OWNg=";  // 商户私钥
        private static readonly string cashUrl = "https://tl-openapi.toppay.asia/gateway/cash";
        public static void requestTransfer()
        {
            long currenttimemillis = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
            string merchantCode = MCH_ID;                                             // 商户号
            string orderNum = "CASH" + currenttimemillis.ToString();                    // 商户订单号
            string money = "20000";                                                     // 订单金额
            string feeType = "1";                                                      		 // 手续费收取方式 0:从提现金额中扣除 1:手续费另计
            string dateTime = "20191107105500";                                         // 时间戳 格式 yyyyMMddHHmmss
            string name = "CHANDRA DERMAWAN";                                           // 收款账号名称
            string number = "3500035098";                                               // 收款账号,注意收款姓名与收款卡号需要对应一致,不然可能会导致转账失败,建议对接账号信息校验接口获取账号名称,具体可参照 CheckBankAccountDemo.java
            string bankCode = "001";                                                    // 银行编号,参数列表见附录
            string description = "TestCash";                                            // 订单描述
            string notifyUrl = "https://www.baidu.com";                                 // 回调地址
            Dictionary<string, object> VarPost = new Dictionary<string, object>();
            VarPost.Add("merchantCode", merchantCode);//用a标识的参数,并用POST传值方式传给网页 ­
            VarPost.Add("orderNum", orderNum);
            VarPost.Add("money", money);
            VarPost.Add("feeType", feeType);
            VarPost.Add("dateTime", dateTime);
            VarPost.Add("name", name);
            VarPost.Add("number", number);
            VarPost.Add("bankCode", bankCode);
            VarPost.Add("description", description);
            VarPost.Add("notifyUrl", notifyUrl);
            List<string> paramNameList = new List<string>();
            foreach (string key in VarPost.Keys)
            {
                paramNameList.Add(key);
            }
            paramNameList.Sort();// 排序key
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < paramNameList.Count; i++)
            {
                string key = paramNameList[i];
                stringBuilder.Append(VarPost[key]);  // 拼接参数
            }
            String keyStr = stringBuilder.ToString();  // 得到待加密的字符串
            string signedStr = "";
            try
            {
                RSAForJava rsa = new RSAForJava();
                signedStr = rsa.EncryptByPrivateKey(keyStr, MCH_PRIVATE_KEY);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            VarPost.Add("sign", signedStr);

            WebClient w = new WebClient();
            w.Headers[HttpRequestHeader.ContentType] = "application/json";
            string jsonStr = JsonNewtonsoft.SerializeDictionaryToJsonString(VarPost);
            Console.WriteLine("postJson:" + jsonStr);     //发送字符串
            string sRemoteInfo = w.UploadString(cashUrl, "POST", jsonStr);
            Console.WriteLine("return:" + sRemoteInfo);     //接收字符串
            Dictionary<string, object> dict = JsonNewtonsoft.DeserializeJsonToDict(sRemoteInfo);
            bool pass = false;
            try
            {
                RSAForJava rsa = new RSAForJava();
                pass = rsa.verifySign(dict, PLAT_PUBLIC_KEY);  // 签名验证
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.WriteLine("verifysign:"+ pass);
        }
    }
}

package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"reflect"
	"sort"
	"strings"
)

// 创建json请求结构
type RequestBody struct {
	MerchantCode string `json:"merchantCode"`
	OrderType    string `json:"orderType"`
	OrderNum     string `json:"orderNum"`
	Method       string `json:"Method"`
	Money        string `json:"money"`
	FeeType      string `json:"feeType"`
	DateTime     string `json:"dateTime"`
	Number       string `json:"number"`
	BankCode     string `json:"bankCode"`
	Name         string `json:"name"`
	Mobile       string `json:"mobile"`
	Email        string `json:"email"`
	Description  string `json:"description"`
	NotifyUrl    string `json:"notifyUrl"`
	Sign         string `json:"sign"`
}

func main() {
	//公私钥(仅用于测试)
	cryptor := NewCryptor()
	cryptor.Pub64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvGQXHktEoCrQ/EnMceY4QVc15KHyvW1ePyYmSqZJC99u4gcdbzYYuunw7kqsdIKWSjPV6q/4cc8665ZOFuUH8W8iFMdOmuGO0QRUIvif09hhyWyaM7IpPMlU2+oydAWWjgc8JFmDZt1dWbMuaOS9Rw959wUOoQpbQK4yD37Bj0wIDAQAB"
	cryptor.Pri64 = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAK8ZBceS0SgKtD8Scxx5jhBVzXkofK9bV4/JiZKpkkL327iBx1vNhi66fDuSqx0gpZKM9Xqr/hxzzrrlk4W5QfxbyIUx06a4Y7RBFQi+J/T2GHJbJozsik8yVTb6jJ0BZaOBzwkWYNm3V1Zsy5o5L1HD3n3BQ6hCltArjIPfsGPTAgMBAAECgYBtrMS7/zBXXm0MXKgRm+nqPXRYgY2n4RT1kY1EekaM/+d2qIOQ8ykrN8/9GJ9pvTs4kmZokja256sD0i0XQ7UaLXYp31jTU4HlNpB8ixiCQG0gvldZRlLlGEeCeNrCQXT88dqC9mmvR7FIvS1sUnDonMZXEtJC8HOL4L80P52P0QJBAN3aovKYaCtmbtmYc76U+CqxyijRCxqV1Cb6u+YFY423FrFG2hXhdVu8UmgV+VvgT5lh0VQyKzVqRIdwk1hwzW8CQQDKDB8alSSBgcaEhlQkuTUjz4TwnYa5UhDuwzIs9FC2QLbBMa5alUiJDVlqVc33WzAHmGBJPRtMnnsGlgPeQiXdAkEAw9GVfjeTyqrxMNLlZtSqb1TaMUjCWkbhKT6q1w7unkl6mCMHn8SPB9ejjQfIP5Yv7Bxw3bYieVVBA6MUCz4VtQJAKju8aK8SMWvyFhOKFR8Np42iKTWUSrqHxZDRtSngkSgXy2xaGJ8pyVQcA6kp43GRKZVFUynNwgdCig7jghrrlQJBANfIE+D+PcFLSC8pRmX0sPhTLbuSFORgRzvpovW/FGXonNRp/yPWgIdXzpJKb40IFbbPEPjZtHKRJwSWWBDEfuk="
	
	url := "https://tl-openapi.toppay.asia/gateway/cash"
	//具体下单参数内容
	request := RequestBody{
		//MerchantCode: 商户ID
        //请登录商户后台,点击 个人中心 > 个人信息 在基本信息中获取商户ID
		MerchantCode: "S820230414142102000012",
		// 订单类型(0-法币(泰铢)交易)
		OrderType: "0",
		// 商户订单号
		OrderNum: "H202404161637",
		// 收款方式(默认传Disbursement)
		Method: "Disbursement",
		// 订单金额,支持两位小数位
		Money: "100",
		//  手续费类型(0-帐内扣除,1-帐外扣除)
		FeeType: "0",
		// 时间 格式 yyyyMMddHHmmss
		DateTime: "20220101235959",
		// 客户银行卡号
		Number: "1548425413",
		// 银行编码:参考附录I 代付
		BankCode: "001",
		// 客户名称
		Name: "จางซาน",
		// 客户手机号,可不传
		Mobile: "082122965511",
		// 客户邮箱,可不传
		Email: "[email protected]",
		// 描述
		Description: "代付下单",
		// 回调地址
		NotifyUrl: "openapi",
	}
	// 将结构体的字段按JSON标签排序并拼接其值
	sortedValues, err := sortedConcatenatedValues(request)
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		return
	}
	//将排序拼接后的值,使用私钥进行加密,并进行base64编码
	encryptedData := cryptor.PriEncrypt([]byte(sortedValues))
	encodedString := base64.StdEncoding.EncodeToString(encryptedData)
	//将获得签名放入请求结构中
	request.Sign = encodedString
	jsonBytes, err := json.Marshal(request)
	if err != nil {
		fmt.Printf("Error: %s", err.Error())
		return
	}
	fmt.Println("json2", bytes.NewBuffer(jsonBytes))
	//进行http请求
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBytes))
	if err != nil {
		fmt.Println("Error creating HTTP request:", err)
		return
	}
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Error sending HTTP request:", err)
		return
	}
	defer resp.Body.Close()
	// 读取并打印响应体
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Error reading response body:", err)
		return
	}
	fmt.Println("Response Body:", string(respBody))
}

// 使用结构体的 JSON 标签按照ASCII进行排序并拼接对应值为一个字符串
func sortedConcatenatedValues(v interface{}) (string, error) {
	valueOf := reflect.ValueOf(v)
	typeOf := valueOf.Type()
	kv := make(map[string]string)
	for i := 0; i < valueOf.NumField(); i++ {
		field := typeOf.Field(i)
		jsonTag := field.Tag.Get("json")
		if jsonTag == "" || jsonTag == "-" {
			continue
		}
		tagName := strings.Split(jsonTag, ",")[0] // 忽略omitempty选项
		kv[tagName] = fmt.Sprint(valueOf.Field(i).Interface())
	}
	keys := make([]string, 0, len(kv))
	for k := range kv {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	var concatenatedValues strings.Builder
	for _, key := range keys {
		concatenatedValues.WriteString(kv[key])
	}
	return concatenatedValues.String(), nil
}

import json
import requests
import base64
import easyocr
from M2Crypto import RSA
from collections import OrderedDict

class TopCashDemo:
    # 商户私钥存储地址
    MCH_PRI_KEY_FILE = 'D:\data\company_rsa_private_key.pem'
    # 平台公钥保存地址
    MCH_PUBLIC_KEY_FILE = 'D:\data\plat_rsa_public_key.pem'
    # MCH_ID: 商户ID
    # 请登录商户后台,点击 个人中心 > 个人信息 在基本信息中获取商户ID
    MCH_ID = "S820240215181932000047"
    # 代付业务请求地址
    url = "https://tl-openapi.toppay.asia/gateway/cash"
    # 回调通知地址
    notify_url = "your notify url"

    @staticmethod
    def cash():
        request_params = OrderedDict()
        # 商户ID,可以在商户后台获取
        request_params["merchantCode"] = TopCashDemo.MCH_ID
        # 订单类型(0-法币(泰铢)交易)
        request_params["orderType"] = "0"
        # 收款方式 默认传Disbursement
        request_params["method"] = "Disbursement"
        # 商户订单号
        request_params["orderNum"] = "T1642592278863"
        # 代付金额(支持两位小数点位)
        request_params["money"] = "150.12" 
        # 手续费类型 0:代付金额内扣除,1:手续费另计
        request_params["feeType"] = "1"
        # 银行编码:参考附录I 代付
        request_params["bankCode"] = "001"
        # 客户银行卡号
        request_params["number"] = "12312431241"
        # 客户名称
        request_params["name"] = "Jack"
        # 按请求参数返回
        request_params["description"] = "代付下单"
        # 回调地址
        request_params["notifyUrl"] = TopCashDemo.notify_url 
        # 时间戳 格式 yyyyMMddHHmmss
        request_params["dateTime"] = "20220101235959"

        # 根据key进行参数排序
        key_str = ''.join([str(value) for value in request_params.values()])
        print("keyStr:", key_str)

        # 加密
        signed_str = TopCashDemo.private_encrypt(key_str, TopCashDemo.MCH_PRI_KEY_FILE)
        request_params["sign"] = signed_str

        # 发送请求
        post_json = json.dumps(request_params)
        print("Post Json Params:", post_json)

        response_json = TopCashDemo.do_post(TopCashDemo.url, post_json)
        print("Response Msg:", response_json)

        check = TopCashDemo.public_key_decrypt(signed_str, TopCashDemo.MCH_PUBLIC_KEY_FILE);
        print("check:", check)

    @staticmethod
    def private_encrypt(data, prikey_file):
        rsa_pri = RSA.load_key(prikey_file)
        # 使用私钥加密数据
        # M2Crypto.RSA.pkcs1_padding 是一种常见的填充方式
        crypto = b''
        for chunk in [data[i:i + 117] for i in range(0, len(data), 117)]:
            encrypt_data = rsa_pri.private_encrypt(chunk.encode('utf-8'), RSA.pkcs1_padding)
            crypto += encrypt_data
        return base64.b64encode(crypto).decode('utf-8')


    @staticmethod
    def public_key_decrypt(data, public_file):
        rsa_key = RSA.load_pub_key(public_file)
        data = base64.b64decode(data)
        crypto = b''
        for chunk in [data[i:i+128] for i in range(0, len(data), 128)]:
            decrypt_data = rsa_key.public_decrypt(chunk, RSA.pkcs1_padding)
            crypto += decrypt_data
        return crypto.decode('utf-8')
    @staticmethod
    def do_post(url, data):
        headers = {"Content-Type": "application/json"}
        response = requests.post(url, data=data, headers=headers)
        if response.status_code == 200:
            return response.json()
        return None

if __name__ == '__main__':
    TopCashDemo.cash()
const { encryptWithPrivateKey} = require('./RSAUtil');
const axios = require('axios');

//具体下单参数内容
//MerchantCode: 商户ID
//请登录商户后台,点击 个人中心 > 个人信息 在基本信息中获取商户ID
var MerchantCode = 'S820230414142102000012'
//订单类型(0-法币(泰铢)交易)
var OrderType = '0'
//商户订单号
var OrderNum = 'H202404161637110012'
//收款方式(默认传Disbursement)
var Method = 'Disbursement'
//订单金额,支持两位小数位
var Money = '100'
//手续费类型(0-帐内扣除,1-帐外扣除)
var FeeType = '0'
//时间 格式 yyyyMMddHHmmss
var DateTime = '20220101235959'
//客户银行卡号
var Number = '1548425413'
//银行编码:参考附录I 代付
var BankCode = '001'
//客户名称
var Name = 'จางซาน'
//描述
var Description = 'test'
//回调地址
var NotifyUrl = 'https://tl-api-doc.toppay.asia/thailand/signatureGenerate.html'

const data = {
    merchantCode: MerchantCode,
    orderType: OrderType,
    orderNum: OrderNum,
    method: Method,
    money: Money,
    feeType: FeeType,
    dateTime: DateTime,
    number: Number,
    bankCode: BankCode,
    name: Name,
    description: Description,
    notifyUrl: NotifyUrl
};

//将对象的键名按ASCII码排序
const sortedKeys = Object.keys(data).sort();

//使用排序后的键名拼接它们的值
let sortedString = '';
sortedKeys.forEach(key => {
    sortedString += data[key];
});

console.log(sortedString);
var sign = encryptWithPrivateKey(sortedString);
//将sign添加到data对象中
data.sign = sign;
const jsonData = JSON.stringify(data);
console.log(jsonData)

//代付url
var url = 'https://tl-openapi.toppay.asia/gateway/cash'

//请求选项
axios.post(url, jsonData,{
  headers: {
    'Content-Type': 'application/json'
  }
})
.then((response) => {
  console.log('状态码:', response.status);
  console.log('响应数据:', response.data);
})
.catch((error) => {
  console.error('请求失败:', error);
});

# 请求地址

  • 请求方式 : POST
  • 请求地址 : https://tl-openapi.toppay.asia/gateway/cash

# 请求参数

注:所有的参数中,不要填写中文!!!

参数 类型 必填 描述 示例
merchantCode String Y 商户ID,在商户平台获取 S820211021094748000001
orderType string(10) Y 订单类型 0-法币(泰铢)交易
method string(10) Y 收款方式 默认传Disbursement
orderNum String Y 商户订单号 10000001
money String Y 代付金额 150.12(支持两位小数点位)
feeType String Y 手续费类型 0 : 代付金额内扣除(实际到账金额=下单金额-手续费)
1 : 手续费另计(实际到账金额=下单金额)
bankCode String Y 银行编号 001
点击查看支持的银行编码
number String Y 客户银行卡号 12312431241
name String Y 客户名称 Jack
mobile String N 用户手机号码 1234567890
email String N 用户邮箱 [email protected]
notifyUrl String Y 回调地址 https://123123.com
dateTime String Y 时间戳格式:yyyyMMddHHmmss 20200101235959
description String Y 按请求参数返回 代付下单
sign String Y 签名 Yg+ePvTFhiRrARcZKBcRG0l8 ...

# 请求报文示例

{
  "merchantCode": "S820211021094748000001",
  "orderType": "0",
  "method": "Disbursement",
  "orderNum": "186888188666",
  "money": "100.00",
  "feeType": "1",
  "bankCode": "001",
  "number": "2021071209403321313122",
  "name": "test cash name",
  "mobile": "082122965511",
  "email": "[email protected]",
  "notifyUrl": "your notify url",
  "dateTime": "20220101235959",
  "description": "test cash",
  "sign": "Yg+ePvTFhiRrARcZKBcRG0l89rqisPIuZQStYqBIwSMPaqwH77qRXI1J+jElOBpa"
}

# 响应参数

参数 类型 必填 描述 示例
platRespCode String Y 请求业务是否成功 FAIL:失败\SUCCESS:成功
platRespMessage String Y 接口响应信息提示 请求成功
platOrderNum String Y 平台订单号 PI1453242857400963072
orderNum String Y 商户订单号 23645782
status Int Y 订单状态 查看订单状态描述
statusMsg String Y 订单状态信息 Apply
money String Y 代付金额 100.00
fee String Y 手续费金额 10.00
feeType String Y 手续费类型 0:订单内扣除,
1:手续费另计
bankCode String N 银行编号 001
点击查看支持的银行编码
number String Y 客户银行卡号 12312431241
name String Y 客户名称 Jack
description String Y 按请求参数返回 代付下单
platSign String Y 签名 PI1453242857400963072

# 代付响应报文示例

{
  "platRespCode": "SUCCESS",
  "platRespMessage": "Request success",
  "platOrderNum": "W0620220119174331000001",
  "orderNum": "186888188666",
  "status": 0,
  "statusMsg": "Apply",
  "money": "100.00",
  "fee": "10.00",
  "feeType": "0",
  "bankCode": "001",
  "number": "2021071209403321313122",
  "name": "test cash name",
  "description": "test cash",
  "platSign": "E5uNF7B9NXyhtlRo2I7/KVHN4Sbz0c3VbwCLpH3vjUpv6Cai+bmJA/Q8dVE2RJRe1+dsbzg=="
}

# 代付异步通知

  • 进行验签时,要用 商户后台-收付款配置-API配置中提供的平台公钥进行解密!!!
  • 进行验签时,以实际回调的参数为准,不要验签固定的参数
  • 订单的最终状态以通知的status为准!!!
  • TopPay结果异步通知后,需响应 SUCCESS 字符串,否则TopPay将继续向下游发起5次通知。

# 通知参数

参数 描述 示例
platOrderNum 平台订单号 BK_1563278763273
orderNum 商户订单号 T1231511321515
money 代付金额 150.12(支持小数点)
feeType 手续费类型 手续费类型
0:订单内扣除,
1:手续费另计
fee 手续费 10.00
name 客户名称 Neo
number 客户银行卡号 45649849659456
bankCode 到账银行 001
点击查看支持的银行编码
status 订单状态 查看订单状态描述
statusMsg 订单状态描述 Payout Success
description 订单描述 商户上传原样返回
platSign 平台签名 ja6R8eukQY9jc8...

# 异步通知报文示例

{
  "platOrderNum": "W0620220119174331000001",
  "orderNum": "186888188666",
  "money": "100.00",
  "fee": "10.00",
  "feeType": "0",
  "name": "test cash name",
  "number": "2021071209403321313122",
  "bankCode": "001",
  "status": "2",
  "statusMsg": "SUCCESS",
  "description": "test cash",
  "platSign": "LGEpz2LjbZ6Iyvn+zLc/+t26AaH0aEhHVD62lSCdo6XIkAg86AUncCvmym62wVoE3r2+dHnv27qi/01UQDcqFK8DYioRCcydYSjB4QRVezG3fcZlhWrACmWGacnXkE7p5zChL7pK5h0HuBhbo1zKt4FunQR6QMmcBVfv7YfB3W0"

}

# 泰文Unicode

法币(泰铢)代付下单,namedescription 如果使用泰文,则在下单时需要对其进行Unicode编码转换

需要注意!参数签名时,请使用泰文原文参与签名,否则会验签失败!!!


import org.apache.commons.lang3.StringUtils;

/**
 * Unicode工具类
 * 
 */
public class UnicodeUtil {

  public static void main(String[] args) {
    String str = "ข้อความต้นฉบับ";
    System.out.println("原始字符串:" + str);
    String unicodeStr = toUnicode(str, true);
    System.out.println("转换后的Unicode字符串:" + unicodeStr);
    String originalStr = toString(unicodeStr);
    System.out.println("转换回原始字符串:" + originalStr);
  }

  /**
   * 将字符串转换为Unicode编码的字符串
   *
   * @param originalText 待转换的原文
   * @param isSkipAscii  是否跳过ASCII字符(只跳过可见字符)
   * @return 转换后的unicode
   */
  public static String toUnicode(String originalText, boolean isSkipAscii) {
    if (StringUtils.isEmpty(originalText)) {
      return originalText;
    }

    final int len = originalText.length();
    final StringBuilder unicode = new StringBuilder(originalText.length() * 6);
    char c;
    for (int i = 0; i < len; i++) {
      c = originalText.charAt(i);
      if (isSkipAscii && isAsciiPrintable(c)) {
        unicode.append(c);
      } else {
        unicode.append(toUnicodeHex(c));
      }
    }
    return unicode.toString();
  }

  /**
   * unicode 转字符串
   *
   * @param unicode 待转换原文
   * @return 转换后的字符串
   */
  public static String toString(String unicode) {
    if (StringUtils.isBlank(unicode)) {
      return unicode;
    }

    final int len = unicode.length();
    StringBuilder sb = new StringBuilder(len);
    int i;
    int pos = 0;
    while ((i = StringUtils.indexOfIgnoreCase(unicode, "\\u", pos)) != -1) {
      sb.append(unicode, pos, i);//写入Unicode符之前的部分
      pos = i;
      if (i + 5 < len) {
        char c;
        try {
          c = (char) Integer.parseInt(unicode.substring(i + 2, i + 6), 16);
          sb.append(c);
          pos = i + 6;//跳过整个Unicode符
        } catch (NumberFormatException e) {
          //非法Unicode符,跳过
          sb.append(unicode, pos, i + 2);//写入"\\u"
          pos = i + 2;
        }
      } else {
        //非Unicode符,结束
        break;
      }
    }

    if (pos < len) {
      sb.append(unicode, pos, len);
    }
    return sb.toString();
  }

  /**
   * 是否为可见ASCII字符,可见字符位于32~126之间
   *
   * @param ch 待校验字符
   * @return 是否为可见ASCII字符
   */
  public static boolean isAsciiPrintable(char ch) {
    return ch >= 32 && ch < 127;
  }

  /**
   * 转换char为unicode
   *
   * @param ch 待转换char
   * @return 转换后的unicode
   */
  public static String toUnicodeHex(char ch) {
    String hex = Integer.toHexString(ch);
    if (hex.length() < 4) {
      hex = "0" + hex;
    }
    return "\\u" + hex;
  }

}
<?php 
  function unicode_encode($str) {
      $unicode = '';
      for ($i = 0; $i < mb_strlen($str); $i++) {
          $char = mb_substr($str, $i, 1);
          $unicode .= '\u' . str_pad(dechex(mb_ord($char)), 4, '0', STR_PAD_LEFT);
      }
      return $unicode;
  }
  $str = 'จ้าเหมยแซ่หลี่';
  $unicode = unicode_encode($str);
  echo $unicode;
?>
using System;
using System.Text;

public static class UnicodeConverter
{
    public static string ToUnicode(string input)
    {
        var sb = new StringBuilder();
        foreach (var c in input)
        {
            // 如果字符是中文或泰文,则转换为Unicode编码
            if ((c >= 0x4e00 && c <= 0x9fff) || // 中文
                (c >= 0x0e00 && c <= 0x0e7f))   // 泰文
            {
                sb.Append("\\u" + ((int)c).ToString("x4"));
            }
            else
            {
                sb.Append(c);
            }
        }
        return sb.ToString();
    }
}
package main

import (
	"fmt"
	"strings"
	"unicode/utf8"
)

// StringToUnicode 将字符串转换为Unicode编码形式
func StringToUnicode(s string) string {
	var unicodeStr strings.Builder
	for _, r := range s {
		// 检查字符是否为UTF-8编码的有效rune
		if r == utf8.RuneError {
			continue
		}
		// 将每个字符格式化为\u或\U前缀的编码
		if r <= 0xFFFF { // 对于16位以下的字符使用\u
			unicodeStr.WriteString(fmt.Sprintf(`\u%04X`, r))
		} else { // 对于更大的码位使用\U
			unicodeStr.WriteString(fmt.Sprintf(`\U%08X`, r))
		}
	}
	return unicodeStr.String()
}

func main() {
	// 示例:将中文转换为Unicode编码
	chinese := "你好,世界!"
	unicodeChinese := StringToUnicode(chinese)
	fmt.Println(unicodeChinese) // 输出:\u4F60\u597D\uFF0C\u4E16\u754C\uFF01

	// 示例:将泰文转换为Unicode编码
	thai := "สวัสดีครับ"
	unicodeThai := StringToUnicode(thai)
	fmt.Println(unicodeThai) // 输出:\u0E2A\u0E27\u0E31\u0E2A\u0E14\u0E35\u0E04\u0E23\u0E31\u0E1A
}

def to_unicode_escape(text):
    return text.encode('unicode_escape').decode('ascii')

# 使用示例
chinese_text = "你好,世界!"
thai_text = "สวัสดีชาวโลก!"

unicode_chinese = to_unicode_escape(chinese_text)
unicode_thai = to_unicode_escape(thai_text)

print(unicode_chinese)  # 输出: \u4f60\u597d\uff0c\u4e16\u754c\uff01
print(unicode_thai)     # 输出: \u0e2a\u0e27\u0e31\u0e2a\u0e14\u0e35\u0e0a\u0e32\u0e27\u0e42\u0e25\u0e01!
function toUnicode(str) {
    return str.split('').map(value => {
      return '\\u' + value.charCodeAt(0).toString(16).padStart(4, '0');
    }).join('');
  }
  
  const chineseText = '你好,世界!'; // 中文文本
  const thaiText = 'สวัสดีชาวโลก!'; // 泰文文本
  
  const encodedChineseText = toUnicode(chineseText);
  const encodedThaiText = toUnicode(thaiText);
  
  console.log(encodedChineseText); // 输出: \u4f60\u597d\uff0c\u4e16\u754c\uff01
  console.log(encodedThaiText); // 输出: \u0e2a\u0e27\u0e31\u0e2a\u0e14\u0e35\u0e0a\u0e32\u0e27\u0e42\u0e25\u0e01\u0021