Cash Api

# Code Sample

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

TopPayRequestUtil(Click here to get the code sample)

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

  private static final String MCH_ID = "S820250514103726000009";
  private static final String PLAT_PUBLIC_KEY = "MIGfMA0GC..........oQIDAQAB";
  private static final String MCH_PRIVATE_KEY = "MIICeA2n2Rut..........NxI2kXf3Vp";
  private static final String cashUrl = "https://vnm-openapi.toppay.asia/gateway/payOut";
  private static final String cashNotify = "http://xxxxx";

  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", "T1234567890");
    requestParams.put("method", "DISBURSEMENT");
    requestParams.put("orderType", "0");
    requestParams.put("money", "20000");
    requestParams.put("feeType", "0");
    requestParams.put("dateTime", "20200101235959");
    requestParams.put("bankCard", "1154149865112");
    requestParams.put("bankCode", "SCB");
    requestParams.put("accountName", "accountName"); 
    requestParams.put("extendParam", "TEST"); 
    requestParams.put("notifyUrl", cashNotify);
    List<String> paramNameList = new ArrayList<>();
    for (String key : requestParams.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);
  
    String postJson = new Gson().toJson(requestParams);
    System.out.println("Post Json Params:" + postJson);

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

    boolean pass = TopPayRequestUtil.verifySign(new Gson().fromJson(responseJson, JsonObject.class), PLAT_PUBLIC_KEY); 
    if (pass) {
    } else {
    }
  }
}

<?php
    $platPublicKey = 'MIGfMA0GCSqGSI..........oSO6wIDAQAB';
    $mchPrivateKey = 'MIICdwIBADANB............GAe3OWNg=';
    $merchantCode = 'YOUR_MERCHANT_CODE_HERE';
    $orderNum = 'T'.date("YmdHis",time());
    $method = 'DISBURSEMENT';
    $orderType = '0';
    $money = '20000';
    $feeType = '1';
    $dateTime = date("YmdHis",time());
    $bankCard = '123456';
    $bankCode = 'SCB';
    $accountName = 'accountName';
    $extendParam = 'TEST';
    $notifyUrl = 'http://example.com/callback';
    $params = array(
        'merchantCode' => $merchantCode,
        'orderType' => $orderType,
        'method' => $method,
        'orderNum' => $orderNum,
        'money' => $money,
        'feeType' => $feeType,
        'dateTime' => $dateTime,
        'bankCard' => $bankCard,
        'bankCode' => $bankCode,
        'accountName' => $accountName,
        'notifyUrl' => $notifyUrl,
        'extendParam' => $extendParam
    );

    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['accountName'] = $accountName;
    $params['extendParam'] = $extendParam;

    $params_string = json_encode($params);
    $url = 'https://vnm-openapi.toppay.asia/gateway/payOut';
    $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);

    $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 "feeType :". $result['feeType'] . "\n";
        echo "bankCode :". $result['bankCode'] . "\n";
        echo "bankCard :". $result['bankCard'] . "\n";
        echo "accountName :". $result['accountName'] . "\n";
        echo "extendParam :". $result['extendParam'] . "\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
    {
        private static readonly string MCH_ID = "S820250514103726000009";
        private static readonly string PLAT_PUBLIC_KEY = "MIGfMA0GCSqGS.......IDAQAB"; 
        private static readonly string MCH_PRIVATE_KEY = "MIICdwIB1nTFjKS............3OWNg=";
        private static readonly string cashUrl = "https://vnm-openapi.toppay.asia/gateway/payOut";
        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";                                                    
            string dateTime = "20191107105500";                                        
            string accountName = "CHANDRA DERMAWAN";                             
            string bankCard = "3500035098";                                    
            string bankCode = "SCB";                                            
            string extendParam = "TestCash";                                 
            string notifyUrl = "https://www.baidu.com";                         
            Dictionary<string, object> VarPost = new Dictionary<string, object>();
            VarPost.Add("merchantCode", merchantCode);
            VarPost.Add("orderNum", orderNum);
            VarPost.Add("money", money);
            VarPost.Add("feeType", feeType);
            VarPost.Add("dateTime", dateTime);
            VarPost.Add("accountName", accountName);
            VarPost.Add("bankCard", bankCard);
            VarPost.Add("bankCode", bankCode);
            VarPost.Add("extendParam", extendParam);
            VarPost.Add("notifyUrl", notifyUrl);
            List<string> paramNameList = new List<string>();
            foreach (string key in VarPost.Keys)
            {
                paramNameList.Add(key);
            }
            paramNameList.Sort();
            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"
)

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"`
	BankCard       string `json:"bankCard"`
	BankCode     string `json:"bankCode"`
	AccountName         string `json:"accountName"`
	extendParam  string `json:"extendParam"`
	NotifyUrl    string `json:"notifyUrl"`
	Sign         string `json:"sign"`
}

func main() {
	cryptor := NewCryptor()
	cryptor.Pub64 = "MIGfMA0GCSqGSUAA4G...........7Bj0wIDAQAB"
	cryptor.Pri64 = "MIICdwIBADANBgkqhkiG9w0BAQ........................eWWBDEfuk="
	
	url := "https://vnm-openapi.toppay.asia/gateway/payOut"
	request := RequestBody{
		MerchantCode: "S820250514103726000009",
		OrderType: "0",
		OrderNum: "H202404161637",
		Method: "DISBURSEMENT",
		Money: "100",
		FeeType: "0",
		DateTime: "20220101235959",
		BankCard: "1548425413",
		BankCode: "SCB",
		AccountName: "accountName",
		ExtendParam: "TEST",
		NotifyUrl: "openapi",
	}
	sortedValues, err := sortedConcatenatedValues(request)
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		return
	}
	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))
	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))
}

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] 
		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 = '\data\company_rsa_private_key.pem'
    MCH_PUBLIC_KEY_FILE = '\data\plat_rsa_public_key.pem'
    MCH_ID = "S820250514103726000009"
    url = "https://vnm-openapi.toppay.asia/gateway/payOut"
    notify_url = "your notify url"

    @staticmethod
    def cash():
        request_params = OrderedDict()
        request_params["merchantCode"] = TopCashDemo.MCH_ID
        request_params["orderType"] = "0"
        request_params["method"] = "DISBURSEMENT"
        request_params["orderNum"] = "T1642592278863"
        request_params["money"] = "10000.00" 
        request_params["feeType"] = "1"
        request_params["bankCode"] = "SCB"
        request_params["bankCard"] = "12312431241"
        request_params["accountName"] = "Jack"
        request_params["extendParam"] = "Test"
        request_params["notifyUrl"] = TopCashDemo.notify_url 
        request_params["dateTime"] = "20220101235959"

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

var MerchantCode = 'S820250514103726000009'
var OrderType = '0'
var OrderNum = 'H202404161637110012'
var Method = 'DISBURSEMENT'
var Money = '100'
var FeeType = '0'
var DateTime = '20220101235959'
var BankCard = '1548425413'
var BankCode = 'SCB'
var AccountName = 'accountName'
var extendParam = 'test'
var NotifyUrl = 'https://xxx'

const data = {
    merchantCode: MerchantCode,
    orderType: OrderType,
    orderNum: OrderNum,
    method: Method,
    money: Money,
    feeType: FeeType,
    dateTime: DateTime,
    bankCard: BankCard,
    bankCode: BankCode,
    accountName: AccountName,
    extendParam: extendParam,
    notifyUrl: NotifyUrl
};

const sortedKeys = Object.keys(data).sort();

let sortedString = '';
sortedKeys.forEach(key => {
    sortedString += data[key];
});

console.log(sortedString);
var sign = encryptWithPrivateKey(sortedString);
data.sign = sign;
const jsonData = JSON.stringify(data);
console.log(jsonData)

var url = 'https://vnm-openapi.toppay.asia/gateway/payOut'

axios.post(url, jsonData,{
  headers: {
    'Content-Type': 'application/json'
  }
})
.then((response) => {
  console.log('Code:', response.status);
  console.log('Msg:', response.data);
})
.catch((error) => {
  console.error('Fail:', error);
});

# Api Address

  • Method : POST
  • Api Address : https://vnm-openapi.toppay.asia/gateway/payOut

# Request Address

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

Params Type Required Desc Ex
merchantCode String Y MchId S820250514103726000009
orderType string(10) Y Order Type The default value is 0
method string(10) Y Method Default transfer DISBURSEMENT
orderNum String Y Merchant order number 10000001
money String Y Payment amount 10000.00(Supports two decimal places)
feeType String Y Fee Type 0: Deducted from the payment amount (actual amount received = order amount - handling fee)
1: Handling fee is calculated separately (actual amount received = order amount)
bankCode String Y Bank Number SCB
Bank Code
bankCard String Y Bank Card 12312431241
accountName String Y Account Name accountName
notifyUrl String Y Notify Url https://123123.com
dateTime String Y yyyyMMddHHmmss 20200101235959
extendParam String Y Transparent parameters (original text return) Test
sign String Y Signature Yg+ePvTFhiRrARcZKBcRG0l8 ...

# Request Example

{
  "merchantCode": "S820250514103726000009",
  "orderType": "0",
  "method": "DISBURSEMENT",
  "orderNum": "T1234567890",
  "money": "10000.00",
  "feeType": "1",
  "bankCode": "SCB",
  "bankCard": "2021071209403321313122",
  "accountName": "test cash accountName",
  "notifyUrl": "your notify url",
  "dateTime": "20220101235959",
  "extendParam": "test cash",
  "sign": "Yg+ePvTFhiRrARcZKBcRG0l89rqisPIuZQStYqBIwSMPaqwH77qRXI1J+jElOBpa"
}

# Response Params

Params Type Required Desc Ex
platRespCode String Y Request Result FAIL\SUCCESS
platRespMessage String Y Message SUCCESS
platOrderNum String Y Platform OrderNum PI1453242857400963072
orderNum String Y Merchant order number 23645782
status Int Y Order Status Cash Order Status
statusMsg String Y Order status information Apply
money String Y Order amount 10000.00
feeType String Y Fee Type 0: Deduction within the order,
1: Handling fee is calculated separately
bankCode String N Bank Code SCB
Bank Code
bankCard String Y Bank Card 12312431241
accountName String Y Account Name accountName
extendParam String Y Transparent parameters (original text return) Test
platSign String Y Platform Signature PI1453242857400963072

# Response Example

{
  "platRespCode": "SUCCESS",
  "platRespMessage": "Request success",
  "platOrderNum": "W0620220119174331000001",
  "orderNum": "T1234567890",
  "status": 0,
  "statusMsg": "Apply",
  "money": "10000.00",
  "feeType": "0",
  "bankCode": "SCB",
  "bankCard": "2021071209403321313122",
  "accountName": "test cash accountName",
  "extendParam": "test cash",
  "platSign": "E5uNF7B9NXyhtlRo2I7/KVHN4Sbz0c3VbwCLpH3vjUpv6Cai+bmJA/Q8dVE2RJRe1+dsbzg=="
}

# Order Notification

  • When verifying the signature, use the platform public key provided in the merchant backend-payment configuration-API configuration for decryption.
  • When verifying the signature, the actual callback parameters shall prevail, and do not verify the fixed parameters
  • The final status of the order shall be based on the status of the notification.
  • After receiving the asynchronous notification, you need to respond to the SUCCESS string, otherwise TopPay will continue to initiate 5 notifications.
  • TopPay Result Asynchronous Notification: Our notification IP address is 35.240.188.94. Please add it to your IP whitelist.

# Notify Params

Params Desc Ex
platOrderNum Platform OrderNum BK_1563278763273
orderNum Merchant order number T1231511321515
money Order Amount 10000.00
feeType Fee Type 0: Deduction within the order,
1: Handling fee is calculated separately
accountName Account Name accountName
bankCard ank Card 45649849659456
bankCode ank Code SCB
Bank Code
status Order Status 2
Cash Order Status
statusMsg Status Desc Payout Success
extendParam Transparent parameters (original text return) Test
platSign Platform Signature ja6R8eukQY9jc8...

# Notify Example

{
  "platOrderNum": "W0620220119174331000001",
  "orderNum": "T1234567890",
  "money": "10000.00",
  "feeType": "0",
  "accountName": "test cash accountName",
  "bankCard": "2021071209403321313122",
  "bankCode": "SCB",
  "status": "2",
  "statusMsg": "SUCCESS",
  "extendParam": "test cash",
  "platSign": "LGEpz2LjbZ6Iyvn+zLc/+t26AaH0aEhHVD62lSCdo6XIkAg86AUncCvmym62wVoE3r2+dHnv27qi/01UQDcqFK8DYioRCcydYSjB4QRVezG3fcZlhWrACmWGacnXkE7p5zChL7pK5h0HuBhbo1zKt4FunQR6QMmcBVfv7YfB3W0"

}