支付API

请求说明

  • 本文档适用于已经在官方申请过渠道号channelId与私钥的合作方

  • 合作方要求:提供渠道名称、注册账户

流程图

接入流程:

①开发者调用创建支付订单接口,创建支付订单;

②返回支付页面链接,用户进行付款;

③获取支付结果,以下两种方式都可行:

ⅰ开发者提供支付完成通知接口,用户完成支付后,我们调用该接口进行通知;

ⅱ 开发者调用查询订单状态接口,获取订单支付结果状态。

接口列表

请求类型

请求方法

描述

接口示例

POST application/json

api/pay/createPayOrder

创建支付订单

代码示例

POST application/json

api/pay/queryPayOrder

查询订单状态

代码示例

POST application/json

由开发者提供

支付完成通知

创建支付订单

api/pay/createPayOrder

说明

合作方调用该接口,创建收款订单

请求参数

参数名称

是否必须

数据类型

描述

默认值

取值范围

channelId

String

渠道编号

由我们官方提供,eg:payaaa201903212028

channelName

String

渠道名称简写

开发者提供给我们,eg:xxMall

sign

String

签名

参见签名生成

timestamp

Long

时间戳

毫秒时间戳

channelOrderId

String

渠道订单Id

开发者自定义

channelUserNo

String

渠道用户名

开发者自定义

coinCode

String

付款币种名称

eg:ETH

amount

String

付款金额

eg:1

remark

String

备注

订单备注

响应参数

 {
     "data": {
         "amount": "2",
         "channelOrderId": "channelorder001",
         "channelUserNo": "xxMall_zhangsan",
         "coinCode": "ETH",
         "payId": "jpedyB3T",
         "payUrl": "{host}/swft-v3/PayAPI.html?payID=jpedyB3T",
         "remark": "zhangsan pay to xxMall"
     },
     "resCode": "800",
     "resMsg": "成功"
 }

data说明

 {
     "amount": "付款金额",
     "channelOrderId": "渠道订单号",
     "channelUserNo": "渠道用户名",
     "coinCode": "付款币种",
     "payId": "支付订单号",
     "payUrl": "支付页面链接",
     "remark": "备注"
 }

查询订单状态

api/pay/queryPayOrder

说明

查询支付订单状态接口

请求参数

参数名称

是否必须

数据类型

描述

默认值

取值范围

payId

String

支付订单Id

eg : Nlt0OnQP

channelId

String

渠道编号

eg:payaaa201903212028

sign

String

签名

参见签名生成

timestamp

String

时间戳

毫秒时间戳

响应参数

 {
     "data": {
         "amount": "2",
         "channelId": "payaaa201903212028",
         "channelName": "xxMall",
         "coinCode": "ETH",
         "createTime": "2019-03-22 17:11:38",
         "payId": "XMdqbM8Q",
         "remark": "zhangsan pay to xxMall",
         "sign": "DB99639E8B9EC419F88C94355DF1C483ACD420B7366C27CAB8E86A6D7B84CB52",
         "status": "complete",
         "timestamp": 1553838107450,
         "transType": "PAY_IN",
         "userNo": "5****@qq.com"
     },
     "resCode": "800",
     "resMsg": "成功"
 }

data说明

   {
       "amount": "付款金额",
       "channelOrderId": "渠道订单号",
       "channelUserNo": "渠道用户名",
       "coinCode": "付款币种",
       "createTime": "创建时间",
       "payId": "支付订单号",
       "remark": "备注",
       "sign": "签名",
       "status": "支付订单状态",
       "timestamp": 时间戳,
       "transType": "订单类型",
       "userNo": "第三方开户账号"
   }

支付完成通知

说明

订单支付完成通知接口

请求参数

参数名称

是否必须

数据类型

描述

默认值

取值范围

payId

String

支付订单号

eg: Nlt0OnQP

status

String

支付订单状态

状态: valid-有效,complete-支付完成,invalid-超时无效

sign

String

签名

timestamp

String

时间戳

毫秒时间戳

响应参数

 {
     "data": “响应完成”,
     "resCode": "800",
     "resMsg": "成功"
 }

data说明

 {
     "data": “响应信息”,
     "resCode": "返回状态码",//800:表示成功,其他表示失败
     "resMsg": "返回结果信息"
 }

错误码说明

HTTP请求错误码

错误码

含义

说明

200

成功

403

资源不可用

header头信息错误或不全

404

资源未找到

url错误

405

请求方式错误

GET、POST方式替换

500

服务器错误

需联系平台客服

接口返回数据resCode码

错误码

含义

说明

800

成功

请求成功

900

服务器错误

服务器错误

213

非法请求

签名认证失败

214

币种不存在

币种不一致

216

金额数量不合法

付款金额不合法

907

必填字段为空

参数请求不全

1002

订单不存在

支付订单未创建或订单号错误

1017

第三方渠道未创建账户或账号不存在

需要检查是否创建账户

1018

第三方渠道账号未配置

需要联系官方进行配置

1019

第三方渠道号未配置

需要联系官方进行配置

1031

备注长度超出50个字符

备注长度超限

1032

第三方渠道支付页面地址未配置

需要联系官方进行配置

生成签名

按照ASCII码的顺序对参数名进行排序,转化为json字符串,使用私钥签名,采用HMAC-SHA256加密方式。

签名生成步骤说明

第一步:

设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

特别注意以下重要规则:

  1. 参数名ASCII码从小到大排序(字典序);

  2. app_id,timestamp为必填参数;timestamp为最近五分钟时间戳,超过5分钟失效;

  3. 如果参数的值为空不参与签名;

  4. 参数名区分大小写;

  5. 传送的sign参数不参与签名,将生成的签名与该sign值作校验。

第二步:

在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行HMAC-SHA256运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。

伪代码举例

假设传送的参数如下: channelId: mttest timestamp : 1516320000 body : test

 第一步:对参数按照key=value的格式,并按照参数名ASCII字典序排序如下:
 stringA="app_id=mttest&body=test&timestamp=1516320000";
 第二步:拼接API密钥:
 stringSignTemp=stringA+"&secret=my_test_secret" 
 sign=hash_hmac("sha256",stringSignTemp,key).toUpperCase()="6A9AE1657590FD6257D693A078E1C3E4BB6BA4DC30B23E0EE2496E54170DACD6" //注:HMAC-SHA256签名方式    

示例代码

 @Test
     public void deductBalance() throws IOException {
         JTextField field ;
         String url = "http://localhost:8088/channel/deductBalance";
         TreeMap<String,Object> params = Maps.newTreeMap();
         params.put("orderId","my_order_id");
         params.put("channelId","test91021071617412");
         long timestamp = System.currentTimeMillis();
         params.put("timestamp",timestamp);
         String channelSign = getChannelSign(params, secret);
         params.put("sign",channelSign);
         System.out.println(url);
         System.out.println(JSON.toJSONString(params));
         String result = HttpUtils.sendRequestBody(url, params);
         System.out.println(result);
     }

     public static String getChannelSign(Map<String, Object> params,String secret) {
         StringBuilder result = new StringBuilder();
         if (params != null) {
             for (Object key : params.keySet()) {
                 Object value = params.get(key);
                 result.append(key).append("=").append(value).append("&");
             }
             String tempString = result + "secret=" + secret;
             try {
                 System.out.println(tempString);
                 String sign = EncryptUtils.sha256_HMAC(tempString, secret).toUpperCase();
                 System.out.println(sign);
                 return sign;
             } catch (Exception e) {
                 e.printStackTrace();
             }
         }
         return null;
     }

代码中参与加密的参数及顺序为:channelId=test91021071617412&orderId=my_test_id&timestamp=1547987604644&secret=my_secret