THB Pay Api

# Code example

  • The code example is for reference only. For specific parameter descriptions, please refer to Request Parameter Description

TopPayRequestUtil Click to obtain code examples


import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Map;
import java.util.TreeMap;

public class PayDemo {

  //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 payUrl = "https://tl-openapi.toppay.asia/gateway/prepaidOrder";
  private static final String payNotify = "your notify url";
  private static final String cashNotify = "your notify url";

  public static void main(String[] args) throws Exception {
    pay();
  }
  private static void pay() throws Exception {
    Map<String, String> requestParams = new TreeMap<>();
    requestParams.put("merchantCode", MCH_ID);
    requestParams.put("orderType", "0"); // orderType(0-BAHT transaction)
    requestParams.put("method", "BankTransfer"); //  When using online banking, pass in the corresponding bank abbreviation, and pass in qr Pay when using a QR code, or not
    requestParams.put("transAccNo", "1234567890"); // The card number paid by the user must be transmitted, and the real card number must be passed, otherwise the transaction will fail
    requestParams.put("orderNum", "T1642592278863"); // merchant order number
    requestParams.put("payMoney", "100.00");  // order amount
    requestParams.put("notifyUrl", payNotify);// callback address
    requestParams.put("dateTime", "20220101235959");// timestamp format yyyyMMddHHmmss

    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);

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

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


<?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=';
    // Merchant ID from idntask, from User info
    
    //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 = 'S820211021094748000001';
     //Order Type(0-BAHT TRANSACTION)
    $orderType = '0';
    // Merchant system unique order number
    $orderNum = 'TEST1231231231';
    // pay money
    $payMoney = '100.00';
    // url for callback
    $notifyUrl = 'http://example.com/callback';
    // order time
    $dateTime = date("YmdHis",time());
    $params = array(
        'merchantCode' => $merchantCode,
        'orderType' => $orderType,
        'orderNum' => $orderNum,
        'payMoney' => $payMoney,
        'notifyUrl' => $notifyUrl,
        'dateTime' => $dateTime,
    );

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


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

    $params['sign'] = $sign;

    $params_string = json_encode($params);
    $url = 'https://tl-openapi.toppay.asia/gateway/prepaidOrder';
    $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 "payMoney :". $result['payMoney'] . "\n";
        echo "payFee :". $result['payFee'] . "\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 CreateBillDemo
    {
        //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 payUrl = "https://tl-openapi.toppay.asia/gateway/prepaidOrder";
        public static void requestPayment()
        {
            long currenttimemillis = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
            string merchantCode = MCH_ID;                                               // Merchant ID
            string orderType = "0";                                                     // Order Type
            string method = "qrPay";                                                    // payment method
            string orderNum = "123124124";                                              // Merchant order number
            string payMoney = "100.00";                                                 // Order amount
            string notifyUrl = "https://www.baidu.com";                                 // Callback address, which is the address notified after successful payment.
            string dateTime = "20191107105500";                                         // Timestamp format yyyyMMddHHmmss
            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("orderType", orderType);
            VarPost.Add("method", method);
            VarPost.Add("orderNum", orderNum);
            VarPost.Add("payMoney", payMoney);
            VarPost.Add("notifyUrl", notifyUrl);
            VarPost.Add("dateTime", dateTime);
            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
            int len = keyStr.Length;
            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(payUrl, "POST", jsonStr);
            Console.WriteLine("return:" + sRemoteInfo);     //receive string
            //string sRemoteInfo = System.Text.Encoding.UTF8.GetString(byRemoteInfo);
            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"`
	PayMoney     string `json:"payMoney"`
	NotifyUrl    string `json:"notifyUrl"`
	DateTime     string `json:"dateTime"`
	Method       string `json:"Method"`
	Sign         string `json:"sign"`
}

func main() {
	//Public and private keys (for testing only)
	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="
	//mode 1 (cashier mode)
	url := "https://tl-openapi.toppay.asia/gateway/prepaidOrder"
	//mode 2 (direct connection mode)
	//url := "https://tl-openapi.toppay.asia/gateway/payment"

	//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",
		//Order amount
		PayMoney: "100.00",
		//Callback notification address
		NotifyUrl: "openapi",
		//payment method
		Method: "qrPay",
		//Time format:yyyyMMddHHmmss
		DateTime: "20220101235959",
	}
	//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 TopPayDemo:
   # 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"
    
    # Checkout mode, use our Checkout page
    url = "https://tl-openapi.toppay.asia/gateway/prepaidOrder"  
    #Direct connection mode, obtain relevant payment information, no cashier page
    # pay_url = "https://tl-openapi.toppay.asia/gateway/payment"
    pay_notify = "your notify url"

    @staticmethod
    def pay():
        request_params = OrderedDict()
        # Merchant ID
        request_params["merchantCode"] = TopPayDemo.MCH_ID
        # Order type (0-fiat currency transaction)
        request_params["orderType"] = "0"
        # Order amount
        request_params["payMoney"] = "100.00"
        # Merchant order number
        request_params["orderNum"] = "T1642592278863"
        # payment method
        request_params["method"] = "qrPay" 
        # Callback notification address
        request_params["notifyUrl"] = TopPayDemo.pay_notify
        # 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 = TopPayDemo.private_encrypt(key_str, TopPayDemo.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 = TopPayDemo.do_post(TopPayDemo.url, post_json)
        print("Response Msg:", response_json)

        check = TopPayDemo.public_key_decrypt(signed_str, TopPayDemo.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__':
    TopPayDemo.pay()
const { encryptWithPrivateKey } = require('./RSAUtil');
const axios = require('axios');

//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
var merchantCode = 'S820230414142102000012'
//Order type (0-fiat currency transaction)
var orderType =0
//Merchant order number
var orderNum = 'H202405061145003'
//Order amount
var payMoney = 50
//Callback notification address
var notifyUrl = 'notify url222222'
//Time format:yyyyMMddHHmmss
var dateTime = '20240430112200'
//payment method
var method = 'qrPay'
const data = {
    merchantCode: merchantCode,
    orderType: orderType,
    orderNum: orderNum,
    payMoney: payMoney,
    notifyUrl: notifyUrl,
    dateTime: dateTime,
    method: method
};
console.log(merchantCode)
console.log(data.merchantCode)

//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)

//mode 1 (cashier mode)
var url = 'https://tl-openapi.toppay.asia/gateway/prepaidOrder'
//mode 2 (direct connection mode)
//var url = 'https://tl-openapi.toppay.asia/gateway/payment'

//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

  • Checkout counter mode (Mode 1): Open the checkout link to get payment information
    • Request method: POST
    • Request address: https://tl-openapi.toppay.asia/gateway/prepaidOrder
  • Direct connection mode (Mode 2): Obtain payment information directly (applicable to merchants with their own checkout page)
    • Request method: POST
    • Request address: https://tl-openapi.toppay.asia/gateway/payment

# Request parameters

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

  • Checkout counter mode (Mode 1):
Param Type Required Description Example
merchantCode string(32) Y merchant ID,Get it in merchant background S820211021094748000001
orderType string(10) Y order type 0-Fiat Currency (Thai Baht) Transaction
method string(32) N Payment method qrPay: Scan the QR code
BankTransfer : Online banking transfer
If not, choose your own payment method on the checkout page
orderNum string(32) Y merchant order number 10000001
transAccNo string(16) Y The real card number for payment is required.Must pass. Otherwise the order cannot be matched.
payMoney string(10) Y payment amount(only two decimal) 100.00
bankCode String(10) Y payment bank number 001
Click to view supported bank codes
notifyUrl string(100) Y Address to receive notification of successful order transaction https://host:port/notifyUrl
dateTime string(255) Y timestamp format:yyyyMMddHHmmss 20190101235959
paymentName string(64) Y Payer Real Name Jerry
extendParam string(100) N Extended parameters (uploaded content will be returned) 123
sign string(255) Y Sign fnbSOvY83pr8hXg+Fd ...
  • Direct connection mode (Mode 2):
Param Type Required Description Example
merchantCode string(32) Y merchant ID,Get it in merchant background S820211021094748000001
orderType string(10) Y order type 0-Fiat currency transaction
method string(32) Y Payment method qrPay : Scan the QR code👍
BankTransfer: Online banking transfer
orderNum string(32) Y merchant order number 10000001
payMoney string(10) Y payment amount(only two decimal) 100.00
notifyUrl string(100) Y Address to receive notification of successful order transaction https://host:port/notifyUrl
dateTime string(32) Y timestamp format:yyyyMMddHHmmss 20190101235959
transAccNo string(16) Y Real card number for payment
The real card number for payment is required.Must pass. Otherwise the order cannot be matched
1234567890
returnAccName string(10) N Whether the response parameters returns the payee name Need to return: true
No need to return: false
paymentName string(64) Y Payer Real Name Jerry
extendParam string(100) N Extended parameters (uploaded content will be returned) 123
sign string(255) Y Sign fnbSOvY83pr8hXg+Fd ...

# Request example

  • Checkout counter mode (Mode 1): (method parameters do not need to be passed, the page to be jumped is different)
{
    "merchantCode": "S820211021094748000001",
    "orderType": "0",
    "orderNum": "T1642593166888",
    "transAccNo": "1234567890", 
    "payMoney": "100.00",
    "method": "qrPay",
    "notifyUrl": "your notify url",
    "dateTime": "20220101235959",
    "paymentName": "Jerry",
    "extendParam": "123456",
    "sign": "fnbSOvY83pr8hXg+FdNNYi2ubQUGNv/qGYc4TjRl+Xxd1yc9fpkpTx5UQEDTgmhwdCKBkhHVsx2AiQbYDxZ5WBuU1GZeiJ"
}
  • **Direct connection mode (mode 2): **
{
    "merchantCode": "S820211021094748000001",
    "orderType": "0",
    "orderNum": "T1642593166888",
    "transAccNo": "1234567890", 
    "payMoney": "100.00",
    "method": "BankTransfer",
    "notifyUrl": "your notify url",
    "dateTime": "20220101235959",
    "returnAccName": "false",
    "paymentName": "Jerry",
    "extendParam": "123456",
    "sign": "fnbSOvY83pr8hXg+FdNNYi2ubQUGNv/qGYc4TjRl+Xxd1yc9fpkpTx5UQEDTgmhwdCKBkhHVsx2AiQbYDxZ5WBuU1GZeiJ"
}

# Response param

Param Type Required Description Example
platRespCode String Y whether the business is successful FAIL\SUCCESS
platRespMessage String Y interface response information prompt Request Transaction Success
platOrderNum String Y platform order number PI1453242857400963072
payMoney String Y payment amount 100.00
orderNum String Y merchant order number 23645782
bankName String N bank name KABNK
custAccName String N beneficiary name NVIDJ
url String N cash register link Cashier mode(mode 1),Returned when 'platRespCode' is SUCCESS
payData String N response parameters Api mode(mode 2),Returned when 'platRespCode' is SUCCESS
custAccName String N Payee name Api mode(mode 2),Returned when 'returnAccName' is true
paymentName string N Payer Real Name Jerry
extendParam string N Extended parameters (uploaded content will be returned) 123

# Response message example

  • Mode 1 response message example (url is the checkout link)
{
    "platOrderNum": "PRE1483771634191044608",
    "payMoney": "100.00",
    "orderNum": "T1642593166888",
    "platRespCode": "SUCCESS",
    "platRespMessage": "Request Transaction Success",
    "url": "https://tl-openapi.toppay.asia/gateway/order/PRE1483771634191044608",
    "paymentName": "Jerry",
    "extendParam": "123456"
}
  • Mode 2 response message example (when method=qrPay, payData returns the QR code serial number, when method=BankTransfer, returns the payment card number)
{
    "platOrderNum": "PRE1483771634191044608",
    "payMoney": "100.00",
    "orderNum": "T1642593166888",
    "platRespCode": "SUCCESS",
    "method": "BankTransfer",
    "bankName": "KBANK",
    "custAccName": "NVIDJ",
    "platRespMessage": "Request Transaction Success",
    "custAccName": "สวัสดี",
    "payData": "123456789",
    "paymentName": "Jerry",
    "extendParam": "123456"
}

Example of a failure response message

{
    "platRespCode": "FAIL",
    "platRespMessage": "Error message"
}

# Pay api callback notify

  • When verifying the signature, you must 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 accepting the asynchronous notification, you need to respond with the SUCCESS string, otherwise TopPay will continue to initiate 5 notifications! ! !

import com.google.gson.JsonObject;

public class TopPayNotify {
    // test account
    private static final String PLAT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2JoMfFqLsSJjAiCahEnlP3aRj8yCT+WHzR+VvPBTw9S1i7iYWb+MY09CG/HYuHF4+IxshXDJygmndxKf/esuwPybS8mAd//yubHpmZsmBqg1FffT8VH1APa6ZRWASUp4U01ZrbCCp35QA8FuWrJGMJxGx4xk7KUtV2yujxC8noQIDAQAB";  // platform public key
    public static void main(String[] args) throws Exception {
        JsonObject notifyBody = new jsonObject();
        boolean verifyResult = TopPayRequestUtil.verifySign(notifyBody,PLAT_PUBLIC_KEY);
        if (verifyResult) {
            // ... signature verification passed,do something
        } else {
            // ... signature verification error
        }
    }
}

<?php

$res = json_decode(file_get_contents('php://input'), true);
$platSign = $res['platSign'];
unset($res['platSign']);
$public_key = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDFJ/AmUV4Z8udG8aOBUt/kEwc/DbxF5Gtfw6Y00NHQ4Pz2X2x9IxjUZxn2dnFxmrmhqKNlfwXOqyejhBzi0pSHyGoI4XP9IEfZGO6YkSb9DCY1ZxX8fDl2G+tPCbWYTVO4JutFmzTWgk1Uhhu6L9dlOMUHvZf3/6czA/a9C7azXwIDAQAB';
$decryptSign = public_key_decrypt($platSign, $public_key);

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

if($params_str == $decryptSign) {
    if($res['code'] == '00') {
        echo 'success';
    }
    else {
        echo 'fail';
    }
}
else {
    echo 'fail';
}

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.Text;
using System.Threading.Tasks;

namespace demo.demos
{
    class CallbackDemo
    {
        private static readonly string PLAT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcEUIvQ/5L+SWbHOeR8VFeZvLbUk7V7OeEAQlQwIVLSZMTef3KtIOKKAsUYPf/aAcKRzZZXECODsPQiDPcdZvM/rFkgrFWkR7lPjTj5SiPxGaiK2Z2sne7A8aDF7fV/D7lfmEwNdZ7FWKVEB84/81BHnlGUwb5HpRTISG+boSO6wIDAQAB";  // Platform public key
        private static readonly string jsonstr = "{\"code\":\"00\",\"msg\":\"SUCCESS\",\"platOrderNum\":\"I1_1289033071470972928\",\"payMoney\":\"20000\",\"payFee\":\"3000\",\"method\":\"qrPay\",\"platSign\":\"INaY8jjdvaHdWKc4gXtTee9PwLl1157wC4+XN1tIQpHxnKtEjoGAD1cHok66eK+PzvPFUfmK/opvZhqf/MhOZEX6i/C9/iU4Esi9rfcN/l+DToG+rBPv8B4Ha908irHeosd3W4F1MnPCxxdjL+NH6aYyxX9cT5rZkJz5eUlr5Y8=\",\"orderNum\":\"T1596164382079\",\"status\":\"SUCCESS"}";

        public static void requestCallback()
        {
            bool pass = false;
            try
            {
                Dictionary<string, object> dict = JsonNewtonsoft.DeserializeJsonToDict(jsonstr);

                RSAForJava rsa = new RSAForJava();
                pass = rsa.verifySign(dict, PLAT_PUBLIC_KEY);  // Signature verification
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.WriteLine("verifysign:" + pass.ToString());
        }

    }
}

package main

import (
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"fmt"
	"log"
	"math/big"
)

func main() {
	// publicKey
	pubKeyBase64 := "MIGfMA0GC***********************************GsDwNLKjYWRGSFAGHGSWS"
	
	// signStr
	encryptedData := "sojbvosnr783fhH89SAVH**********************hvors09gossnHIOSNECKN="

	pubKey, err := parsePublicKey(pubKeyBase64)
	if err != nil {
		log.Fatalf("fail: %v", err)
	}

	encryptedBytes, err := base64.StdEncoding.DecodeString(encryptedData)
	if err != nil {
		log.Fatalf("fail: %v", err)
	}

	decryptedData, err := decryptWithPublicKey(pubKey, encryptedBytes)
	if err != nil {
		log.Fatalf("fail: %v", err)
	}

	fmt.Printf("result: %s\n", string(decryptedData))
}


func parsePublicKey(pubKeyBase64 string) (*rsa.PublicKey, error) {
	pubKeyBytes, err := base64.StdEncoding.DecodeString(pubKeyBase64)
	if err != nil {
		return nil, fmt.Errorf("fail: %v", err)
	}

	pubKeyInterface, err := x509.ParsePKIXPublicKey(pubKeyBytes)
	if err != nil {
		pubKeyInterface, err = x509.ParsePKCS1PublicKey(pubKeyBytes)
		if err != nil {
			return nil, fmt.Errorf("fail: %v", err)
		}
	}

	pubKey, ok := pubKeyInterface.(*rsa.PublicKey)
	if !ok {
		return nil, fmt.Errorf("is not publicKey")
	}

	return pubKey, nil
}

func decryptWithPublicKey(pubKey *rsa.PublicKey, encryptedData []byte) ([]byte, error) {
	k := (pubKey.N.BitLen() + 7) / 8
	if k != len(encryptedData) {
		return nil, fmt.Errorf("length is error")
	}

	m := new(big.Int).SetBytes(encryptedData)
	if m.Cmp(pubKey.N) > 0 {
		return nil, fmt.Errorf("data is too long")
	}

	m.Exp(m, big.NewInt(int64(pubKey.E)), pubKey.N)

	d := leftPad(m.Bytes(), k)
	if d[0] != 0 {
		return nil, fmt.Errorf("error")
	}
	if d[1] != 0 && d[1] != 1 {
		return nil, fmt.Errorf("not match")
	}

	var i = 2
	for ; i < len(d); i++ {
		if d[i] == 0 {
			break
		}
	}
	i++
	if i == len(d) {
		return nil, nil
	}

	return d[i:], nil
}

func leftPad(input []byte, size int) []byte {
	n := len(input)
	if n > size {
		n = size
	}
	out := make([]byte, size)
	copy(out[len(out)-n:], input)
	return out
} 

import base64
import json
from collections import OrderedDict

import requests
from M2Crypto import RSA


class TopNotifyDemo:
    PLAT_PUBLIC_KEY_FILE = 'D:\data\plat_rsa_public_key.pem'
    MCH_ID = "S820240215181932000047"

    @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')


if __name__ == '__main__':
    response = '{"platOrderNum":"I1_1289033071470972928","payMoney":"20","payFee":"3000","method":"qrpay","platSign":"INaY8jjdvaHdWKc4gXtTee9PwLl1157wC4+XN1tIQpHxnKtEjoGAD1cHok66eK+PzvPFUfmK/opvZhqf/MhOZEX6i/C9/iU4Esi9rfcN/l+DToG+rBPv8B4Ha908irHeosd3W4F1MnPCxxdjL+NH6aYyxX9cT5rZkJz5eUlr5Y8=\",\"orderNum\":\"T1596164382079\",\"code\":\"SUCCESS\",\"msg\":\"Request Transaction Success\",\"status\":\"SUCCESS"}'
    response_json = json.loads(response)
    sign = response_json["sign"]
    del response_json["sign"]
    sign='U/ohCCCF9Ia3Vq+eF0TIxM4yQBMLOANdNPdVJ+U3bVtBjxlAl8YnjgizhKuiaRlP4Em4clLcshlYTjtDX9aRDIjuCew8if4y7PAX5q66Zvka5XCJgu3jOpmOP0InVtTEndhVjNaQwYCnSc3W6w13vjshJZepHgyfjnb/ij4UjJU='
    data = json.JSONDecoder(object_pairs_hook=OrderedDict).decode(response_json)
    key_str = ''.join([str(value) for value in data.values()])
    check = TopNotifyDemo.public_key_decrypt(sign, TopNotifyDemo.PLAT_PUBLIC_KEY_FILE);
    if(key_str == check):
        print("true")
    print("false")
    print(response_json)

const { decryptWithPublicKey } = require('./RSAUtil');
const publicKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCQ4pegy9+XNK6u9m2qkcenSczXa0tgcUbZn51bvBqLIscRnTPJsyY6zVOIh1fS4FLfs+llX1ihSDgVBk/Rs8YW2WdSwj/TVtGUrVTIaN3UaH2HK17TWMttFwX0AKkhAEOu1+E7TfzPubz/uvtzpa1u4/h5P4Pvkb1ifHkq+quaOQIDAQAB
-----END PUBLIC KEY-----`;

const jsonString = '{"msg":"SUCCESS","code":"00","method":"qrPay","transAccNo":"*****-x9088-x","orderNum":"20240508224642","platOrderNum":"PRE1788234076591779906","payFee":"3.00","payMoney":"100.00","platSign":"BCJqad4TC8iUQRlA1SqzWrnV86FNJ1ugcaAS+DToje0NLbDV2kPhI61Y3vXJShZD7Fo0NDmdaW1qu8i3Whf9jFmj4n9QqAAy5jC4dxmk//cpTSYW1kMGBQs0q6dkuMBnRL3WyGxeEW4W43p6NrrvGTcQUNs4Lu4oZhL1Wvg1MyA=","status":"SUCCESS"}';

try {
    //Convert message to Json structure
    const jsonObj = JSON.parse(jsonString);
    //After taking out the signature, remove the signature
    const signature = jsonObj.platSign;
    delete jsonObj['platSign'];   
    //Sort object key names by ASCII code
    const sortedKeys = Object.keys(jsonObj).sort();
    //Concatenate their values using sorted key names
    let sortedString = '';
    sortedKeys.forEach(key => {
        sortedString += jsonObj[key];
    });
    console.log(sortedString);
   //Decrypt using public key
   const decryptedData = decryptWithPublicKey(signature);
  
  console.log(sortedString === decryptedData.toString());
  if(sortedString === decryptedData.toString()){
    //Business processing
  }
} catch (e) {
    console.error('验证签名时发生错误:', e);
}

# Notify Params

Param Required Remark Example
code Y response code 00
msg Y response
message
SUCCESS
method Y pay type BankTransfer:Online bank transfer
qrPay:QR code scanning
status Y pay result Click to view order status description
platOrderNum Y platform order number BK_1563278763273
orderNum Y merchant order number T1231511321515
payMoney Y payment
amount
100.00
payFee Y merchant fee 10.00
transAccNo Y Payment card number 123456
paymentName N Payment name Jerry
extendParam N Extend parameters (uploaded content will be returned by the original path) 123
platSign Y Platform Sign ja6R8eukQY9jc8zrhtf34654ungj7u8sdgdfjfs

# Pay api callback notify example

{
  "code": "00",
  "msg": "SUCCESS",
  "status": "SUCCESS",
  "method": "BankTransfer",
  "platOrderNum": "PRE1483771634191044608",
  "orderNum": "T1642593166888",
  "payMoney": "100.00",
  "payFee": "10.00",
  "transAccNo": "*****1236",
  "paymentName": "Jerry",
  "extendParam": "123456",
  "platSign": "ja6R8eukQY9jc8zrhtf34654ungj7u8sdgdfjfs"
}