THB Cash Api

# Code Example

  • The code example is for reference only, please refer to request parameter description for specific parameter description

TopPayRequestUtil Click to obtain code examples

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

  //MCH_ID: Merchant ID
  //1.Please log in to the merchant backend
  //2.Click on personal center > personal information
  //3.Get Merchant ID in Basic Information
  private static final String MCH_ID = "S820211021094748000001";
  private static final String PLAT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2JoMfFqLsSJjAiCahEnlP3aRj8yCT+WHzR+VvPBTw9S1i7iYWb+MY09CG/HYuHF4+IxshXDJygmndxKf/esuwPybS8mAd//yubHpmZsmBqg1FffT8VH1APa6ZRWASUp4U01ZrbCCp35QA8FuWrJGMJxGx4xk7KUtV2yujxC8noQIDAQAB";  // platform public key
  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";  // merchant private key
  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"); // Merchant order number
    requestParams.put("method", "Disbursement"); // Payment method (disbursement by default)
    requestParams.put("orderType", "0"); // Order Type(0-baht transaction)
    requestParams.put("money", "125.12"); // Order amount, supports two decimal places
    requestParams.put("feeType", "0");  //  fee type
    requestParams.put("dateTime", "20200101235959");// timestamp format yyyyMMddHHmmss
    requestParams.put("number", "2021071209403321313122");     // Customer bank card number
    requestParams.put("bankCode", "001");       // Bank code: refer to Appendix I pay
    //Name The original text participates in the signature, but Unicode encoding is required when calling the API
    requestParams.put("name", "จางซาน");  // customer name
    requestParams.put("mobile", "082122965511"); // customer phone,Can not pass
    requestParams.put("email", "[email protected]"); // customer mail,Can not pass
    //The original text of description participates in the signature, but Unicode encoding is required when calling the API
    requestParams.put("description", "คำอธิบาย");    // description
    requestParams.put("notifyUrl", cashNotify);  // callback address
    StringBuilder stringBuilder = new StringBuilder();
    for (String key : requestParams.keySet()) {
      stringBuilder.append(requestParams.get(key));  // stitching parameters
    }

    String keyStr = stringBuilder.toString();  // get the string to be encrypted
    System.out.println("keyStr:" + keyStr);
    String signedStr = TopPayRequestUtil.privateEncrypt(keyStr, TopPayRequestUtil.getPrivateKey(MCH_PRIVATE_KEY));  // private key encryption
    requestParams.put("sign", signedStr);


    //After the signature is completed, encode the name and description UnicodeUtil sample code reference Item 9 of this section Thai Unicode
    requestParams.put("name", UnicodeUtil.toUnicode("จางซาน", true));  // customer name
    requestParams.put("description", UnicodeUtil.toUnicode("คำอธิบาย", true));    // description

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

    String responseJson = TopPayRequestUtil.doPost(cashUrl, postJson);  // send post json request
    System.out.println("Response Msg:" + responseJson);

    boolean pass = TopPayRequestUtil.verifySign(new Gson().fromJson(responseJson, JsonObject.class), PLAT_PUBLIC_KEY);  // signature verification
    if (pass) {
      // ... signature verification passed,execute normal business logic
    } else {
      // ... signature verification error
    }
  }
}


<?php
    // platform public key, from Secret key config
    $platPublicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiaKBgQCcEUIvQ/5L+SWbHOeR8VFeZvLbUk7V7OeEAQlQwIVLSZMTef3KtsOKKAsUYPf/aAcKRzZZXECODsPQiDPcdZvM/rFkgrFWkR7lPjTj5SiPxGaiK2Z2sne7A8aDF7fV/D7lfmEwNdZ7FWKVEB84/81BHnlGUwb5HpRTISG+boSO6wIDAQAB';
    // Merchant private key
    $mchPrivateKey = 'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMigm7rtWnTeNagwFzGTH+Uw1ypbiy7VhIoFJbgSYSSHdCaXWdT/l2+2fQlEYgAETVZ/IXB29MCnrf3O0dwRFXiipIbsm5zyqSLiS6cKXe8zN1/PlQWUbEt5wyWm0GADB/4bV6eu6gA7sGXmjQqrzfKZkcie3aK7+7ry1NFxTI51AgMBAAECgYEAklqXQAVlt1tiSQ7L3J425jp6u6uMHN4lkYmvuleuBbfKQ1yla3wIPLYjAF+iHeEFidOz0Rb19JRdmIkHDkJoJg2W27LvO6RdUwzgRnsuA3OuNz97w08B3aXXbPmB91nTFjKSlUsbh3IQWP71noxW+iKn844EW5hC5Gvn4L3quAECQQDrz1r0VKIbBSBB2aLuz1XyD/TBT2aRhvOKf0XtTRiQhNjtJxoQmvNbbhvUwj8an7HyCuihAbdbrC2ymFFyOSDZAkEA2c4Yudi48C6COrroi1cWgPlEFeGJXP/V1k5loZ1n2vstYAGPhAB4wUnFBLDvMqaBzWJt7MRkiazT8KnBQCDY/QJAMXpNlEyZwt+deBOpO0BnwSWV7mWxmMFfImU4D+WITPbC7aexsWBBxaJh1o93XCe715RwYTAR//stj3akSDoyaQJAa4FKuxC51/Nc3Fg9R+modeiTLqmv/3NXvPvdNjRXesLX1rduex0wfVdII9ShfEKrdxDKaT9W0NyzD+r6NAkCkQJBAMAnTgPYf0f7rh417GdoP7R7Nwi8KBKwPHlmfRukibOQlKt9xjqpsKJwglLn8pcnXbYbswXIdqzuBvIGAe3OWNg=';
   
    //merchantCode: Merchant ID
    //1.Please log in to the merchant backend
    //2.Click on personal center > personal information
    //3.Get Merchant ID in Basic Information
    $merchantCode = 'YOUR_MERCHANT_CODE_HERE';
    // Merchant system unique order number
    $orderNum = 'T'.date("YmdHis",time());
    // Method 
    $method = 'Disbursement';
    //order type(0-baht transaction)
    $orderType = '0';
    // withdraw money
    $money = '20000';
    // fee type
    $feeType = '1';
    // timestamp format yyyyMMddHHmmss
    $dateTime = date("YmdHis",time());
    // customer bank card number
    $number = '123456';
    // bank code(for details refer to the bottom of the document)
    $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;

    //After the original text participates in the signature, it needs to use unicode encoding. For the encoding method, refer to Item 9 in this section. Thai 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: Merchant ID
        //1.Please log in to the merchant backend
        //2.Click on personal center > personal information
        //3.Get Merchant ID in Basic Information
        private static readonly string MCH_ID = "S820191106095842000004";
        private static readonly string PLAT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcEUIvQ/5L+SWbHOeR8VFeZvLbUk7V7OeEAQlQwIVLSZMTef3KtIOKKAsUYPf/aAcKRzZZXECODsPQiDPcdZvM/rFkgrFWkR7lPjTj5SiPxGaiK2Z2sne7A8aDF7fV/D7lfmEwNdZ7FWKVEB84/81BHnlGUwb5HpRTISG+boSO6wIDAQAB";  // Platform public key
        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=";  //  Merchant private key
        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;                                             // Merchant ID
            string orderNum = "CASH" + currenttimemillis.ToString();                    // Merchant order number
            string money = "20000";                                                     // Order amount
            string feeType = "1";                                                       // Handling fee 0: Deducted from the withdrawal amount 1: Handling fee is additional
            string dateTime = "20191107105500";                                         // Timestamp format yyyyMMddHHmmss
            string name = "CHANDRA DERMAWAN";                                           // Payment account name
            string number = "3500035098";                                               // Receipt account number. Please note that the beneficiary name and the collection card number need to be consistent, otherwise the transfer may fail. It is recommended to connect to the account information verification interface to obtain the account name.
            string bankCode = "001";                                                    // Bank number
            string description = "TestCash";                                            // Order description
            string notifyUrl = "https://www.baidu.com";                                 // Callback address
            Dictionary<string, object> VarPost = new Dictionary<string, object>();
            VarPost.Add("merchantCode", merchantCode);//Parameters identified by a are passed to the web page using POST value transfer method.
            VarPost.Add("method", method);
            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();// sort key
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < paramNameList.Count; i++)
            {
                string key = paramNameList[i];
                stringBuilder.Append(VarPost[key]);  // Splicing parameters
            }
            String keyStr = stringBuilder.ToString();  // Get the string to be encrypted
            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);     //Send string
            string sRemoteInfo = w.UploadString(cashUrl, "POST", jsonStr);
            Console.WriteLine("return:" + sRemoteInfo);     //Receive string
            Dictionary<string, object> dict = JsonNewtonsoft.DeserializeJsonToDict(sRemoteInfo);
            bool pass = false;
            try
            {
                RSAForJava rsa = new RSAForJava();
                pass = rsa.verifySign(dict, PLAT_PUBLIC_KEY);  //Signature verification
            }
            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"
)

// Create json request structure
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"
	//Specific order parameters
	request := RequestBody{
		//MerchantCode: Merchant ID
        //1.Please log in to the merchant backend
        //2.Click on personal center > personal information
        //3.Get Merchant ID in Basic Information
		MerchantCode: "S820230414142102000012",
		//Order type (0-fiat currency transaction)
		OrderType: "0",
		//Merchant order number
		OrderNum: "H202404161637",
		//Payment method (disbursement is passed by default)
		Method: "Disbursement",
		//Order amount
		Money: "100",
		//Fee type (0-on-account deduction, 1-off-account deduction)
		FeeType: "0",
		//Time format yyyyMMddHHmmss
		DateTime: "20220101235959",
		//Customer bank card
		Number: "1548425413",
		//Bank code: refer to Append I for payment
		BankCode: "001",
		//Customer name
		Name: "จางซาน",
		//Customer mobile phone number is not required.
		Mobile: "082122965511",
		//Customer email address is optional
		Email: "[email protected]",
		//describe
		Description: "代付下单",
		//Callback notification address
		NotifyUrl: "openapi",
	}
	//Sort the fields of the structure by JSON tags and splice their values
	sortedValues, err := sortedConcatenatedValues(request)
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		return
	}
	//The sorted and spliced values are encrypted using the private key and base64 encoded.
	encryptedData := cryptor.PriEncrypt([]byte(sortedValues))
	encodedString := base64.StdEncoding.EncodeToString(encryptedData)
	//Put the obtained signature into the request structure
	request.Sign = encodedString
	jsonBytes, err := json.Marshal(request)
	if err != nil {
		fmt.Printf("Error: %s", err.Error())
		return
	}
	fmt.Println("json2", bytes.NewBuffer(jsonBytes))
	//Make http request
	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()
	//Read and print the response body
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Error reading response body:", err)
		return
	}
	fmt.Println("Response Body:", string(respBody))
}

/**
* Use the JSON tag of the structure to sort according to ASCII and splice the corresponding value into a string
 */
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] //Ignore omitempty option
		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:
     # Merchant private key storage address
    MCH_PRI_KEY_FILE = 'D:\data\company_rsa_private_key.pem'
    # Platform public key storage address
    MCH_PUBLIC_KEY_FILE = 'D:\data\plat_rsa_public_key.pem'
    //MCH_ID: Merchant ID
    //1.Please log in to the merchant backend
    //2.Click on personal center > personal information
    //3.Get Merchant ID in Basic Information
    MCH_ID = "S820240215181932000047"
    # Payment service request address
    url = "https://tl-openapi.toppay.asia/gateway/cash"
    # Callback notification address
    notify_url = "your notify url"

    @staticmethod
    def cash():
        request_params = OrderedDict()
        # Merchant ID
        request_params["merchantCode"] = TopCashDemo.MCH_ID
        # Order type (0-fiat currency transaction)
        request_params["orderType"] = "0"
        # Payment method (disbursement is passed by default)
        request_params["method"] = "Disbursement"
        # Merchant order number
        request_params["orderNum"] = "T1642592278863"
        # Order amount
        request_params["money"] = "150.12" 
        # Fee type (0-on-account deduction, 1-off-account deduction)
        request_params["feeType"] = "1"
        # Bank code: refer to Append I for payment
        request_params["bankCode"] = "001"
        # Customer bank card
        request_params["number"] = "12312431241"
        # Customer name
        request_params["name"] = "Jack"
        # describe
        request_params["description"] = "代付下单"
        # Callback notification address
        request_params["notifyUrl"] = TopCashDemo.notify_url 
        # Time format yyyyMMddHHmmss
        request_params["dateTime"] = "20220101235959"

        # Sort parameters according to key
        key_str = ''.join([str(value) for value in request_params.values()])
        print("keyStr:", key_str)

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

        # Send request
        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)
        # Encrypt data using private key
        # M2Crypto.RSA.pkcs1_padding   is a common filling method
        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');

//MCH_ID: Merchant ID
//1.Please log in to the merchant backend
//2.Click on personal center > personal information
//3.Get Merchant ID in Basic Information
var MerchantCode = 'S820230414142102000012'
//Order type (0-fiat currency transaction)
var OrderType = '0'
//Merchant order number
var OrderNum = 'H202404161637110012'
//Payment method (disbursement by default)
var Method = 'Disbursement'
//Order amount
var Money = '100'
//Fee type (0-on-account deduction, 1-off-account deduction)
var FeeType = '0'
//Time format yyyyMMddHHmmss
var DateTime = '20220101235959'
//Customer bank card
var Number = '1548425413'
//Bank code: refer to Append I for payment
var BankCode = '001'
//Customer name
var Name = 'จางซาน'
//Describe
var Description = 'test'
//Callback notification address
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
};

//Sort object key names by ASCII code
const sortedKeys = Object.keys(data).sort();

//Concatenate their values using sorted key names
let sortedString = '';
sortedKeys.forEach(key => {
    sortedString += data[key];
});

console.log(sortedString);
var sign = encryptWithPrivateKey(sortedString);
//Add sign to the data object
data.sign = sign;
const jsonData = JSON.stringify(data);
console.log(jsonData)

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

//Send request
axios.post(url, jsonData,{
  headers: {
    'Content-Type': 'application/json'
  }
})
.then((response) => {
  console.log('code:', response.status);
  console.log('message:', response.data);
})
.catch((error) => {
  console.error('fail:', error);
});

# Request Address

  • Request method: POST
  • Request address: https://tl-openapi.toppay.asia/gateway/cash

# Request param

Note: Do not fill in Chinese in all the parameters! ! !

Param Type Required Remark Example
merchantCode string Y merchant ID,Get it in Merchant Platform-Personal Center-Personal Information S820211021094748000001
orderType string(10) Y order Type 0-baht transaction
method string(10) Y payment method Disbursement is passed by default
orderNum string Y merchant order number 10000001
money string Y payment amount 150.12(supports two decimal places)
feeType String Y fee type 0: deducted from the payment amount(Amount received = order amount - fee)
1: extra handling fee(Amount received = order amount)
bankCode String Y bank number Click to view supported bank codes
number String Y customer bank card number 12312431241
name String Y Customer name Jack
mobile String N customer phone 1234567890
email String N customer mail [email protected]
notifyUrl string Y callback address https://123123.com
dateTime string Y timestamp format:yyyyMMddHHmmss 20200101235959
description string Y return by request parameter pai
sign string Y Sign Yg+ePvTFhiRrARcZKBcRG0l8 ...

# Request example

{
  "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"
}

# Response param

Param Type Required Remark Example
platRespCode String Y code FAIL:fail\SUCCESS:success
platRespMessage String Y Message SUCCESS
platOrderNum String Y Platform order number PI1453242857400963072
orderNum String Y merchant order number 23645782
status Int Y order status Click to view the order status description
statusMsg String Y order status information Apply
money string Y payment amount 100.00
fee String Y fee amount 10.00
feeType String Y fee type 0:order deduction
1:extra handling fee
bankCode String N bank number Click to view supported bank codes
number String Y customer bank card number 12312431241
name String Y customer name Jack
description String Y return by request parameter pay
platSign String Y Sign PI1453242857400963072

# Response example

{
  "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=="
}

# Cash api callback notify

  • When verifying the signature, use the platform public key provided in Merchant Background-Receipt and Payment Configuration-API Configuration to decrypt! ! !
  • When verifying the signature, the actual callback parameters shall prevail. Do not verify the fixed parameters
  • The final status of the order is subject to the status of the notification! ! !
  • After TopPay results are notified asynchronously, you need to respond with the SUCCESS string, otherwise TopPay will continue to send 5 notifications to the downstream.

# Notify Params

Param Remark Example
platOrderNum platform order number BK_1563278763273
orderNum merchant order number T1231511321515
money amount 100000
feeType fee type 0:deduction in order, 1:deduction out order
fee fee 10.00
name name Neo
number bank number 45649849659456
bankCode bank code Click to view supported bank codes
status order status Click to view the order status description
statusMsg order status message Payout Success
description description description
platSign sign ja6R8eukQY9jc8...

# Cash api callback notify example

{
  "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"

}

# Thai unicode

When placing an order in French currency (Thai Baht), name and description will need to be converted to Unicode when placing an order.

requires attention! When signing parameters, please use the original Thai text to participate in the signature, otherwise the signature verification will fail! ! !


import org.apache.commons.lang3.StringUtils;

/**
 * unicode tools
 * 
 */
public class UnicodeUtil {

  public static void main(String[] args) {
    String str = "ข้อความต้นฉบับ";
    System.out.println("raw string:" + str);
    String unicodeStr = toUnicode(str, true);
    System.out.println("converted unicode string:" + unicodeStr);
    String originalStr = toString(unicodeStr);
    System.out.println("convert back to original string:" + originalStr);
  }

  /**
   * converts a string to a unicode encoded string
   *
   * @param originalText original text to be converted
   * @param isSkipAscii  Whether to skip ASCII characters (only visible characters are skipped)
   * @return converted 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 convert string
   *
   * @param unicode original text to be converted
   * @return converted string
   */
  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);//write the part before the unicode character
      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;//skip entire unicode characters
        } catch (NumberFormatException e) {
          //illegal unicode character skip
          sb.append(unicode, pos, i + 2);//Write "\\u"
          pos = i + 2;
        }
      } else {
        //non unicode character end
        break;
      }
    }

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

  /**
   * Whether it is a visible ASCII character, the visible character is between 32~126
   *
   * @param ch character to be checked
   * @return whether it is a visible ascii character
   */
  public static boolean isAsciiPrintable(char ch) {
    return ch >= 32 && ch < 127;
  }

  /**
   * convert char to unicode
   *
   * @param ch char to be converted
   * @return converted 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)
        {
            // If the character is Chinese or Thai, convert to Unicode encoding
            if ((c >= 0x4e00 && c <= 0x9fff) || // Chinese
                (c >= 0x0e00 && c <= 0x0e7f))   // Thai
            {
                sb.Append("\\u" + ((int)c).ToString("x4"));
            }
            else
            {
                sb.Append(c);
            }
        }
        return sb.ToString();
    }
}
package main

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

// Convert string to Unicode encoding form
func StringToUnicode1(s string) string {
	var unicodeStr strings.Builder
	for _, r := range s {
		// Check if a character is a valid rune encoded in UTF-8
		if r == utf8.RuneError {
			continue
		}
		// Format each character to the encoding prefixed by \u or \U
		if r <= 0xFFFF {
			unicodeStr.WriteString(fmt.Sprintf(`\u%04X`, r))
		} else {
			unicodeStr.WriteString(fmt.Sprintf(`\U%08X`, r))
		}
	}
	return unicodeStr.String()
}

func main4() {
	//Example: Convert Chinese to Unicode encoding
	chinese := "你好,世界!"
	unicodeChinese := StringToUnicode(chinese)
	fmt.Println(unicodeChinese) //Output: \u4F60\u597D\uFF0C\u4E16\u754C\uFF01

	// Example: Convert Thai to Unicode encoding
	thai := "สวัสดีครับ"
	unicodeThai := StringToUnicode(thai)
	fmt.Println(unicodeThai) // Output: \u0E2A\u0E27\u0E31\u0E2A\u0E14\u0E35\u0E04\u0E23\u0E31\u0E1A
}

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

# Usage example
chinese_text = "你好,世界!"
thai_text = "สวัสดีชาวโลก!"

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

print(unicode_chinese)  # Output:  \u4f60\u597d\uff0c\u4e16\u754c\uff01
print(unicode_thai)     # Output:  \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