凭证上传

# 代码示例

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

TopPayRequestUtil点击获取代码示例


import com.google.gson.JsonObject;
public class demo {
    
  private static final String PLAT_PUBLIC_KEY = "MIGfMA0GCSqG***AQAB";  // 平台公钥
  private static final String MCH_PRIVATE_KEY = "MIICeAI******IBIuhihgi";  // 商户私钥
  private static final String URL = "https://tl-openapi.toppay.asia/gateway/order/upload";

  public static void main(String[] args) throws Exception {
    query();
  }
  private static void query() throws Exception {
    Map<String, String> requestParams = new TreeMap<>();
    //只有platOrderNum参与签名
    requestParams.put("platOrderNum", "O123123123123123");
    List<String> paramNameList = new ArrayList<>();
    for (String key : maps.keySet()) {
        paramNameList.add(key);
    }
    Collections.sort(paramNameList);
    StringBuilder stringBuilder = new StringBuilder();
    for (String key : paramNameList) {
        stringBuilder.append(requestParams.get(key));  // 拼接参数
    }

    String keyStr = stringBuilder.toString();  // 得到待加密的字符串
    System.out.println("keyStr:" + keyStr);
    String signedStr = TopPayRequestUtil.privateEncrypt(keyStr, TopPayRequestUtil.getPrivateKey(MCH_PRIVATE_KEY));  // 私钥加密
    requestParams.put("sign", signedStr);
    requestParams.put("imgStr", "0000030123012031203120312030120210.00ybTRjhcf"); // qrCode/Data base
    String postJson = new Gson().toJson(requestParams);
    System.out.println("Post Json Params:" + postJson);

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


<?php
    //商户私钥,用工具生成(这里只是测试案例)
    //密钥请检查格式,不要带有空格
    $mchPrivateKey = 'MIICe*******AoUbZT/';
    $imgStr = '0000030123012031203120312030120210.00ybTRjhcf';
    //platOrderNum: 平台订单号
    platOrderNum = 'O123123123123123';
    
    $params = array(
        'platOrderNum' => platOrderNum,
    );

    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['imgStr'] = $imgStr;
    $params_string = json_encode($params);
    $url = 'https://tl-openapi.toppay.asia/gateway/order/upload';
    $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 "message :". $result['message'] . "<br>";
        $thbData = array();
        // 打印满足条件的数据
        print_r($thbData);
    }
    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);
    }
?>

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 demo
    {
        private static readonly string PLAT_PUBLIC_KEY = "MIGfMA0GCSqG******6wIDAQAB";  // 平台公钥
        private static readonly string MCH_PRIVATE_KEY = "MIICdwIBADAN*****qzuBvIGAe3OWNg=";  // 商户私钥
        private static readonly string payUrl = "https://tl-openapi.toppay.asia/gateway/order/upload";
        public static void requestQuery()
        {
            long currenttimemillis = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
            string platOrderNum = platOrderNum;                                            
            string imgStr = "0000030123012031203120312030120210.00ybTRjhcf";                                                  
            Dictionary<string, object> VarPost = new Dictionary<string, object>(); ;
            VarPost.Add("platOrderNum", platOrderNum);
            
            List<string> paramNameList = new List<string>();
            foreach (string key in VarPost.Keys)
            {
                paramNameList.Add(key);
            }
            paramNameList.Sort();// 排序key
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < paramNameList.Count; i++)
            {
                string key = paramNameList[i];
                stringBuilder.Append(VarPost[key]);  // 拼接参数
            }
            string keyStr = stringBuilder.ToString();  // 得到待加密的字符串
            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);
            VarPost.Add("imgStr", imgStr);
            WebClient w = new WebClient();
            w.Headers[HttpRequestHeader.ContentType] = "application/json";
            string jsonStr = JsonNewtonsoft.SerializeDictionaryToJsonString(VarPost);
            Console.WriteLine("postJson:" + jsonStr);     //发送字符串
            string sRemoteInfo = w.UploadString(payUrl, "POST", jsonStr);
        }

    }
}

package main

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

func main() {
	//公私钥(仅用于测试)
	cryptor := NewCryptor()
	cryptor.Pub64 = "MIGfMA0GCSqGSIb3******K4yD37Bj0wIDAQAB"
	cryptor.Pri64 = "MIICdwIBAD*********HKRJwSWWBDEfuk="
	
	url := "https://tl-openapi.toppay.asia/gateway/order/upload"
	imgStr := "000002000000123012030100.00BHhbBNKO"
	//具体查询参数内容
	request := RequestBody{
		platOrderNum: "P123123123123123",
	}
	// 将结构体的字段按JSON标签排序并拼接其值
	sortedValues, err := sortedConcatenatedValues(request)
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		return
	}
	//将排序拼接后的值,使用私钥进行加密,并进行base64编码
	encryptedData := cryptor.PriEncrypt([]byte(sortedValues))
	encodedString := base64.StdEncoding.EncodeToString(encryptedData)
	//将获得签名放入请求结构中
	request.Sign = encodedString
	request.imgStr = imgStr
	jsonBytes, err := json.Marshal(request)
	if err != nil {
		fmt.Printf("Error: %s", err.Error())
		return
	}
	fmt.Println("json2", bytes.NewBuffer(jsonBytes))
	//进行http请求
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBytes))
	if err != nil {
		fmt.Println("Error creating HTTP request:", err)
		return
	}
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Error sending HTTP request:", err)
		return
	}
	defer resp.Body.Close()
	// 读取并打印响应体
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Error reading response body:", err)
		return
	}
	fmt.Println("Response Body:", string(respBody))
}

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

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

class TopQueryDemo:
    # 商户私钥存储地址
    MCH_PRI_KEY_FILE = 'D:\data\company_rsa_private_key.pem'
    # 平台公钥保存地址
    MCH_PUBLIC_KEY_FILE = 'D:\data\plat_rsa_public_key.pem'
    
    # API查询地址
    url = "https://tl-openapi.toppay.asia/gateway/order/upload"

    @staticmethod
    def cash():
        request_params = OrderedDict()
        request_params["platOrderNum"] = "p678987867239412344"

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

        # 加密
        signed_str = TopQueryDemo.private_encrypt(key_str, TopQueryDemo.MCH_PRI_KEY_FILE)
        request_params["sign"] = signed_str
        request_params["imgStr"] = "00002000021320120352345234.00bhihjieh"
        # 发送请求
        post_json = json.dumps(request_params)
        print("Post Json Params:", post_json)

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

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

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


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

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

//请求结构
//具体下单参数内容
var platOrderNum = 'P000000012312312312312'
var imgStr = '0000021012312330534761823478134.91BHYUghi'
const data = {
    platOrderNum: platOrderNum,
};

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

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

console.log(sortedString);
var sign = encryptWithPrivateKey(sortedString);

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

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

# 请求地址

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

# 请求参数

图片大小不能超过 1M —— 图片类型为 jpg | png

参数 必填 参与签名 类型 示例
platOrderNum Y Y 平台订单号 P1287348712634781236478123
imgStr Y N 图片内容(qrCode或者base64),优先上传qrCode qrCode:00000000024123478234834132435.90HGUIbbvs
data:image.....
sign Y Y RSA签名 ja6R8eukQ...

# 请求报文示例

{
  "platOrderNum": "P019208391823491823",
  "imgStr": "00000000024123478234834132435.90HGUIbbvs",
  "sign": "X/o+IQUzLJqYe9Feid9Uww72mJGOvhJSJEIfo1EUChrZyVZnzGHtd61QhOqRmXCtAwk7V7k="
}

# 响应参数

参数 类型 必填 描述 示例
success BOOLEAN Y 接口响应 true/false
code int Y 接口响应码 1000代表成功,其他的都为失败
message String Y 接口响应信息 返回具体响应信息
data Json Y 接口响应参数 以下参数都在data中返回,如失败则为null

# 响应报文示例

{
  "success": true,
  "code": 1000,
  "message": "SUCCESS",
  "data": null
}