一、TopPay API Reference
本文档面向具有开发能力的技术人员 欢迎您联系我们,请在Telegram Messenger 👨💻 Cindy 欢迎咨询.
二、说明
统一请求方式
HTTP POST
ContentType
application/json
签名sign
右侧阴暗区域为签名工具类
import com.google.gson.JsonObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* <p>
* TopPay RSA签名工具类
* </p>
*
* @author TopPay
*/
public class TopPayRequestUtil {
/**
* 验证签名
* @param params
* @return
*/
public static boolean verifySign(JsonObject params, String publickey) throws InvalidKeySpecException, NoSuchAlgorithmException {
String platSign = params.remove("platSign").getAsString(); // 签名
List<String> paramNameList = new ArrayList<>(params.keySet());
Collections.sort(paramNameList);
StringBuilder stringBuilder = new StringBuilder();
for (String name : paramNameList) {
stringBuilder.append(params.get(name).getAsString());
}
System.out.println("keys:" + stringBuilder);
String decryptSign = publicDecrypt(platSign, getPublicKey(publickey));
System.out.println("decryptSign:" + decryptSign);
return stringBuilder.toString().equals(decryptSign);
}
/**
* 私钥加密
* @param data
* @param privateKey
* @return
*/
public static String privateEncrypt(String data, RSAPrivateKey privateKey){
try{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return Base64.encodeBase64String(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes("UTF-8"), privateKey.getModulus().bitLength()));
}catch(Exception e){
throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
}
}
/**
* 公钥解密
* @param data
* @param publicKey
* @return
*/
public static String publicDecrypt(String data, RSAPublicKey publicKey){
try{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()), "UTF-8");
}catch(Exception e){
throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
}
}
/**
* 得到私钥
* @param privateKey 密钥字符串(经过base64编码)
*/
public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
//通过PKCS#8编码的Key指令获得私钥对象
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
return key;
}
/**
* 得到公钥
* @param publicKey 密钥字符串(经过base64编码)
*/
public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
//通过X509编码的Key指令获得公钥对象
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
return key;
}
private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize){
int maxBlock = 0;
if(opmode == Cipher.DECRYPT_MODE){
maxBlock = keySize / 8;
}else{
maxBlock = keySize / 8 - 11;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] buff;
int i = 0;
try{
while(datas.length > offSet){
if(datas.length-offSet > maxBlock){
buff = cipher.doFinal(datas, offSet, maxBlock);
}else{
buff = cipher.doFinal(datas, offSet, datas.length-offSet);
}
out.write(buff, 0, buff.length);
i++;
offSet = i * maxBlock;
}
}catch(Exception e){
throw new RuntimeException("加解密阀值为["+maxBlock+"]的数据时发生异常", e);
}
byte[] resultDatas = out.toByteArray();
IOUtils.closeQuietly(out);
return resultDatas;
}
public static String doPost(String url,String json) throws IOException {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
StringEntity s = new StringEntity(json);
s.setContentEncoding("UTF-8");
s.setContentType("application/json");//发送json数据需要设置contentType
post.setEntity(s);
HttpResponse res = client.execute(post);
if(res.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
return EntityUtils.toString(res.getEntity());// 返回json格式:
}
return null;
}
}
签名统一生成规则:
基于RSA的签名验证方式 将所有非空参数的key按照ASCII排序后,取参数值(不包含Key)进行拼接后 采用RAS算法对字符串计算,算出签名字符串
参数示例值
参数 | 类型 |
---|---|
merchantCode | S820211021094748000001 |
orderNum | T1642592278863 |
payMoney | 150.60 |
notifyUrl | your notify ur |
expiryPeriod | 1440 |
拼接字符串
示例 首先根据参数Key按照ASCII排序,排序后加密字符串 StrA = 2022-01-01 10:55:00test1440S820211021094748000001014JackMayour notify urlT1642593166888150.60082122965511Test Pay
计算签名
使用您在TopPay商户后台配置的密钥对,用您的私钥进行加密计算RSA(StrA)获取到最终的签名字符串 sign = IMLn23c4orM+7pZhHoRmbjrol4X33jeAqFxbZuQ+pnznBIGhb6Ail3qQPmKwcuhNCt536nmldpbWI72 k1lDxd0zZ95ZHElcNzwTFHFKtd8063uy6rFaxaW6DQ47t4U/95dpGfHAZe0GiIFAQ6xQquaoLINyQa4QqL+cpB JFEg1dyW6GYLFSdJnx7ycQvFYllmOpGZmdPLny62GvrCWvkiIARUsmc9fpkpTx5UQEDTgmhwdCKBkhHVsx2AiQ bYDxZ5WBuU1GZeiJjPuzSxvzWP6VoQBsfpwTI5kdJs6aQCekGO2/YScD+tGgrm2J89Pc/axPcb1xZzsi5SxpWh feabQ\u003d\u003d
三、配置商户公钥信息
1.商户后台地址
https://bra-mch.toppay.asia
2.绑定谷歌验证码
登录商户后台->个人中心->安全信息,使用谷歌验证器扫描页面二维码绑定您的账号
3.RSA密钥对生成地址
POST http://pay.hehebo.com:15082/index-rsa.jsp
https://www.bchrt.com/tools/rsa/
http://www.usey.cn/rsa
4.配置公钥
登录商户后台->收付款配置->API配置,填入您的公钥信息并保存.配置完成
5.保存平台公钥
登录商户后台->收付款配置->API配置,将其中展示的平台公钥进行保存,用于验签解密。
四、法币(BRL)代收下单
1.代码示例
代码示例仅供参考,具体参数说明请参考请求参数说明
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 TopPayDemo {
private static final String PLAT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2JoMfFqLsSJjAiCahEnlP3aRj8yCT+WHzR+VvPBTw9S1i7iYWb+MY09CG/HYuHF4+IxshXDJygmndxKf/esuwPybS8mAd//yubHpmZsmBqg1FffT8VH1APa6ZRWASUp4U01ZrbCCp35QA8FuWrJGMJxGx4xk7KUtV2yujxC8noQIDAQAB"; // 平台公钥
private static final String MCH_PRIVATE_KEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAJU8gKFKD0luIYx7X8+JRdCIE0UDBctS6LjXxWLEv/EO7jDBTid6zYP1KmNgpd2DAWWtBFBSQ+gcNwVZZSBHJiSDqVvvJVs2FEbeBvfdv4X93+IYRAXksBasSW5Tpdshbo82pVL4V7wuKCuFLk9UxBHbpQjWAbfyF66RmwIbZD71AgMBAAECgYBjPe7UU2nDDSfmQg0++CyjNjqKRC5QPfxhH6w1uF1kMueXKJWOj42n2RutJpJmsj31nY8m0u4xpsG4HvCu/GGSFhhKZCHLvzp41oY2ubYj9nuFNU//81LycQjulWo2y0UUBY0k2piEt+SwPaiUNbT6nMxNMjlnjRe2okp/3rw+KQJBANG3YlZWoVbCEqzy64bJJLxiPsCA5ErGB0NzRGitq44xkhqGtR8ZZQyVz40pruNa58d73O2xyJSy5+fmZGn4E+sCQQC2LBnguj0CSCKub0mPDcunTTz9V79VXBBZdlB1/YGmRUx2s4sQrJNZS7rL4EqBQ3maIRnG+s+AXCSTfsYrV6CfAkEAxugnVfpelhoGepEAgNuggyivmgfl/2Gpm/jk5l/qOjib+ZrQiQmeBPzGWX4yiSM8eMDrP2sC8r5pJFMp5DRONwJBAJ4n4XuSFJ9jgwCPy3vvzSv9SYLk6E6yM9uHdUlKgoGYzk6Lh6M9QFuY/J49plFdBDiEnj16yCU3WeXXfTJpzB8CQQDMNMR/rIOTE9xGybS3mlQbt22AUnO6XhupWcckEKW4nPGxATwYBQzCY3i/9FTGN0vA+9ZPC2cwHtNxI2kXf3Vp"; // 商户私钥
private static final String payUrl = "https://bra-openapi.toppay.asia/gateway/prepaidOrder";
private static final String cashUrl = "https://bra-openapi.toppay.asia/gateway/cash";
private static final String payNotify = "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", "S820211021094748000001");//商户ID
requestParams.put("orderType", "0"); // 订单类型(0-法币(BRL)交易)
requestParams.put("orderNum", "T1642592278863"); // 商户订单号
requestParams.put("notifyUrl", payNotify);// 回调地址
requestParams.put("description", "PAY"); // 描述
requestParams.put("name", "AAA"); // 用户名
StringBuilder stringBuilder = new StringBuilder();
for (String key : requestParams.keySet()) {
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(payUrl, postJson); // 发送 post json请求
System.out.println("Response Msg:" + responseJson);
}
}
<?php
// 平台公钥,从密钥配置中获取
// platform public key, from Secret key config
$platPublicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiaKBgQCcEUIvQ/5L+SWbHOeR8VFeZvLbUk7V7OeEAQlQwIVLSZMTef3KtsOKKAsUYPf/aAcKRzZZXECODsPQiDPcdZvM/rFkgrFWkR7lPjTj5SiPxGaiK2Z2sne7A8aDF7fV/D7lfmEwNdZ7FWKVEB84/81BHnlGUwb5HpRTISG+boSO6wIDAQAB';
// 商户私钥,商户自己生成(这里只是测试案例)
$mchPrivateKey = 'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMigm7rtWnTeNagwFzGTH+Uw1ypbiy7VhIoFJbgSYSSHdCaXWdT/l2+2fQlEYgAETVZ/IXB29MCnrf3O0dwRFXiipIbsm5zyqSLiS6cKXe8zN1/PlQWUbEt5wyWm0GADB/4bV6eu6gA7sGXmjQqrzfKZkcie3aK7+7ry1NFxTI51AgMBAAECgYEAklqXQAVlt1tiSQ7L3J425jp6u6uMHN4lkYmvuleuBbfKQ1yla3wIPLYjAF+iHeEFidOz0Rb19JRdmIkHDkJoJg2W27LvO6RdUwzgRnsuA3OuNz97w08B3aXXbPmB91nTFjKSlUsbh3IQWP71noxW+iKn844EW5hC5Gvn4L3quAECQQDrz1r0VKIbBSBB2aLuz1XyD/TBT2aRhvOKf0XtTRiQhNjtJxoQmvNbbhvUwj8an7HyCuihAbdbrC2ymFFyOSDZAkEA2c4Yudi48C6COrroi1cWgPlEFeGJXP/V1k5loZ1n2vstYAGPhAB4wUnFBLDvMqaBzWJt7MRkiazT8KnBQCDY/QJAMXpNlEyZwt+deBOpO0BnwSWV7mWxmMFfImU4D+WITPbC7aexsWBBxaJh1o93XCe715RwYTAR//stj3akSDoyaQJAa4FKuxC51/Nc3Fg9R+modeiTLqmv/3NXvPvdNjRXesLX1rduex0wfVdII9ShfEKrdxDKaT9W0NyzD+r6NAkCkQJBAMAnTgPYf0f7rh417GdoP7R7Nwi8KBKwPHlmfRukibOQlKt9xjqpsKJwglLn8pcnXbYbswXIdqzuBvIGAe3OWNg=';
// 商户ID,从商户信息中获取
$merchantCode = 'S820211021094748000001';
//订单类型(0-法币(BRL)交易)
$orderType = '0';
// 商户订单号
$orderNum = 'TEST1231231231';
// 用户名
$name = 'AAA';
// 描述
$description = 'PAY;
// 回调地址
$notifyUrl = 'http://123/callback';
$params = array(
'merchantCode' => $merchantCode,
'orderType' => $orderType,
'orderNum' => $orderNum,
'description' => $description,
'name' => $name,
'notifyUrl' => $notifyUrl,
);
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://bra-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 "description :". $result['description'] . "\n";
echo "url :". $result['url'] . "\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;
}
2.请求地址
我们提供了两种代收下单模式,一种是通过我们的收银台进行获取支付信息,一种是直接请求API获取返回信息,您可以根据自身需求,自行选择。
收银台 :
POST https://bra-openapi.toppay.asia/gateway/prepaidOrder
注:所有的参数中,不要填写中文!!!
3.请求参数
收银台:
参数 | 类型 | 必填 | 描述 | 示例 |
---|---|---|---|---|
merchantCode | string(32) | Y | 商户ID,在商户平台获取 | S820211021094748000001 |
orderType | string(10) | Y | 订单类型 | 0-法币(BRL)交易 |
orderNum | string(32) | Y | 商户订单号 | ASD12312312331 |
payMoney | string(10) | Y | 付款金额(只允许两位小数位) | 20.54 |
name | string(32) | N | 客户名称 | customer name |
description | string(50) | N | 描述 | description |
notifyUrl | string(100) | Y | 订单支付成功异步通知地址(用来接收订单交易成功后的通知) | https://host:port/notifyUrl |
sign | string(255) | Y | 签名 | fnbSOvY83pr8hXg+FdNNYi2ubQUGNv/qGYc4TjRl+XxO2jo92dyjKHFU9/4hNECilMooOcH |
4.请求报文示例
请求参数示例
{
"merchantCode": "S820211021094748000001",
"orderType": "0",
"orderNum": "T1642593166888",
"notifyUrl": "your notify url",
"description": "description",
"sign": "fnbSOvY83pr8hXg+FdNNYi2ubQUGNv/qGYc4TjRl+Xxd1yc9fpkpTx5UQEDTgmhwdCKBkhHVsx2AiQbYDxZ5WBuU1GZeiJ"
}
``
5.响应参数
参数 | 类型 | 必填 | 描述 | 示例 |
---|---|---|---|---|
platRespCode | String | Y | 请求业务是否成功 | FAIL:失败\SUCCESS:成功 |
platRespMessage | String | Y | 接口响应信息提示 | Request Transaction Success |
platOrderNum | String | Y | 平台订单号 | PI1453242857400963072 |
orderNum | String | Y | 商户订单号 | 23645782 |
name | String | N | 客户名称 | customer name |
payMoney | string(10) | N | 付款金额(只允许两位小数位) | 直联模式(模式2),'platRespCode'为SUCCESS时返回 |
url | String | N | 收银台链接 | 请求收银台下单(模式1),'platRespCode'为SUCCESS时返回 |
payData | String | N | 响应参数 | 直联模式(模式2),'platRespCode'为SUCCESS时返回 |
6.成功响应报文示例
下单成功响应报文示例
响应报文示例
{
"platRespCode": "SUCCESS",
"platRespMessage": "Request Transaction Success",
"platOrderNum": "PRE1483771634191044608",
"orderNum": "T1642593166888",
"name": "customer name",
"description": "description",
"url": "https://bra-openapi.toppay.asia/..."
}
失败响应报文示例
{
"platRespCode": "FAIL",
"platRespMessage": "Error message..."
}
7.代收异步通知
进行验签时,要用 商户后台-收付款配置-API配置
中提供的平台公钥
进行解密!!!
进行验签时,要按照实际回调的参数进行验签,不要使用固定参数
接受异步通知后,需响应 SUCCESS
字符串
否则TopPay将继续发起5次通知。
import com.google.gson.JsonObject;
public class TopPayNotify {
// 测试账号
private static final String MCH_CODE = "S820211021094748000001"; // 商户号
private static final String PLAT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2JoMfFqLsSJjAiCahEnlP3aRj8yCT+WHzR+VvPBTw9S1i7iYWb+MY09CG/HYuHF4+IxshXDJygmndxKf/esuwPybS8mAd//yubHpmZsmBqg1FffT8VH1APa6ZRWASUp4U01ZrbCCp35QA8FuWrJGMJxGx4xk7KUtV2yujxC8noQIDAQAB"; // 平台公钥
public static void main(String[] args) throws Exception {
// 代收
JsonObject notifyBody = new jsonObject();
boolean verifyResult = TopPayRequestUtil.verifySign(notifyBody,PLAT_PUBLIC_KEY);
if (verifyResult) {
// ... 签名验证通过,处理正常的业务逻辑
} else {
// ... 签名验证错误
}
}
}
<?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;
}
参数 | 必填 | 描述 | 示例 |
---|---|---|---|
code | Y | 响应状态 | 00 |
msg | Y | 响应信息 | SUCCESS |
method | Y | 支付方式 | PIX |
status | Y | 支付结果 | INIT_ORDER:订单初始化 NO_PAY:未支付 SUCCESS:支付成功 PAY_CANCEL:撤销 PAY_ERROR:支付失败 |
platOrderNum | Y | 平台订单号 | BK_1563278763273 |
orderNum | Y | 商户订单号 | T1231511321515 |
payMoney | Y | 代收金额 | 100.12 |
payFee | Y | 手续费金额 | 5.32 |
name | N | 客户名称 | customer name |
description | N | 描述 | description |
platSign | Y | 平台签名 | ja6R8eukQY9jc8zrhtf34654ungj7u8sdgdfjfs |
8.异步通知报文示例
{
"code": "00",
"msg": "SUCCESS",
"status": "SUCCESS",
"method": "PIX",
"platOrderNum": "PRE1483771634191044608",
"orderNum": "T1642593166888",
"payMoney": "150",
"payFee": "150",
"name": "customer",
"description": "description",
"platSign": "ja6R8eukQY9jc8zrhtf34654ungj7u8sdgdfjfs"
}
五、数字代收下单
代收下单支持法币(BRL)与数字货币(USDT/BTC/ETH/TRX)交易 如果您想使用数字货币交易,请设置orderType=1;
通过商户用户ID来区分不同用户的交易
我们的数字代收订单分两个模式:有单模式和无单模式
Ex: 收银台版本(v1.0和v3.0属于有单模式版本;v2.0和v4.0属于无单模式)
Ex: v1.0、v2.0-只展示支付地址
Ex: v3.0、v4.0-展示二维码和支付地址两种方式
使用数字货币进行交易时,币种和链网络是必传项,您需要告诉我们您想使用何种数字货币和链网络(TRC20/BEP20/OMNI/ERC20/TRX)进行交易 我们后续会推出其他币种和网络的交易,敬请期待
1.代码示例
代码示例仅供参考,具体参数说明请参考请求参数说明
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 TopPayDemo {
// 测试账号
private static final String MCH_CODE = "S820211021094748000001"; // 商户号
private static final String PLAT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2JoMfFqLsSJjAiCahEnlP3aRj8yCT+WHzR+VvPBTw9S1i7iYWb+MY09CG/HYuHF4+IxshXDJygmndxKf/esuwPybS8mAd//yubHpmZsmBqg1FffT8VH1APa6ZRWASUp4U01ZrbCCp35QA8FuWrJGMJxGx4xk7KUtV2yujxC8noQIDAQAB"; // 平台公钥
private static final String MCH_PRIVATE_KEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAJU8gKFKD0luIYx7X8+JRdCIE0UDBctS6LjXxWLEv/EO7jDBTid6zYP1KmNgpd2DAWWtBFBSQ+gcNwVZZSBHJiSDqVvvJVs2FEbeBvfdv4X93+IYRAXksBasSW5Tpdshbo82pVL4V7wuKCuFLk9UxBHbpQjWAbfyF66RmwIbZD71AgMBAAECgYBjPe7UU2nDDSfmQg0++CyjNjqKRC5QPfxhH6w1uF1kMueXKJWOj42n2RutJpJmsj31nY8m0u4xpsG4HvCu/GGSFhhKZCHLvzp41oY2ubYj9nuFNU//81LycQjulWo2y0UUBY0k2piEt+SwPaiUNbT6nMxNMjlnjRe2okp/3rw+KQJBANG3YlZWoVbCEqzy64bJJLxiPsCA5ErGB0NzRGitq44xkhqGtR8ZZQyVz40pruNa58d73O2xyJSy5+fmZGn4E+sCQQC2LBnguj0CSCKub0mPDcunTTz9V79VXBBZdlB1/YGmRUx2s4sQrJNZS7rL4EqBQ3maIRnG+s+AXCSTfsYrV6CfAkEAxugnVfpelhoGepEAgNuggyivmgfl/2Gpm/jk5l/qOjib+ZrQiQmeBPzGWX4yiSM8eMDrP2sC8r5pJFMp5DRONwJBAJ4n4XuSFJ9jgwCPy3vvzSv9SYLk6E6yM9uHdUlKgoGYzk6Lh6M9QFuY/J49plFdBDiEnj16yCU3WeXXfTJpzB8CQQDMNMR/rIOTE9xGybS3mlQbt22AUnO6XhupWcckEKW4nPGxATwYBQzCY3i/9FTGN0vA+9ZPC2cwHtNxI2kXf3Vp"; // 商户私钥
private static final String payUrl = "https://bra-openapi.toppay.asia/gateway/prepaidOrder";
private static final String cashUrl = "https://bra-openapi.toppay.asia/gateway/cash";
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_CODE);
requestParams.put("orderType", "1"); // 订单类型(1-数字货币交易)
requestParams.put("mchUserId", "100001"); // 商户用户ID
requestParams.put("method", "USDT"); // 数字货币类型USDT/BTC/ETH/TRX(可不传)
requestParams.put("orderNum", "T1642592278863"); // 商户订单号(有单模式必传,无单模式不传)
requestParams.put("payMoney", "1.000001"); // 订单金额(最大支持6位小数)
requestParams.put("name", "JackMa");// 客户名称
requestParams.put("notifyUrl", payNotify);// 回调地址
requestParams.put("currency", "USDT"); // 数字货币币种(如果指定了method,则必传)
requestParams.put("netWork", "TRC20"); // 链网络(如果指定了method,则必传)
requestParams.put("orderVersion", "v1.0"); // 收银台版本(v1.0和v3.0属于有单模式版本;v2.0和v4.0属于无单模式)
StringBuilder stringBuilder = new StringBuilder();
for (String key : requestParams.keySet()) {
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(payUrl, postJson); // 发送 post json请求
System.out.println("Response Msg:" + responseJson);
}
}
<?php
// 平台公钥,从密钥配置中获取
// platform public key, from Secret key config
$platPublicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiaKBgQCcEUIvQ/5L+SWbHOeR8VFeZvLbUk7V7OeEAQlQwIVLSZMTef3KtsOKKAsUYPf/aAcKRzZZXECODsPQiDPcdZvM/rFkgrFWkR7lPjTj5SiPxGaiK2Z2sne7A8aDF7fV/D7lfmEwNdZ7FWKVEB84/81BHnlGUwb5HpRTISG+boSO6wIDAQAB';
// 商户私钥,商户自己生成
// mchchant private key
$mchPrivateKey = 'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMigm7rtWnTeNagwFzGTH+Uw1ypbiy7VhIoFJbgSYSSHdCaXWdT/l2+2fQlEYgAETVZ/IXB29MCnrf3O0dwRFXiipIbsm5zyqSLiS6cKXe8zN1/PlQWUbEt5wyWm0GADB/4bV6eu6gA7sGXmjQqrzfKZkcie3aK7+7ry1NFxTI51AgMBAAECgYEAklqXQAVlt1tiSQ7L3J425jp6u6uMHN4lkYmvuleuBbfKQ1yla3wIPLYjAF+iHeEFidOz0Rb19JRdmIkHDkJoJg2W27LvO6RdUwzgRnsuA3OuNz97w08B3aXXbPmB91nTFjKSlUsbh3IQWP71noxW+iKn844EW5hC5Gvn4L3quAECQQDrz1r0VKIbBSBB2aLuz1XyD/TBT2aRhvOKf0XtTRiQhNjtJxoQmvNbbhvUwj8an7HyCuihAbdbrC2ymFFyOSDZAkEA2c4Yudi48C6COrroi1cWgPlEFeGJXP/V1k5loZ1n2vstYAGPhAB4wUnFBLDvMqaBzWJt7MRkiazT8KnBQCDY/QJAMXpNlEyZwt+deBOpO0BnwSWV7mWxmMFfImU4D+WITPbC7aexsWBBxaJh1o93XCe715RwYTAR//stj3akSDoyaQJAa4FKuxC51/Nc3Fg9R+modeiTLqmv/3NXvPvdNjRXesLX1rduex0wfVdII9ShfEKrdxDKaT9W0NyzD+r6NAkCkQJBAMAnTgPYf0f7rh417GdoP7R7Nwi8KBKwPHlmfRukibOQlKt9xjqpsKJwglLn8pcnXbYbswXIdqzuBvIGAe3OWNg=';
// 商户ID,从商户信息中获取
// merchent ID from idntask, from User info
$merchantCode = 'YOUR_MERCHANT_CODE_HERE';
// 商户用户ID
$mchUserId = 'YOUR_MERCHANT_USDR_ID';
// 支付金额 pay money(最大支持6位小数)
$payMoney = '1.000001';
// 支付方式 参考: (USDT/BTC/ETH/TRX)
$method = 'USDT';
//订单类型(1-数字货币交易)
$orderType = '1';
// 商户订单号
$orderNum = 'T'.date("YmdHis",time());
// 在付款确认页面显示的转账对象
// Display name on bank confirmation display
$name = 'Neo';
// 回调地址
// url for callback
$notifyUrl = 'http://example.com/callback';
// 订单过期时间 Order expiration time
// 数字货币币种(如果指定了method,则必传)
$currency = 'USDT';
// 链网络(如果指定了method,则必传)
$netWork = 'TRC20';
// 收银台版本(v1.0和v3.0属于有单模式版本;v2.0和v4.0属于无单模式)
$orderVersion = 'v1.0';
$params = array(
'merchantCode' => $merchantCode,
'orderType' => $orderType,
'mchUserId' => $mchUserId,
'method' => $method,
'orderNum' => $orderNum,
'payMoney' => $payMoney,
'name' => $name,
'notifyUrl' => $notifyUrl,
'currency' => $currency,
'netWork' => $netWork,
'orderVersion' => $orderVersion
);
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://bra-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 "mchUserId :". $result['mchUserId'] . "\n";
echo "platOrderNum :". $result['platOrderNum'] . "\n";
echo "orderNum :". $result['orderNum'] . "\n";
echo "method :". $result['method'] . "\n";
echo "name :". $result['name'] . "\n";
echo "url :". $result['url'] . "\n";
echo "payMoney :". $result['payMoney'] . "\n";
echo "currency :". $result['currency'] . "\n";
echo "netWork :". $result['netWork'] . "\n";
echo "orderVersion :". $result['orderVersion'] . "\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;
}
2.请求地址
POST https://bra-openapi.toppay.asia/gateway/prepaidOrder
注:所有的参数中,不要填写中文!!!
3.数字代收请求参数
参数 | 类型 | 必填 | 描述 | 示例 |
---|---|---|---|---|
merchantCode | string(32) | Y | 商户ID,在商户平台获取 | S820211021094748000001 |
orderType | string(10) | Y | 订单类型 | 1-数字货币交易 |
mchUserId | string(32) | Y | 商户用户ID(您的用户唯一标识,请勿传特殊字符、空格等) | 100001 |
method | string(10) | N | 支付方式(如果需要指定支付方式,可以在右侧的示例支付方式列表中选择其一;如果不指定支付方式,则可不传该参数,可以在我们的收银台页面中选择某个支付方式。) | USDT BTC ETH TRX (备注:数字货币对应的支付方式) |
currency | string(14) | N | 数字货币币种(如果指定支付方式,则必传) | USDT |
netWork | string(30) | N | 链网络(如果指定支付方式,则必传) | TRC20 |
orderNum | string(32) | N | 商户订单号(有单模式必传,无单模式不传) | TEST123456789 |
payMoney | int(10) | Y | 付款金额(最大允许6位小数) | 1.000001 |
notifyUrl | string(100) | Y | 订单支付成功异步通知地址(用来接收订单交易成功后的通知) | https://host:port/notifyUrl |
name | string(16) | Y | 客户名称 | Jack |
orderVersion | string(10) | N | 收银台模式必传 API模式不传 收银台版本(v1.0和v3.0属于有单模式版本;v2.0和v4.0属于无单模式) |
v1.0 |
sign | string(255) | Y | 签名 | fnbSOvY83pr8hXg+FdNNYi2ubQUGNv/qGYc4TjRl+XxO2jo92dyjKHFU9/4hNECilMooOcH |
4.请求报文示例
{
"merchantCode": "S820211021094748000001",
"mchUserId": "100001",
"orderType": "1",
"method": "USDT",
"currency": "USDT",
"netWork": "TRC20",
"orderNum": "T1642593166888",
"payMoney": "1.000001",
"notifyUrl": "your notify url",
"name": "JackMa",
"sign": "fnbSOvY83pr8hXg+FdNNYi2ubQUGNv/qGYc4TjRl+Xxd1yc9fpkpTx5UQEDTgmhwdCKBkhHVsx2AiQbYDxZ5WBuU1GZeiJ"
}
5.响应参数
参数 | 类型 | 必填 | 描述 | 示例 |
---|---|---|---|---|
platRespCode | String | Y | 请求业务是否成功 | FAIL:失败\SUCCESS:成功 |
platRespMessage | String | Y | 接口响应信息提示 | Request Transaction Success |
mchUserId | String | Y | 商户用户ID(唯一标识) | 10001 |
platOrderNum | String | Y | 平台订单号 | PI1453242857400963072 |
orderNum | String | Y | 商户订单号 | 23645782 |
currency | String | Y | 币种 | USDT |
netWork | String | Y | 链网络 | TRC20 |
payMoney | string | Y | 支付金额 | 1.000001 |
url | String | Y | 支付连接 | 'platRespCode'为'SUCCESS'时返回 |
6.成功响应报文示例
{
"platRespCode": "SUCCESS",
"url": "https://id-openapi.toppay.asia/cashier?orderNum=PRE1626161123977859130123",
"mchUserId": "10001",
"platOrderNum": "PRE1626161123977859130",
"payMoney": "1.000001",
"currency": "USDT",
"netWork": "TRC20",
"platSign": "U79dat+VITTQ8xAI1wsxtFlK2DwcVvZ6ypC+QFIDaEy4oNxZECRy+INAcqIWZHL1m6/pge1SOEbVss8ZZPsZbtRZiefhtH+6qyu99MU+1rGdu+oSXSNhP4+2aDucg/SylS3+TkjKJf+IowTX7d2TJEbDh011JLOc9zglkhqVEc0FVIbBmKInZ/+TaLhDfFt6Sqmf85GCP7V5JwW1arIUwUjlGkCs3TtvHfpDVaMi2fl+cfNGYSrCOZfursVwjiwJmka+44FyaGrrEOE9tKwODiZo/jg9FLZnp2eRZwIIwef8CFg7eqx13uo/y61g0D9pzH17IVcr7Mc8BrweO7X4Pw==",
"platRespMessage": "Request Transaction Success"
}
失败响应报文示例
{
"platRespCode": "FAIL",
"platRespMessage": "the orderNum already exists"
}
7.数字代收异步通知
请注意:当前业务只有在订单支付成功的时候才有回调通知接收到。
数字货币有两种特殊情况:无单模式以及支付金额与下单金额不符,为此我们将异步通知进行了调整,如下:
1.如果是上述特殊情况,我们会生成一笔新的成功订单进行通知,您需要根据通知的信息进行验证,并生成新的订单;
2.根据通知的商户订单号(orderNum)查询是否您的系统存在该订单,建议您在下单成功时同时存储我们的平台订单号(platOrderNum),做双步校验;
3.根据通知的参数specialStatus(0-默认,1-特殊状态)判断,如果为1则判断为上述特殊情况.
TopPay结果异步通知后,需响应 SUCCESS
字符串,不包含引号,不是Json格式。
否则TopPay将继续向下游发起5次通知。
import com.google.gson.JsonObject;
public class TopPayNotify {
// 测试账号
private static final String MCH_CODE = "S820211021094748000001"; // 商户号
private static final String PLAT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2JoMfFqLsSJjAiCahEnlP3aRj8yCT+WHzR+VvPBTw9S1i7iYWb+MY09CG/HYuHF4+IxshXDJygmndxKf/esuwPybS8mAd//yubHpmZsmBqg1FffT8VH1APa6ZRWASUp4U01ZrbCCp35QA8FuWrJGMJxGx4xk7KUtV2yujxC8noQIDAQAB"; // 平台公钥
public static void main(String[] args) throws Exception {
// 代收
JsonObject notifyBody = new jsonObject();
boolean verifyResult = TopPayRequestUtil.verifySign(notifyBody,PLAT_PUBLIC_KEY);
if (verifyResult) {
// ... 签名验证通过,处理正常的业务逻辑
} else {
// ... 签名验证错误
}
}
}
<?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;
}
参数 | 描述 | 示例 |
---|---|---|
code | 响应状态 | 00 |
msg | 响应信息 | SUCCESS |
mchUserId | 商户用户ID(唯一标识) | 10001 |
platOrderNum | 平台订单号 | BK_1563278763273 |
orderNum | 商户订单号 | T1231511321515 |
method | 支付方式 | USDT |
currency | 币种 | USDT |
netWork | 链网络 | TRC20 |
status | 支付结果 | INIT_ORDER: 订单初始化 NO_PAY: 未支付 SUCCESS: 支付成功 PAY_CANCEL: 撤销 PAY_ERROR: 支付失败 |
payMoney | 代收金额 | 100000 |
payFee | 手续费 | 500 |
hashCode | 交易哈希 | 5e5c356af0ewrhgnf3d757h8a6a5506cc66354620 |
sendAddress | 发送地址 | TDBbbeAB32WE576DVGE82GEC5BhsZs4 |
specialStatus | 特殊状态(0-默认,1-特殊状态) | 0 |
platSign | 平台签名 | ja6R8eukQY9jc8z |
8.异步通知报文示例
{
"code": "00",
"msg": "SUCCESS",
"mchUserId": "100001",
"platOrderNum": "PRE1483771634191044608",
"orderNum": "T1642593166888",
"method": "USDT",
"currency": "USDT",
"netWork": "TRC20",
"status": "SUCCESS",
"payMoney": "1.0000001",
"payFee": "0.000016",
"hashCode": "5e5c356af0ewrhgnf3d757h8a6a5506cc66354620",
"sendAddress": "TDBbbeAB32WE576DVGE82GEC5BhsZs4",
"specialStatus": "0",
"platSign": "ja6R8eukQY9jc8zrhtf34654ungj7u8sdgdfjfs"
}
六、法币(BRL)代付下单
1.代码示例
代码示例仅供参考,具体参数说明请参考请求参数说明
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.util.Map;
import java.util.TreeMap;
public class TopPayDemo {
private static final String PLAT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2JoMfFqLsSJjAiCahEnlP3aRj8yCT+WHzR+VvPBTw9S1i7iYWb+MY09CG/HYuHF4+IxshXDJygmndxKf/esuwPybS8mAd//yubHpmZsmBqg1FffT8VH1APa6ZRWASUp4U01ZrbCCp35QA8FuWrJGMJxGx4xk7KUtV2yujxC8noQIDAQAB"; // 平台公钥
private static final String MCH_PRIVATE_KEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAJU8gKFKD0luIYx7X8+JRdCIE0UDBctS6LjXxWLEv/EO7jDBTid6zYP1KmNgpd2DAWWtBFBSQ+gcNwVZZSBHJiSDqVvvJVs2FEbeBvfdv4X93+IYRAXksBasSW5Tpdshbo82pVL4V7wuKCuFLk9UxBHbpQjWAbfyF66RmwIbZD71AgMBAAECgYBjPe7UU2nDDSfmQg0++CyjNjqKRC5QPfxhH6w1uF1kMueXKJWOj42n2RutJpJmsj31nY8m0u4xpsG4HvCu/GGSFhhKZCHLvzp41oY2ubYj9nuFNU//81LycQjulWo2y0UUBY0k2piEt+SwPaiUNbT6nMxNMjlnjRe2okp/3rw+KQJBANG3YlZWoVbCEqzy64bJJLxiPsCA5ErGB0NzRGitq44xkhqGtR8ZZQyVz40pruNa58d73O2xyJSy5+fmZGn4E+sCQQC2LBnguj0CSCKub0mPDcunTTz9V79VXBBZdlB1/YGmRUx2s4sQrJNZS7rL4EqBQ3maIRnG+s+AXCSTfsYrV6CfAkEAxugnVfpelhoGepEAgNuggyivmgfl/2Gpm/jk5l/qOjib+ZrQiQmeBPzGWX4yiSM8eMDrP2sC8r5pJFMp5DRONwJBAJ4n4XuSFJ9jgwCPy3vvzSv9SYLk6E6yM9uHdUlKgoGYzk6Lh6M9QFuY/J49plFdBDiEnj16yCU3WeXXfTJpzB8CQQDMNMR/rIOTE9xGybS3mlQbt22AUnO6XhupWcckEKW4nPGxATwYBQzCY3i/9FTGN0vA+9ZPC2cwHtNxI2kXf3Vp"; // 商户私钥
private static final String cashUrl = "https://bra-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", "S820211021094748000001");// 商户ID
requestParams.put("orderNum", "186888188666"); // 商户订单号
requestParams.put("method", "DISBURSEMENT"); // 收款方式(默认传DISBURSEMENT)
requestParams.put("orderType", "0"); // 订单类型(0-法币(BRL)交易)
requestParams.put("money", "125.12"); // 订单金额,支持两位小数位
requestParams.put("feeType", "0"); // 手续费类型(0-帐内扣除,1-帐外扣除)
requestParams.put("pixType", "CPF"); // PIX类型
requestParams.put("pixAccount", "123123123"); // PIX账号
requestParams.put("taxNumber", "123123123"); // 税号
requestParams.put("name", "custmener"); // 客户名称
requestParams.put("description", "description"); // 描述
requestParams.put("notifyUrl", cashNotify); // 回调地址
StringBuilder stringBuilder = new StringBuilder();
for (String key : requestParams.keySet()) {
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); // 发送 post json请求
System.out.println("Response Msg:" + responseJson);
boolean pass = TopPayRequestUtil.verifySign(new Gson().fromJson(responseJson, JsonObject.class), PLAT_PUBLIC_KEY); // 签名验证
if (pass) {
// ... 签名验证通过,执行正常的业务逻辑
} else {
// ... 签名验证错误
}
}
}
<?php
// 平台公钥,从密钥配置中获取
// platform public key, from Secret key config
$platPublicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiaKBgQCcEUIvQ/5L+SWbHOeR8VFeZvLbUk7V7OeEAQlQwIVLSZMTef3KtsOKKAsUYPf/aAcKRzZZXECODsPQiDPcdZvM/rFkgrFWkR7lPjTj5SiPxGaiK2Z2sne7A8aDF7fV/D7lfmEwNdZ7FWKVEB84/81BHnlGUwb5HpRTISG+boSO6wIDAQAB';
// 商户私钥,商户自己生成
// mchchant private key
$mchPrivateKey = 'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMigm7rtWnTeNagwFzGTH+Uw1ypbiy7VhIoFJbgSYSSHdCaXWdT/l2+2fQlEYgAETVZ/IXB29MCnrf3O0dwRFXiipIbsm5zyqSLiS6cKXe8zN1/PlQWUbEt5wyWm0GADB/4bV6eu6gA7sGXmjQqrzfKZkcie3aK7+7ry1NFxTI51AgMBAAECgYEAklqXQAVlt1tiSQ7L3J425jp6u6uMHN4lkYmvuleuBbfKQ1yla3wIPLYjAF+iHeEFidOz0Rb19JRdmIkHDkJoJg2W27LvO6RdUwzgRnsuA3OuNz97w08B3aXXbPmB91nTFjKSlUsbh3IQWP71noxW+iKn844EW5hC5Gvn4L3quAECQQDrz1r0VKIbBSBB2aLuz1XyD/TBT2aRhvOKf0XtTRiQhNjtJxoQmvNbbhvUwj8an7HyCuihAbdbrC2ymFFyOSDZAkEA2c4Yudi48C6COrroi1cWgPlEFeGJXP/V1k5loZ1n2vstYAGPhAB4wUnFBLDvMqaBzWJt7MRkiazT8KnBQCDY/QJAMXpNlEyZwt+deBOpO0BnwSWV7mWxmMFfImU4D+WITPbC7aexsWBBxaJh1o93XCe715RwYTAR//stj3akSDoyaQJAa4FKuxC51/Nc3Fg9R+modeiTLqmv/3NXvPvdNjRXesLX1rduex0wfVdII9ShfEKrdxDKaT9W0NyzD+r6NAkCkQJBAMAnTgPYf0f7rh417GdoP7R7Nwi8KBKwPHlmfRukibOQlKt9xjqpsKJwglLn8pcnXbYbswXIdqzuBvIGAe3OWNg=';
// 商户ID,从商户信息中获取
// merchent ID from idntask, from User info
$merchantCode = 'YOUR_MERCHANT_CODE_HERE';
// 商户订单号
$orderNum = 'T'.date("YmdHis",time());
// 支付方式
// Payment method
$method = 'DISBURSEMENT';
//订单类型(0-法币(BRL)交易)
$orderType = '0';
// 出款金额 withdraw money
$money = '20000';
// 手续费类型(0-帐内扣除,1-帐外扣除)
$feeType = '1';
// PIX类型
$pixType = 'CPF';
// PIX账号
$pixAccount = '123123123123';
// 税号
$taxNumber = '45324532434';
// 描述
$description = 'description';
// 回调地址
// url for callback
$notifyUrl = 'http://example.com/callback';
$params = array(
'merchantCode' => $merchantCode,
'orderType' => $orderType,
'method' => $method,
'orderNum' => $orderNum,
'money' => $money,
'feeType' => $feeType,
'name' => $name,
'pixType' => $pixType,
'pixAccount' => $pixAccount,
'taxNumber' => $taxNumber,
'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;
$params['name'] = $name;
$params['description'] = $description;
$params_string = json_encode($params);
$url = 'https://bra-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 "status :". $result['status'] . "\n";
echo "statusMsg :". $result['statusMsg'] . "\n";
echo "money :". $result['money'] . "\n";
echo "feeType :". $result['feeType'] . "\n";
echo "name :". $result['name'] . "\n";
echo "pixType :". $result['pixType'] . "\n";
echo "pixAccount :". $result['pixAccount'] . "\n";
echo "taxNumber :". $result['taxNumber'] . "\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;
}
2.请求地址
POST https://bra-openapi.toppay.asia/gateway/cash
3.请求参数
参数 | 类型 | 必填 | 描述 | 示例 |
---|---|---|---|---|
merchantCode | string | Y | 商户ID,在商户平台获取 | S820211021094748000001 |
orderType | string(10) | Y | 订单类型 | 0-法币(BRL)交易 |
method | string(10) | Y | 收款方式 | 默认传DISBURSEMENT |
orderNum | string | Y | 商户订单号 | 10000001 |
money | string | Y | 代付金额 | 150.12(支持两位小数点位) |
feeType | String | Y | 手续费类型 | 0:代付金额内扣除,1:手续费另计 |
name | String | Y | 客户名称(真实姓名,增加成功率) | Jack |
pixType | string | Y | PIX类型 | CPF(11位数字) CNPJ(14位数字) PHONE(+55开头,号码10-11位) EMAIL(邮箱格式) EVP |
pixAccount | string | Y | PIX账号 | 以pixType为准,传递对应的账号即可;pixType为CPF,则pixAccount传CPF;pixType为PHONE,则pixAccount传PHONE;以此类推... |
taxNumber | string | Y | 税号 | CPF/CNPJ税号 |
notifyUrl | string | Y | 回调地址 | https://123123.com |
description | string | N | 按请求参数返回 | description |
sign | string | Y | 签名 | Yg+ePvTFhiRrARcZKBcRG0l89rqisPIuZQStYqBIwSMPaqvqbc3dFevgS9jt |
4.请求报文示例
{
"merchantCode": "S820211021094748000001",
"orderType": "0",
"method": "DISBURSEMENT",
"orderNum": "186888188666",
"money": "100",
"feeType": "1",
"name": "test cash name",
"pixType": "CPF",
"pixAccount": "123456789",
"taxNumber": "123456789",
"notifyUrl": "your notify url",
"description": "test cash",
"sign": "Yg+ePvTFhiRrARcZKBcRG0l89rqisPIuZQStYqBIwSMPaqwH77qRXI1J+jElOBpa"
}
5.响应参数
参数 | 类型 | 必填 | 描述 | 示例 |
---|---|---|---|---|
platRespCode | String | Y | 请求业务是否成功 | FAIL:失败\SUCCESS:成功 |
platRespMessage | String | Y | 接口响应信息提示 | 请求成功 |
platOrderNum | String | Y | 平台订单号 | PI1453242857400963072 |
orderNum | String | Y | 商户订单号 | 23645782 |
status | int | Y | 订单状态 | 0-待处理 1-处理中 2-代付成功 4-代付失败 5-银行代付中 |
statusMsg | String | Y | 订单状态信息 | Apply |
money | string | Y | 代付金额 | 150000 |
feeType | String | Y | 手续费类型 | 0:订单内扣除,1:手续费另计 |
fee | String | Y | 手续费 | 500 |
name | String | Y | 客户名称 | Jack |
pixType | string | Y | PIX类型 | CPF(11位数字) CNPJ(14位数字) PHONE(+55开头,号码10-11位) EMAIL(邮箱格式) EVP |
pixAccount | string | Y | PIX账号 | 以pixType为准,传递对应的账号即可;pixType为CPF,则pixAccount传CPF;pixType为PHONE,则pixAccount传PHONE;以此类推... |
taxNumber | string | Y | 税号 | CPF/CNPJ税号 |
description | String | Y | 按请求参数返回 | 代付下单 |
platSign | String | Y | 签名 | PI1453242857400963072 |
6.代付响应报文示例
{
"platRespCode": "SUCCESS",
"platRespMessage": "Request success",
"platOrderNum": "W0620220119174331000001",
"orderNum": "186888188666",
"status": 0,
"statusMsg": "Apply",
"money": "50000",
"feeType": "0",
"fee": "1",
"name": "test cash name",
"pixType": "CPF",
"pixAccount": "123456",
"taxNumber": "123456",
"description": "test cash",
"platSign": "E5uNF7B9NXyhtlRo2I7/KVHN4Sbz0c3VbwCLpH3vjUpv6Cai+bmJA/Q8dVE2RJRe1+dsbzg=="
}
7.代付异步通知
进行验签时,要用 商户后台-收付款配置-API配置
中提供的平台公钥
进行解密!!!
TopPay结果异步通知后,需响应 SUCCESS
字符串.
否则TopPay将继续向下游发起5次通知。
参数 | 描述 | 示例 |
---|---|---|
platOrderNum | 平台订单号 | BK_1563278763273 |
orderNum | 商户订单号 | T1231511321515 |
money | 代付金额 | 150.12(支持小数点) |
feeType | 手续费类型 | 0:代付金额内扣除,1:手续费另计 |
fee | 手续费 | 500 |
name | 客户名称 | Neo |
pixType | PIX类型 | CPF(11位数字) CNPJ(14位数字) PHONE(+55开头,号码10-11位) EMAIL(邮箱格式) EVP |
pixAccount | PIX账号 | 以pixType为准,传递对应的账号即可;pixType为CPF,则pixAccount传CPF;pixType为PHONE,则pixAccount传PHONE;以此类推... |
taxNumber | 税号 | CPF/CNPJ税号 |
status | 订单状态 | 0-待处理 1-处理中 2-代付成功 4-代付失败 5-银行代付中 |
statusMsg | 订单状态描述 | Payout Success |
description | 订单描述 | 商户上传原样返回 |
platSign | 平台签名 | ja6R8eukQY9jc8... |
8.异步通知报文示例
{
"platOrderNum": "W0620220119174331000001",
"orderNum": "186888188666",
"money": "50000",
"feeType": "0",
"fee": "7",
"name": "test cash name",
"pixType": "CPF",
"pixAccount": "123456",
"taxNumber": "123456",
"status": "2",
"statusMsg": "SUCCESS",
"description": "test cash",
"platSign": "LGEpz2LjbZ6Iyvn+zLc/+t26AaH0aEhHVD62lSCdo6XIkAg86AUncCvmym62wVoE3r2+dHnv27qi/01UQDcqFK8DYioRCcydYSjB4QRVezG3fcZlhWrACmWGacnXkE7p5zChL7pK5h0HuBhbo1zKt4FunQR6QMmcBVfv7YfB3W0"
}
七、数字代付下单
代付下单支持法币(BRL)与数字货币(USDT/BTC/ETH/TRX)交易 如果您想使用数字货币交易,请设置orderType=1,并传入对应的货币币种Currency和网络netWork 使用数字货币进行交易时,币种和链网络是必传项 您需要告诉我们您想使用何种数字币和链网络(TRC20/BEP20/OMNI/ERC20/TRX)进行交易 当使用数字货币进行交易时,您需要传入您的inAddress用以收取数字货币 我们后续会推出其他币种和网络的交易,敬请期待
1.代码示例
代码示例仅供参考,具体参数说明请参考请求参数说明
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.util.Map;
import java.util.TreeMap;
public class TopPayDemo {
private static final String MCH_CODE = "S820211021094748000001"; // 商户号
private static final String PLAT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2JoMfFqLsSJjAiCahEnlP3aRj8yCT+WHzR+VvPBTw9S1i7iYWb+MY09CG/HYuHF4+IxshXDJygmndxKf/esuwPybS8mAd//yubHpmZsmBqg1FffT8VH1APa6ZRWASUp4U01ZrbCCp35QA8FuWrJGMJxGx4xk7KUtV2yujxC8noQIDAQAB"; // 平台公钥
private static final String MCH_PRIVATE_KEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAJU8gKFKD0luIYx7X8+JRdCIE0UDBctS6LjXxWLEv/EO7jDBTid6zYP1KmNgpd2DAWWtBFBSQ+gcNwVZZSBHJiSDqVvvJVs2FEbeBvfdv4X93+IYRAXksBasSW5Tpdshbo82pVL4V7wuKCuFLk9UxBHbpQjWAbfyF66RmwIbZD71AgMBAAECgYBjPe7UU2nDDSfmQg0++CyjNjqKRC5QPfxhH6w1uF1kMueXKJWOj42n2RutJpJmsj31nY8m0u4xpsG4HvCu/GGSFhhKZCHLvzp41oY2ubYj9nuFNU//81LycQjulWo2y0UUBY0k2piEt+SwPaiUNbT6nMxNMjlnjRe2okp/3rw+KQJBANG3YlZWoVbCEqzy64bJJLxiPsCA5ErGB0NzRGitq44xkhqGtR8ZZQyVz40pruNa58d73O2xyJSy5+fmZGn4E+sCQQC2LBnguj0CSCKub0mPDcunTTz9V79VXBBZdlB1/YGmRUx2s4sQrJNZS7rL4EqBQ3maIRnG+s+AXCSTfsYrV6CfAkEAxugnVfpelhoGepEAgNuggyivmgfl/2Gpm/jk5l/qOjib+ZrQiQmeBPzGWX4yiSM8eMDrP2sC8r5pJFMp5DRONwJBAJ4n4XuSFJ9jgwCPy3vvzSv9SYLk6E6yM9uHdUlKgoGYzk6Lh6M9QFuY/J49plFdBDiEnj16yCU3WeXXfTJpzB8CQQDMNMR/rIOTE9xGybS3mlQbt22AUnO6XhupWcckEKW4nPGxATwYBQzCY3i/9FTGN0vA+9ZPC2cwHtNxI2kXf3Vp"; // 商户私钥
private static final String cashUrl = "https://bra-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_CODE);
requestParams.put("orderNum", "186888188666"); // 商户订单号
requestParams.put("method", "USDT"); // 收款方式(USDT/BTC/ETH/TRX)
requestParams.put("orderType", "1"); // 订单类型(1-数字货币交易)
requestParams.put("money", "1.000001"); // 订单金额,最大支持6位小数
requestParams.put("feeType", "1"); // 手续费类型(0:代付金额内扣除,1:手续费另计)
requestParams.put("name", "test cash name"); // 客户名称
requestParams.put("description", "test cash"); // 描述
requestParams.put("notifyUrl", cashNotify); // 回调地址
requestParams.put("currency", "USDT"); // 数字货币币种(当orderType=1(数字货币交易)时,是必填项,否则会无法完成交易)
requestParams.put("netWork", "TRC20"); // 链网络(当orderType=1(数字货币交易)时,是必填项,否则无法完成交易)
requestParams.put("inAddress", "zkif74bhvkf8934rgg6"); // 入账地址(当orderType=1(数字货币交易)时,是必填项,否则无法完成交易)
StringBuilder stringBuilder = new StringBuilder();
for (String key : requestParams.keySet()) {
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); // 发送 post json请求
System.out.println("Response Msg:" + responseJson);
boolean pass = TopPayRequestUtil.verifySign(new Gson().fromJson(responseJson, JsonObject.class), PLAT_PUBLIC_KEY); // 签名验证
if (pass) {
// ... 签名验证通过,执行正常的业务逻辑
} else {
// ... 签名验证错误
}
}
}
2.请求地址
POST https://bra-openapi.toppay.asia/gateway/cash
注:所有的参数中,不要填写中文!!!
3.请求参数
参数 | 类型 | 必填 | 描述 | 示例 |
---|---|---|---|---|
merchantCode | string | Y | 商户ID,在商户平台获取 | S820211021094748000001 |
orderType | string(10) | Y | 订单类型 | 1-数字货币交易 |
method | string(10) | Y | 收款方式 | USDT BTC ETH TRX |
orderNum | string | Y | 商户订单号 | 186888188666 |
money | string | Y | 代付金额 | 1.000001(最大支持6位小数)如果feeType选择0的话,因为涉及到手续费,所以麻烦您先以3位小数的金额进行代付下单 |
feeType | String | Y | 手续费类型 | 0:代付金额内扣除 1:手续费另计 |
name | String | Y | 客户名称 | Jack |
notifyUrl | string | Y | 回调地址 | 1234567890 |
currency | string(14) | Y | 数字货币币种 | USDT |
netWork | string(30) | Y | 链网络 | TRC20 |
inAddress | string | Y | 入账地址 | vboj3457vbiae5y35y |
4.请求报文示例
{
"merchantCode": "S820211021094748000001",
"orderType": "1",
"method": "USDT",
"orderNum": "186888188666",
"money": "1.00000001",
"feeType": "1",
"name": "test cash name",
"notifyUrl": "your notify url",
"currency": "USDT",
"netWork": "TRC20",
"inAddress": "vboj3457vbiae5y35y",
"sign": "Yg+ePvTFhiRrARcZKBcRG0l89rqisPIuZQStYqBIwSMPaqwH77qRXI1J+jElOBpa"
}
5.响应参数
参数 | 类型 | 描述 | 示例 |
---|---|---|---|
platRespCode | String | 请求业务是否成功 | FAIL:失败\SUCCESS:成功 |
platRespMessage | String | 接口响应信息提示 | 请求成功 |
platOrderNum | String | 平台订单号 | PI1453242857400963072 |
status | String | 订单状态 | 0 |
statusMsg | String | 订单状态信息 | Apply |
orderNum | String | 商户订单号 | 23645782 |
money | string | 代付金额 | 1.00000001 |
feeType | String | 手续费类型 | 0:代付金额内扣除 1:手续费另计 |
name | String | 客户名称 | Jack |
currency | string | 数字货币币种 | USDT |
netWork | string | 链网络 | TRC20 |
platSign | String | 签名 | PI1453242857400963072 |
6.响应报文示例
{
"platRespCode": "SUCCESS",
"platRespMessage": "Request success",
"platOrderNum": "W0620220119174331000001",
"orderNum": "186888188666",
"status": "0",
"statusMsg": "Apply",
"money": "50000",
"feeType": "1",
"currency": "USDT",
"netWork": "TRC20",
"platSign": "E5uNF7B9NXyhtlRo2I7/KVHN4Sbz0c3VbwCLpH3vjUpv6Cai+bmJA/Q8dVE2RJRe1+dsbzg=="
}
7.数字代付异步通知
接收到结果异步通知后,需响应 SUCCESS
字符串,不包含引号,不是Json格式。
否则TopPay将继续向下游发起5次通知。
参数 | 描述 | 示例 |
---|---|---|
platOrderNum | 平台订单号 | BK_1563278763273 |
orderNum | 商户订单号 | T1231511321515 |
money | 代付金额 | 1.000001(最大支持6位小数) |
feeType | 订单结果状态 | 手续费类型, 0:代付金额内扣除,1:手续费另计 |
fee | 手续费 | 500 |
name | 客户名称 | Neo |
status | 订单状态 | 0-待处理 1-处理中 2-代付成功 4-代付失败 5-银行代付中 |
statusMsg | 订单状态描述 | Payout Success |
hashCode | 交易哈希 | 5e5c356af0ewrhgnf3d757h8a6a5506cc66354620 |
inAddress | 接收地址 | TDBbbeAB32WE576DVGE82GEC5BhsZs4 |
sendAddress | 发送地址 | TDBbbeAB32WE576DVGE82GEC5BhsZs4 |
platSign | 平台签名 | ja6R8eukQY9jc8... |
8.异步通知报文示例
{
"platOrderNum": "W0620220119174331000001",
"orderNum": "186888188666",
"money": "1.00000001",
"feeType": "1",
"fee": "0.0001",
"currency": "USDT",
"netWork": "TRC20",
"name": "test cash name",
"status": "2",
"statusMsg": "SUCCESS",
"hashCode": "5e5c356af0ewrhgnf3d757h8a6a5506cc66354620",
"inAddress": "Twrgtehsd576gsdre876d2545C5Br23324",
"sendAddress": "TDBbbeAB32WE576DVGE82GEC5BhsZs4",
"platSign": "LGEpz2LjbZ6Iyvn+zLc/+t26AaH0aEhHVD62lSCdo6XIkAg86AUncCvmym62wVoE3r2+dHnv27qi/01UQDcqFK8DYioRCcydYSjB4QRVezG3fcZlhWrACmWGacnXkE7p5zChL7pK5h0HuBhbo1zKt4FunQR6QMmcBVfv7YfB3W0"
}
八、订单查询
1.订单查询
import com.google.gson.JsonObject;
public class OrderQuery {
// 测试账号
private static final String MCH_CODE = "S820211021094748000001"; // 商户号
private static final String PLAT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2JoMfFqLsSJjAiCahEnlP3aRj8yCT+WHzR+VvPBTw9S1i7iYWb+MY09CG/HYuHF4+IxshXDJygmndxKf/esuwPybS8mAd//yubHpmZsmBqg1FffT8VH1APa6ZRWASUp4U01ZrbCCp35QA8FuWrJGMJxGx4xk7KUtV2yujxC8noQIDAQAB"; // 平台公钥
private static final String MCH_PRIVATE_KEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAJU8gKFKD0luIYx7X8+JRdCIE0UDBctS6LjXxWLEv/EO7jDBTid6zYP1KmNgpd2DAWWtBFBSQ+gcNwVZZSBHJiSDqVvvJVs2FEbeBvfdv4X93+IYRAXksBasSW5Tpdshbo82pVL4V7wuKCuFLk9UxBHbpQjWAbfyF66RmwIbZD71AgMBAAECgYBjPe7UU2nDDSfmQg0++CyjNjqKRC5QPfxhH6w1uF1kMueXKJWOj42n2RutJpJmsj31nY8m0u4xpsG4HvCu/GGSFhhKZCHLvzp41oY2ubYj9nuFNU//81LycQjulWo2y0UUBY0k2piEt+SwPaiUNbT6nMxNMjlnjRe2okp/3rw+KQJBANG3YlZWoVbCEqzy64bJJLxiPsCA5ErGB0NzRGitq44xkhqGtR8ZZQyVz40pruNa58d73O2xyJSy5+fmZGn4E+sCQQC2LBnguj0CSCKub0mPDcunTTz9V79VXBBZdlB1/YGmRUx2s4sQrJNZS7rL4EqBQ3maIRnG+s+AXCSTfsYrV6CfAkEAxugnVfpelhoGepEAgNuggyivmgfl/2Gpm/jk5l/qOjib+ZrQiQmeBPzGWX4yiSM8eMDrP2sC8r5pJFMp5DRONwJBAJ4n4XuSFJ9jgwCPy3vvzSv9SYLk6E6yM9uHdUlKgoGYzk6Lh6M9QFuY/J49plFdBDiEnj16yCU3WeXXfTJpzB8CQQDMNMR/rIOTE9xGybS3mlQbt22AUnO6XhupWcckEKW4nPGxATwYBQzCY3i/9FTGN0vA+9ZPC2cwHtNxI2kXf3Vp"; // 商户私钥
private static final String orderQueryUrl = "https://bra-openapi.toppay.asia/gateway/query";
public static void main(String[] args) throws Exception {
// 代收
query();
}
private static void query() throws Exception {
Map<String, String> requestParams = new TreeMap<>();
requestParams.put("merchantCode", MCH_CODE);
requestParams.put("queryType", "CASH_QUERY"); // 支付渠道
requestParams.put("orderNum", "186888188666"); // 商户订单号
requestParams.put("platOrderNum", "PRE186888188666"); // 平台订单号
StringBuilder stringBuilder = new StringBuilder();
for (String key : requestParams.keySet()) {
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(orderQueryUrl, postJson); // 发送 post json请求
System.out.println("Response Msg:" + responseJson);
}
}
请求地址
POST https://bra-openapi.toppay.asia/gateway/query
注:商户订单号和平台订单号两者必需传递其中一个,也可以同时传递
请求参数
参数 | 是否必填(Y-是,N-否) | 类型 | 示例 |
---|---|---|---|
merchantCode | Y | 商户ID | S820190712000002 |
queryType | Y | 查询类型 | 代收:ORDER_QUERY.代付:CASH_QUERY |
orderNum | Y | 商户订单号 | T1231511321515 |
platOrderNum | Y | 平台订单号 | PRE1234567890 |
sign | Y | RSA签名 | ja6R8eukQ... |
响应参数说明(格式参考-代收订单查询响应报文示例)
参数 | 类型 | 必填 | 描述 | 示例 |
---|---|---|---|---|
success | BOOLEAN | Y | 接口响应 | true/false |
code | int | Y | 接口响应码 | 1000代表成功,其他的都为失败 |
message | String | Y | 接口响应信息 | 返回具体响应信息 |
data | Json | Y | 接口响应参数 | 以下参数都在data中返回,如失败则为null |
msg | String | Y | 订单状态详细信息 | Request Transaction Success |
platOrderNum | String | Y | 平台订单号 | PI1453242857400963072 |
amount | String | Y | 支付金额 | 1500 |
fee | string | Y | 手续费金额 | 5 |
orderNum | String | Y | 商户订单号 | 23645782 |
inAddress | string | N | 入账地址 | TLRx8JXsDidC7PYVLmeD6Bhk5k5CUjnPV3 |
sendAddress | String | N | 出账地址 | TLRx8JcxDidC7PYVLmeD6Bhk5k5CUjnPV3 |
platRespCode | String | Y | 请求业务是否成功 | FAIL:失败\SUCCESS:成功 |
platRespMessage | String | Y | 接口响应信息提示 | Request Transaction Success |
status | int/String | Y | 订单状态 | 代收状态返回string类型,代付状态返回int类型 |
2.请求报文示例
{
"merchantCode": "S820211021094748000001",
"orderNum": "T1642593166888",
"platOrderNum": "PRE1642593166888",
"queryType": "ORDER_QUERY",
"sign": "lGw1OJcuUL0MGaIq44U2u2bFM5dalJJuT/G6mQWbIBT9dmVAJaLwR125emPDXYYSdnOtNxja86A2VJJLf40BCg2HevHolebvt2ay3ukCQaUhwNkIGz4KF0Ud+XMUA36LoFTWZbDYv9y8vgCnWxwZFKj7ePrfLxc+TA7jpqv65lQ\u003d"
}
3.代收订单查询响应报文示例
{
"success": true,
"code": 1000,
"message": "Success",
"data": {
"msg": "Payment Success",
"platOrderNum": "PRE1483771634191044608",
"amount": "150",
"fee": "16",
"orderNum": "T1642593166888",
"platRespCode": "SUCCESS",
"platRespMessage": "success",
"status": "SUCCESS"
}
}
4.代付订单查询响应报文示例
{
"success": true,
"code": 1000,
"message": "Success",
"data": {
"msg": "test cash",
"platOrderNum": "W0620220119174331000001",
"amount": "125",
"fee": "16",
"orderNum": "186888188666",
"platRespCode": "SUCCESS",
"platRespMessage": "success",
"status": 2
}
}
九、账户余额查询
1.账户余额查询
import com.google.gson.JsonObject;
public class OrderQuery {
// 测试账号
private static final String MCH_CODE = "S820211021094748000001"; // 商户号
private static final String PLAT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2JoMfFqLsSJjAiCahEnlP3aRj8yCT+WHzR+VvPBTw9S1i7iYWb+MY09CG/HYuHF4+IxshXDJygmndxKf/esuwPybS8mAd//yubHpmZsmBqg1FffT8VH1APa6ZRWASUp4U01ZrbCCp35QA8FuWrJGMJxGx4xk7KUtV2yujxC8noQIDAQAB"; // 平台公钥
private static final String MCH_PRIVATE_KEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAJU8gKFKD0luIYx7X8+JRdCIE0UDBctS6LjXxWLEv/EO7jDBTid6zYP1KmNgpd2DAWWtBFBSQ+gcNwVZZSBHJiSDqVvvJVs2FEbeBvfdv4X93+IYRAXksBasSW5Tpdshbo82pVL4V7wuKCuFLk9UxBHbpQjWAbfyF66RmwIbZD71AgMBAAECgYBjPe7UU2nDDSfmQg0++CyjNjqKRC5QPfxhH6w1uF1kMueXKJWOj42n2RutJpJmsj31nY8m0u4xpsG4HvCu/GGSFhhKZCHLvzp41oY2ubYj9nuFNU//81LycQjulWo2y0UUBY0k2piEt+SwPaiUNbT6nMxNMjlnjRe2okp/3rw+KQJBANG3YlZWoVbCEqzy64bJJLxiPsCA5ErGB0NzRGitq44xkhqGtR8ZZQyVz40pruNa58d73O2xyJSy5+fmZGn4E+sCQQC2LBnguj0CSCKub0mPDcunTTz9V79VXBBZdlB1/YGmRUx2s4sQrJNZS7rL4EqBQ3maIRnG+s+AXCSTfsYrV6CfAkEAxugnVfpelhoGepEAgNuggyivmgfl/2Gpm/jk5l/qOjib+ZrQiQmeBPzGWX4yiSM8eMDrP2sC8r5pJFMp5DRONwJBAJ4n4XuSFJ9jgwCPy3vvzSv9SYLk6E6yM9uHdUlKgoGYzk6Lh6M9QFuY/J49plFdBDiEnj16yCU3WeXXfTJpzB8CQQDMNMR/rIOTE9xGybS3mlQbt22AUnO6XhupWcckEKW4nPGxATwYBQzCY3i/9FTGN0vA+9ZPC2cwHtNxI2kXf3Vp"; // 商户私钥
private static final String orderQueryUrl = "https://bra-openapi.toppay.asia/gateway/query";
public static void main(String[] args) throws Exception {
query();
}
private static void query() throws Exception {
Map<String, String> requestParams = new TreeMap<>();
requestParams.put("merchantCode", MCH_CODE);
requestParams.put("currency", "BRL"); // 币种(BRL)
StringBuilder stringBuilder = new StringBuilder();
for (String key : requestParams.keySet()) {
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(orderQueryUrl, postJson); // 发送 post json请求
System.out.println("Response Msg:" + responseJson);
}
}
请求地址
POST https://bra-openapi.toppay.asia/gateway/interface/getBalance
请求参数
参数 | 必填 | 类型 | 示例 |
---|---|---|---|
merchantCode | Y | 商户ID | S820211021094748000001 |
currency | N | 币种 | BRL(不传展示所有货币单位的余额) |
sign | Y | RSA签名 | ja6R8eukQ... |
响应参数
参数 | 类型 | 必填 | 描述 | 示例 |
---|---|---|---|---|
success | BOOLEAN | Y | 接口响应 | true/false |
code | int | Y | 接口响应码 | 1000代表成功,其他的都为失败 |
message | String | Y | 接口响应信息 | 返回具体响应信息 |
data | Json | Y | 接口响应参数 | 以下参数都在data中返回,如失败则为null |
mchId | String | Y | 商户ID | S8202110212321300001 |
mchName | String | Y | 商户名称 | test |
mchNo | String | Y | 商户ID | TP123 |
currency | string | Y | 币种 | BRL |
balance | String | Y | 可用余额 | 1000.00 |
freeze | String | Y | 冻结余额 | 10.00 |
waitingSettleAmount | String | Y | 待结算金额 | 200.00 |
freezeWaitingSettleAmount | String | Y | 冻结待结算金额 | 100.00 |
totalAmount | String | Y | 全部金额(可用余额+冻结余额+待结算金额+冻结待结算金额) | 20000.00 |
2.请求报文示例
{
"merchantCode": "S8202110212321300001",
"currency": "BRL",
"sign": "X/o+IQUzLJqYe9Feid9Uww72mJGOvhJSJEIfo1EUChrZyVZnzGHtd61QhOqRmXCtAwk7V7k="
}
3.响应报文示例
{
"success": true,
"code": 1000,
"message": "SUCCESS",
"data": [
{
"mchId": "S82022091232130000001",
"mchName": "test",
"mchNo": "test",
"country": "BRAZIL",
"currency": "BRL",
"balance": "1000000.01",
"freeze": "10.00",
"waitingSettleAmount": "10.00",
"freezeWaitingSettleAmount": "20.00",
"totalAmount": "1000040.01"
}
]
}
十、可选参数附录
Ⅰ 代收业务
1 Status 参数
字段值 | 说明 |
---|---|
INIT_ORDER | 订单初始化 |
NO_PAY | 未支付 |
SUCCESS | 支付成功(最终态) |
PAY_CANCEL | 撤销(最终态) |
PAY_ERROR | 支付失败(最终态) |
Ⅱ 代付业务
1 Status 参数
字段值 | 说明 |
---|---|
0 | 待处理 |
1 | 已受理 |
2 | 代付成功(最终态) |
4 | 代付失败(最终态) |
5 | 银行代付中 |