开发说明 & DEMO

APP+ 采用了 HTTP 协议提供各类接口,并且所有接口都是统一请求地址,方便商户简单、快速接入。本 API 包含 2 类接口,页面浏览器类和系统调用类。

  • 页面浏览器类:需要从前端页面以 Form 表单的形式发起请求,浏览器会自动跳转至汇付的相关页面(一般是快捷收银台或签约页面),用户在该页面完成相关业务操作后再回跳到商户指定页面,页面方式返回的是标准的表单格式。
  • 系统调用类:直接从服务端发起 HTTP 请求,API 会同步返回请求结果,返回的数据格式都是规范 JSON 格式。

参数和订单规范

参数规范

  • 参数为可选项时,JSON 格式中可以不包含该参数,或该参数内容为空;
  • 所有参数值不应该包含与 JSON 格式冲突的特殊字符,如括号,逗号,双引号,冒号等;
  • 金额单位为元,精确到分,如:1200.00,359.14;
  • 日期为定长 8 的字符串,格式为 YYYYMMDD,如 20140802;
  • 商户客户号、用户客户号和账户号均为变长字符串;

订单规范

  • 每个接口通过商户客户号、订单号、订单日期来标识订单的唯一性;

  • 由于网络的不稳定性等原因,相同订单的交易应答返回给商户订单系统时,有可能会出现以下两种情况:

    1.同一订单请求多次,先支付完成的订单返回参数后通知到商户;

    2.同一笔订单收到多次支付结果;

处理原则:商户以订单的成功状态为终态,商户收到订单支付成功的应答后,如果再次收到订单支付失败的应答,不做处理即可。

API 调用规范

_images/cfca_eg_request.png

举例说明:假设接口参数为:version=10,cmd_id=101,mer_cust_id=6666000000011499,user_name=张三,bg_ret_url=http://mertest.chinapnr.com/npay

第一步:将接口参数转换成 JSON 格式字符串。

{“version”:”10”,”cmd_id”:”101”,”mer_cust_id”:”6666000000011499”,”user_name”:”张三”,”bg_ret_url”:”http://mertest.chinapnr.com/npay”}

第二步:使用 pfx 证书和密码进行加密,生成 check_value。

java

SignResult signResult  = CFCASignature.signature(pfxFile, pfxFilePwd,params, "utf-8");
String check_value = signResult.getSign();

第三步:组装请求参数 version、cmd_id、mer_cust_id 和 check_value,以 post 方式请求接口。

java

String postStr = "cmd_id=101&version=10&mer_cust_id=6666000000011499&check_value=第二步生成的加签串";
HttpRequest httpRequest = HttpRequest.post("https://apptrade.testpnr.com/api/merchantRequest").charset("UTF-8");
HttpResponse httpResponse = httpRequest.contentType("application/x-www-form-urlencoded").body(postStr).send();

注意:组装请求参数时 version、cmd_id 和 mer_cust_id 必须和第一步的接口参数中的 version、cmd_id 和 mer_cust_id 值保持一致。

API 应答接收规范

_images/cfca_eg_response.png

举例说明(以交易状态查询接口返回的数据为例):

第一步:从应答报文中取得 check_value

假设返回数据如下:

{"check_value":"B170E66B00D344F8CEA68C3A84F0ED2207805147793F806CBD3D3E166B57F511ABEB7D5D7A725ECEFDC640FDC2F7102CD8D470CB0BE18A3B4ADE870689D7FCBD4CA55DD5C2E1D6BFC3F30514B0813D8E680708B44A1C1637780CA0D998EF22C10B7E4B8954F304F226BB50F091A60C939F7C4DB513261FC47667757550C7911E"}

第二步:解签 check_value,并取得返回参数

将第一步取得的 check_value,使用 cer 证书文件和汇付的商户号(100001)进行解签,得到返回参数的 JSON 格式字符串,例如:

{"extension":"extension","trans_stat":"","cmd_id":"301","div_detail":"","resp_code":"301000","mer_priv":"mer_priv","trans_amt":"","trans_type":"01","order_date":"20160801","order_id":"600001","mer_cust_id":"6666000000024878","resp_desc":"查询成功"}

API 特点

  • 为保证接口的安全性,每笔交易都通过 CFCA 进行签名,篡改签名将导致验签失败,交易无法正常进行;
  • 商户可以动态地将每笔交易的返回地址指向不同的交易网站,适合于多网站和多应用的商户;
  • 商户在接口中可以自定义域,本平台返回时,会将该域原样返回,供商户实现特定的功能;
  • 本平台通过后台方式向商户发送交易结果,通过分析商户的返回页面,可以准确地知道商户是否收到交易应答结果,从而对发送失败的交易采取自动重发;

结果返回机制

接口中提供“商户前台应答地址ret_url”,“商户后台应答地址bg_ret_url”,向用户反馈接口处理结果

  • 商户前台应答地址ret_url,商户通过此参数传入商户侧的页面展示页面,汇付交易受理完跳转到该地址展示受理结果。
  • 商户后台应答地址bg_ret_url,对于交易异步产生终态结果的,商户通过此参数传入后台结果回调地址,汇付在交易处理完毕后通过调用该地址通知商户交易的终态结果。

异步回调接收规范

  • 本平台除了查询交易外所有交易,都同时提供异步回调通知,当请求HTTP或HTTPS,5秒内未收到交易应答,或者应答的状态码非200,该交易即进入重发队列,本平台会尝试将该交易应答重发给商户,重试3次 。如若由于网络或商户系统异常导致返回均无法接收,需线下请求重发。

  • 为了表示商户订单系统已经收到交易应答,商户必须在应答接收页面输出一段特殊的字符串,组成规则为:固定字符串RECV_ORD_ID_加上交易接口的订单号order_id。

    例如:商户收到一笔订单号为order_id=20180101ABCD 的交易应答,则应在该页面输出 RECV_ORD_ID_20180101ABCD 的字符串。 代码示例:resp.getWriter().print(“RECV_ORD_ID_” + orderId);

  • 我司本系统生产环境出口IP为:139.224.111.237,若贵司系统对外网访问有IP限制,烦请将该IP加入白名单,以确保异步回调能收到。

加解签 & DEMO

本 API 对商户与汇付之间请求数据采用的是 CFCA 证书加解签方式。目前支持JAVA、PHP、C#、Python四种语言。

JAVA 代码示例及完整DEMO

相关 jar 包下载

JAVA版完整DEMO 下载

加签示例

java

private static String sign(String valueObj) {
       // 加签用 pfx 文件,请换成商户自己导出的证书
       String pfxFile = "/app/etc/product/888888-汇付测试商户.pfx";
       // 加签用密码,导出 pfx 证书时的密码
       String pfxFilePwd = "888888";
       // 加签
       SignResult signResult  = CFCASignature.signature(pfxFile, pfxFilePwd,valueObj, "utf-8");
       if ("000".equals(signResult.getCode())) {
           return signResult.getSign();
       } else {
           return "加签失败";
       }
    }

验签示例

java

public static String parseResult(String responseJson) throws Exception {
    JSONObject jsonObject = JSON.parseObject(responseJson);
    String sign = jsonObject.getString("check_value");
            // 解签用的证书,请换成商户自己下载的证书
    String cerFile = "/app/etc/product/CFCA_ACS_OCA31.cer";

    VerifyResult verifyResult = CFCASignature.verifyMerSign("100001", sign, "utf-8", cerFile);

    if ("000".equals(verifyResult.getCode())) {
        String content = new String(verifyResult.getContent(), Charset.forName("utf-8"));
        return content;
    } else {
        return "验签失败";
    }
}

JAVA版完整DEMO说明

DEMO 分别提供了页面浏览器调用方式的快捷支付 APP 版接口和后台系统调用方式的 APP 支付接口调用示例。使用 DEMO 之前商户需要申请 CFCA 加解签证(商户在汇付开户后,会有邮件通知下载)

硬件需求

服务可以部署在 linux 和 windows 等具有 JVM 环境的服务容器内,比如 jboss,tomcat 等(暂提供 jboss)。安装 JDK1.7 并配置好 JDK 的环境变量。

部署服务

将证书文件放到服务器 $path 目录下,上传 war 包到服务器。

上传测试证书888888-NEW.pfx,CFCA_ACS_TEST_OCA31.cer,到/app/etc/目录下。

启动服务器

  • Windows服务器下执行**/jboss/bin/standalone.bat

如:**/jboss/bin/standalone.bat

  • Linux服务器下,执行**/jboss/bin/standalone.sh

如:**/jboss/bin/standalone.sh

接口 调用方式 访问地址 说明
快捷支付 APP 版接口 页面浏览器提交 http://ip:port/service-demo/quickPay/pay.json 请求后跳转快捷支付页面
APP 支付接口 后台系统调用 http://ip:port/service-demo/appPay/pay?pay_type=10 请求后返回APP支付参数

PHP 代码示例( Linux 版)

相关组件下载

Demo 运行

一、安装对应版本的PHP

二、安装运行时环境(glibc库等)

三、修改PHP的配置文件php.ini

  • 修改php.ini,使php允许加载扩展,并将当前扩展添加到其扩展列表中
  • enable_dl = On
  • extension=libSADKExtension.so

四、在DemoRSA目录下替换证书和cer文件

  • pfx为私钥文件请妥善保管不要泄露给他人,cer文件为颁发者公钥,用来验证汇付公钥

五、配置 cfcalog.conf cfca日志文件

六、通过命令行终端运行Demo文件

  • php huifuCFCALinuxDemo.php

PHP demo运行常见问题

  • Message:cfca_Initialize error:24578,请检查下证书权限、日志权限,证书路径是否正确
  • Message:cfca_signData_PKCS7Attached error:24578,请检查下证书权限、日志权限,证书路径是否正确
  • 具体错误可通过cfca.log日志中判断排查问题
  • 注:cfca_verifyCertificate 参数 $nCertVerifyFlag 是数值类型的
Msg PKCS7-attached Sign 为使用 pfx 证书加签
PKCS7-attached-Verify 为验证汇付的签名
cfca_verifyCertificate 为验证证书链合法性
cfca_getCertificateInfo 为获取证书信息(非必要)

php

 <?php

class HuifuCFCA
{
        private $apiUrl                 = 'http://mertest.chinapnr.com/npay/merchantRequest';                       //app+ 商户交易接口,此处使用的是联调环境地址
        private $strSignAlg             = 'RSA';                     //RSA证书类型
        private $strPfxPassword         = '888888';                 //导出时设置的密码
        private $strHashAlg             = 'SHA-256';                //加签算法
        private $strPfxFilePath        = './RSA/AS0381.pfx';      //汇付下发的证书,此处换成商户自己的证书 .pfx 格式 加签使用
        private $strTrustedCACertFilePath = './RSA/CFCA_ACS_TEST_OCA31.cer|./RSA/CFCA_ACS_TEST_CA.cer'; //汇付下发的.cer证书 ,需要一对证书 解签使用
        private $strLogCofigFilePath  = './cfcalog.conf';          //CFCA log 目录

        public function __construct()
        {
                $this->getCFCAInitialize();     //CFCA工具初始化
        }

        /**
         * CFCA工具初始化
         */
        private function getCFCAInitialize()
        {
                $nResult = cfca_initialize($this->strLogCofigFilePath);
                if (0 != $nResult) {
                        //记录log
                        echo new Exception("\n cfca_Initialize error:".$nResult."\n");
                }
        }

        /**
         * 调用接口  此处是APP + 的接口请求
         *
         * @return string
         */
        public function apiRequest(){
                //请求参数,依据商户自己的参数为准
                $requestParam['version'] = '10';
                $requestParam['cmd_id'] = '202';
                $requestParam['mer_cust_id'] = '6666000000002619';
                $requestParam['user_cust_id'] = '6666000000054387';
                $requestParam['order_date'] = '20180918';
                $requestParam['order_id'] = '201809189000001';
                $requestParam['trans_amt'] = '1.00';
                $requestParam['cash_bind_card_id'] = '76247';
                $requestParam['fee_obj'] = '';
                $requestParam['fee_acct_id'] = '';
                $requestParam['cash_type'] = '02030000';
                $requestParam['bg_ret_url'] = 'http://192.168.0.74:8001/npayCallBack/asyncHandle.json';
                $requestParam['mer_priv'] = 'test_mer_priv';
                $requestParam['extension'] = 'test_extension';

                //加签
                $strSignSourceData = json_encode($requestParam);
                $cfcaSign = $this->CFCASignature($strSignSourceData);

                //接口请求参数
                $param = [
                        'requestData'  => [
                                'cmd_id' => $requestParam['cmd_id'],
                                'mer_cust_id' => $requestParam['mer_cust_id'],
                                'version' => $requestParam['version'],
                                'check_value' => $cfcaSign,
                        ],
                        'headers' => ['Content-type' => 'application/x-www-form-urlencoded;charset=UTF-8']
                ];
                $requestData = $this->requestData($param);
                $checkValue = json_decode($requestData['body'],1)['check_value'];

                //验证接口返回的签名数据
                $sourceData = $this->getCFCASignSourceData($checkValue);
                $SignCertContent = !empty($sourceData['strMsgP7AttachedSignCertContent']) ? $sourceData['strMsgP7AttachedSignCertContent'] : '';

                //验证返回数据的CFCA证书有效性
                $verifyCertificat = $this->verifyCertificat($SignCertContent);
                $signSourceData = '';
                if(!empty($sourceData['strMsgP7AttachedSource']) && $verifyCertificat){  //校验证书有效性
                        $signSourceData =  $sourceData['strMsgP7AttachedSource'];
                }

                return $signSourceData;
        }

        /**
         * CFCA 加签方法
         *
         * @param $strSignSourceData  base64 encode 加签原串
         * @return string  base64 encode 加签串
         */
        private function CFCASignature($strSignSourceData){
                $strMsgPKCS7AttachedSignature = '';//加签生成串 ,输出变量,无需传值

                try{
                        //调用加签方法
                        $nResult = cfca_signData_PKCS7Attached($this->strSignAlg, $strSignSourceData,
                                $this->strPfxFilePath, $this->strPfxPassword, $this->strHashAlg,$strMsgPKCS7AttachedSignature);

                        //加签方法异常判断及记录
                        if (0 != $nResult) {
                                //记录log
                                echo new Exception("\n cfca_signData_PKCS7Attached error:".$nResult."\n");
                        }

                }catch (Exception $e){
                        throw new Exception("\n cfca_verifyCertificate error:".$e."\n");
                }

                return base64_encode($strMsgPKCS7AttachedSignature);
        }

        /**
         * CFCA 验证签名数据
         *
         * @param $signature
         * @return array
         */
        private function getCFCASignSourceData($signature){
                $strMsgP7AttachedSignCertContent = '';  //PKCS#7 中的签名证书  输出变量,无需传值
                $strMsgP7AttachedSource = '';   //签名原文字符串  输出变量,无需传值

                try{
                        //调用验证签名数据方法
                        $nResult = cfca_verifyDataSignature_PKCS7Attached($this->strSignAlg, base64_decode($signature),
                                $strMsgP7AttachedSignCertContent,$strMsgP7AttachedSource);

                        //验证签名方法异常判断及记录
                        if (0 != $nResult) {
                                //记录log
                                echo new Exception("cfca_verifyDataSignature error:".$nResult);
                        }

                }catch (Exception $e){
                        //记录log
                        throw new Exception("cfca_verifyDataSignature_PKCS7Attached error:".$e);
                }

                return array(
                        'strMsgP7AttachedSource' => $strMsgP7AttachedSource,
                        'strMsgP7AttachedSignCertContent' => $strMsgP7AttachedSignCertContent,
                );
        }

        /**
         * CFCA 证书有效性验证
         *
         * @param $strMsgP7AttachedSignCertContent PKCS#7 中的签名证书 base64
         * @return int
         */
        private function verifyCertificat($strMsgP7AttachedSignCertContent = ''){
                $nCertVerifyFlag = '4'; //验证证书链完整性
                $strTrustedCACertFilePath = $this->strTrustedCACertFilePath;
                $isVerify = false;

                try{
                        //调用验证方法
                        $nResult = cfca_verifyCertificate($strMsgP7AttachedSignCertContent, $nCertVerifyFlag, $strTrustedCACertFilePath,"");
                        if (0 == $nResult) {  // 0 为验证通过 ,其他验证失败
                                $isVerify = true;
                        }else{
                                //记录log
                                echo new Exception("cfca_verifyCertificate error:".$nResult);
                        }

                }catch (Exception $e){
                        //记录log
                        throw new Exception("cfca_verifyCertificate error:".$e);
                }

                return $isVerify;
        }


        /**
         * 请求接口返回数据
         * @param $param
         * @return array
         */
        private function requestData($param)
        {
                try{
                        // 请求接口所以参数初始化
                        $data = [
                                'url'         => $this->apiUrl,          // 接口 url
                                'requestData' => $param['requestData'], // 请求接口参数
                                'headers'     =>$param['headers']
                        ];

                        $res = $this->httpPostRequest($data['url'],$data['headers'],$data['requestData']);

                } catch (\Exception $e) {
                        //记录log
                        throw new Exception("api requestData error :".$e);
                }

                return [
                        'status' => $res['info']['http_code'],
                        'body' => $res['body']
                ];
        }

        /**
         * curl post 请求方法
         *
         * @param string $url
         * @param array $header
         * @param array $requestData
         * @return array
         */
        private function httpPostRequest($url = '',$header = array(),$requestData = array()){
                $curl = curl_init();
                curl_setopt ( $curl, CURLOPT_HTTPHEADER,$header);
                curl_setopt($curl, CURLOPT_URL, $url);
                curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
                curl_setopt($curl, CURLOPT_POST, true);
                curl_setopt($curl, CURLOPT_POSTFIELDS,http_build_query($requestData));
                $res = curl_exec($curl);
                $info = curl_getinfo($curl);
                $error = curl_error($curl);
                curl_close($curl);

                return [
                        'body' => $res,
                        'info' => $info,
                        'error' => $error,
                ];
        }

        /**
         *CFCA工具结束
         */
        public function __destruct()
        {
                cfca_uninitialize();
        }

}
//调用
$demoObj = new HuifuCFCA();
$data = $demoObj->apiRequest();

print_r('<pre/>');
print_r($data);

PHP 代码示例( Windows 版)

DEMO 下载

Demo 运行

环境要求:WinServer2008 64bit、 WinServer2012 64bit 1. 配置php.ini php -i|findstr ini ,找到php.ini所在路径 将重命名后的 php.ini 文件内的“; extension_dir = “ext””行,修改为 “extension_dir = “./ext””。然后,在 php.ini 文件末尾,添加以下两行内容: [COM_DOT_NET] extension=php_com_dotnet.dll

2. 注册com组件 64位下执行 regsvr32 CryptoKit.Standard.x64.dll 32位下执行 regsvr32 CryptoKit.Standard.x86.dll

3. 在DemoRSA目录下替换证书和cer文件 pfx为私钥文件请妥善保管不要泄露给他人 cer文件为颁发者公钥,用来验证汇付公钥

4. 在Demo目录下执行 php huifuCFCAWindowsDemo.php

SignData_PKCS7Attached 为使用 pfx 证书加签
VerifyDataSignature_PKCS7Attached 为验证汇付的签名
VerifyCertificate 为验证证书链合法性
GetCertificateInfo 为获取证书信息(非必要)

php

<?php

class HuifuCFCA
{
        private $apiUrl                 = 'http://mertest.chinapnr.com/npay/merchantRequest';   // app+ 商户交易接口,此处使用的是联调环境地址
        private $strSignAlg             = 'RSA';                     //RSA证书类型
        private $strPfxPassword         = '888888';                 //导出时设置的密码
        private $strHashAlg             = 'SHA-256';                //加签算法
        private $strPfxFilePath        = './RSA/AS0381.pfx';       //汇付天下发的证书,此处换成商户自己的证书  此处换成商户自己的证书 .pfx 格式 加签使用
        private $strTrustedCACertFilePath = './RSA/CFCA_ACS_TEST_OCA31.cer|./RSA/CFCA_ACS_TEST_CA.cer'; //汇付下发的.cer证书 ,需要一对证书 验签使用
        private $cryptoAgentServerObj = '';                         //CFCA obj

        public function __construct()
        {
                // Create the object of COM by its ProgID
                // If your php is compiled with x64, you need to use CryptoKit.standard.x64.dll, its ProgID is:CryptoKit.CryptoAgent.Server.Standard.x64.1
                // If your php is compiled with x86, you need to use CryptoKit.standard.x86.dll, its ProgID is:CryptoKit.CryptoAgent.Server.Standard.x86.1
                // Change next line according to your php
                //注册windows com 服务,依据自己PHP编译版本选择对应参数,此处使用的是32位编译版本的PHP
                $this->cryptoAgentServerObj = new \COM("CryptoKit.CryptoAgent.Server.Standard.x86.1", NULL, CP_UTF8);
        }

        /**
         * 调用接口  此处是APP + 的接口请求
         *
         * @return string
         */
        public function apiRequest(){
                //请求参数,依据商户自己的参数为准
                $requestParam['version'] = '10';
                $requestParam['cmd_id'] = '202'; //取现接口
                $requestParam['mer_cust_id'] = '6666000000002619';
                $requestParam['user_cust_id'] = '6666000000054387';
                $requestParam['order_date'] = '20180918';
                $requestParam['order_id'] = '201809189000001';
                $requestParam['trans_amt'] = '1.00';
                $requestParam['cash_bind_card_id'] = '76247';
                $requestParam['fee_obj'] = '';
                $requestParam['fee_acct_id'] = '';
                $requestParam['cash_type'] = '02030000';
                $requestParam['bg_ret_url'] = 'http://192.168.0.74:8001/npayCallBack/asyncHandle.json';
                $requestParam['mer_priv'] = 'test_mer_priv';
                $requestParam['extension'] = 'test_extension';

                //加签
                $strSignSourceData = json_encode($requestParam);
                $cfcaSign = $this->CFCASignature($strSignSourceData);

                //取现接口请求
                $param = [
                        'requestData'  => [
                                'cmd_id' => $requestParam['cmd_id'],
                                'mer_cust_id' => $requestParam['mer_cust_id'],
                                'version' => $requestParam['version'],
                                'check_value' => $cfcaSign,
                        ],
                        'headers' => ['Content-type' => 'application/x-www-form-urlencoded;charset=UTF-8']
                ];
                $requestData = $this->requestData($param);
                $checkValue = json_decode($requestData['body'],1)['check_value'];

                //验证接口返回的签名数据
                $strBase64CertContent = $this->verifyDataSignature($checkValue);

                //验证返回数据的CFCA证书有效性
                $verifyCertificat = $this->verifyCertificat($strBase64CertContent);

                //获取解签数据
                $signSourceData = '';
                if($verifyCertificat){  //校验证书有效性
                        $signSourceData = $this->getCFCASignSourceData($checkValue);
                }

                return $signSourceData;
        }

        /**
         * cfca 加签方法
         *
         * @param $strSignSourceData 待签名字符串
         * @return string
         */
        private function CFCASignature($strSignSourceData){
                $strMsgPKCS7AttachedSignature = '';

                try{
                        $strMsgPKCS7AttachedSignature = $this->cryptoAgentServerObj->SignData_PKCS7Attached($this->strSignAlg, $strSignSourceData,
                                $this->strPfxFilePath, $this->strPfxPassword, $this->strHashAlg);

                }catch (Exception $e){
                        $strErrorMsg = $this->cryptoAgentServerObj->GetLastErrorDesc();

                        return  $strErrorMsg;
                }

                return base64_encode($strMsgPKCS7AttachedSignature);
        }

        /**
         * CFCA 验证签名数据
         * @param $signature Base64编码的签名
         * @return string
         */
        private function verifyDataSignature($signature){
                $strBase64CertContent = "";

                try{
                        $strBase64CertContent = $this->cryptoAgentServerObj->VerifyDataSignature_PKCS7Attached($this->strSignAlg,base64_decode($signature));

                }catch (Exception $e){
                        $strErrorMsg = $this->cryptoAgentServerObj->GetLastErrorDesc();
                        //记录log
                        throw new Exception("\n verifyDataSignature error:".$strErrorMsg."\n");
                }

                return $strBase64CertContent;
        }

        /**
         * CFCA 解签获取签名数据
         * @param $signature
         * @return string
         */
        private function getCFCASignSourceData($signature){
                $strMsgP7AttachedSource = '';

                try{
                        $strMsgP7AttachedSource = $this->cryptoAgentServerObj->GetSignSourceData(base64_decode($signature));

                }catch (Exception $e){
                        $strErrorMsg = $this->cryptoAgentServerObj->GetLastErrorDesc();

                        return  $strErrorMsg;
                }

                return $strMsgP7AttachedSource;
        }

        /**
         * CFCA 证书有效性验证
         *
         * @param $strBase64CertContent 签名证书内容 base64
         * @return bool
         */
        private function verifyCertificat($strBase64CertContent = ''){
                $nCertVerifyFlag = '4'; //验证证书链完整性
                $strTrustedCACertFilePath = $this->strTrustedCACertFilePath;

                try{
                        //调用验证方法
                        $nResult = $this->cryptoAgentServerObj->VerifyCertificate($strBase64CertContent, $nCertVerifyFlag, $strTrustedCACertFilePath,"");

                        if (!$nResult) {  // true 为验证通过 ,其他验证失败
                                //记录log
                                echo new Exception("verifyCertificat error:".$nResult);
                        }

                }catch (Exception $e){
                        //记录log
                        throw new Exception("verifyCertificat error:".$e);
                }

                return $nResult;
        }

        /**
         * 请求接口返回数据
         * @param $param
         * @return array
         */
        private function requestData($param)
        {
                try{
                        // 请求接口所以参数初始化
                        $data = [
                                'url'         => $this->apiUrl,          // 接口 url
                                'requestData' => $param['requestData'], // 请求接口参数
                                'headers'     =>$param['headers']
                        ];

                        $res = $this->httpPostRequest($data['url'],$data['headers'],$data['requestData']);

                } catch (\Exception $e) {
                        //记录log
                        throw new Exception("api requestData error :".$e);
                }

                return [
                        'status' => $res['info']['http_code'],
                        'body' => $res['body']
                ];
        }

        /**
         * curl post 请求方法
         *
         * @param string $url
         * @param array $header
         * @param array $requestData
         * @return array
         */
        private function httpPostRequest($url = '',$header = array(),$requestData = array()){
                $curl = curl_init();
                curl_setopt ( $curl, CURLOPT_HTTPHEADER,$header);
                curl_setopt($curl, CURLOPT_URL, $url);
                curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
                curl_setopt($curl, CURLOPT_POST, true);
                curl_setopt($curl, CURLOPT_POSTFIELDS,http_build_query($requestData));
                $res = curl_exec($curl);
                $info = curl_getinfo($curl);
                $error = curl_error($curl);
                curl_close($curl);

                return [
                        'body' => $res,
                        'info' => $info,
                        'error' => $error,
                ];
        }

}
//调用接口
$demoObj = new HuifuCFCA();
$data = $demoObj->apiRequest();

print_r('<pre/>');
print_r($data);

Python 代码示例

DEMO 下载

Demo 运行环境要求:Linux 64bit

1、Python要求:Python2.7/Python3.x

2、使用 pip 安装 cfcasign, 安装命令: pip install cfcasign-0.0.1.tar.gz

3、参考demo完成cfca加解签

python

 """CFCA Python SDK version Demo"""

 from cfcasign import CFCASignature

 import os

 if __name__ == '__main__':
 cfca_signature = CFCASignature()
  # 加签
  _return_code, sign = cfca_signature.get_sign(algorithm='rsa',
                                               source_data=__doc__,
                                               pfx_file_path=os.path.join('rsasigncert.pfx'),
                                               pfx_password='111111',
                                               hash_alg='sha-256'
                                          )
  print("sign return code: {0}".format(_return_code))
  print("sign value: {0}".format(sign))

  # 验签
  signature_base64 = b"TUlJR0pRWUpLb1pJaHZjTkFRY0NvSUlHRmpDQ0JoSUNBUUV4RHpBTkJnbGdoa2dCWlFNRUFnRUZBREFYQmdrcWhraUc5dzBCQndHZ0NnUUlWR1Z6ZEVSaGRHR2dnZ1JNTUlJRVNEQ0NBekNnQXdJQkFnSUZRQUtaZDNVd0RRWUpLb1pJaHZjTkFRRUxCUUF3WFRFTE1Ba0dBMVVFQmhNQ1EwNHhNREF1QmdOVkJBb1RKME5vYVc1aElFWnBibUZ1WTJsaGJDQkRaWEowYVdacFkyRjBhVzl1SUVGMWRHaHZjbWwwZVRFY01Cb0dBMVVFQXhNVFEwWkRRU0JCUTFNZ1ZFVlRWQ0JQUTBFek1UQWVGdzB4T0RBeE1UVXdORFE1TkRCYUZ3MHlNekF4TVRVd05EUTVOREJhTUhFeEN6QUpCZ05WQkFZVEFrTk9NUlV3RXdZRFZRUUtFd3hEUmtOQklGUkZVMVFnUTBFeEVUQVBCZ05WQkFzVENFeHZZMkZzSUZKQk1Sa3dGd1lEVlFRTEV4QlBjbWRoYm1sNllYUnBiMjVoYkMweE1SMHdHd1lEVlFRREZCUXdOVEZBUVZNd016Z3hRRTR4TVRFeE16QkFNVENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFOMlN3T0MyeDUwQkRMSXpHWGNJOFlUQ0VMTEVsTG5VUFNBZndNQi9zYXN0eWZ1WjFLQnQ5YlFSOEhhTkRVM0I4S0o2RVdEYTlYYUcyMStmT0hvViszOW1vV3E2Vm1jL2pHRDJMaUdneGJCWWgyUkkwakZFODdZQjIvZE1iT3JyT3E5SjViVHc5bVQ0L3BCbHF1Q0RLdlkwclpUdlVVb3loRW5TcWlaQ0lFY1hBall3T2l0UlovS0tkbU9pTUhrOXJ3ZTJhekhjZ1R5TGJiMzVDL2dIUjViZWRCVWNPbEhuUnh1N2pNSlgwbWxEaEFXOUo4c3E2ZHJ0eTVIRkxoTTR0VjVuUW1ES1JteEo5Ylk0WmRuaXpvdlg0NTJmNFJOYUs2TE4vQ1RYUWcvSkpmYzMxM3k3YitQSFJjSHFINlh6dnBXRHJhczNhbEtRMlBqVlhwQnRwcThDQXdFQUFhT0IrakNCOXpBL0JnZ3JCZ0VGQlFjQkFRUXpNREV3THdZSUt3WUJCUVVITUFHR0kyaDBkSEE2THk5dlkzTndkR1Z6ZEM1alptTmhMbU52YlM1amJqbzRNQzl2WTNOd01COEdBMVVkSXdRWU1CYUFGSm85dEs1bFdQdk9XZ1Y0SnFCdEt3U0d1c2JzTUF3R0ExVWRFd0VCL3dRQ01BQXdOd1lEVlIwZkJEQXdMakFzb0NxZ0tJWW1hSFIwY0Rvdkx6SXhNQzQzTkM0ME1pNHpMMDlEUVRNeEwxSlRRUzlqY213eU9TNWpjbXd3RGdZRFZSMFBBUUgvQkFRREFnYkFNQjBHQTFVZERnUVdCQlR0Szk2V2w4aTlDaThaV3ZEeUpZSWpuaStCMWpBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFnWUlLd1lCQlFVSEF3UXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBRGE2cVpuS1Ryak9HSWpoWXdMelY2N3VqMFJYbDMzcXNsNFpMSVY1Ym1BQ0dRWUVPSlpuaDZLcjhHNnI1TXBZK0k0S2ptNCtUNXlrSmNlRHoyMGJNa0lDMnlXREpoQW1kWjIrTEdXcE9wdnlka1hVaE5QNzZ5aFc2RzdSdGVUZllDSSsrYmhTdUd1TWRGSUNPN3VOSDN4d0lUUGhabjliWVR4dGxVbWh3MnU5U0ZXOG5oQVphdHd0VExJVUxXYmcwZ2lXbU5tcXNENVhiNG45U2xRVk9tTDBDd3o0Zkd3d2FoVG9Tait5aU82QmhwbFlyeWJuNHc2cXhtU0htMXhOYkJqSW05djYrV2EwcHFRbldGZ3VwZCtFMGYxYVphSmxYQi9wWkMyNzBGZEZyZ0hYdTBBNEFOZ0lTZjNJYU5RNk1mbUFDTm5BRGpSQVd2dFVZWTFCaEhVeGdnR1JNSUlCalFJQkFUQm1NRjB4Q3pBSkJnTlZCQVlUQWtOT01UQXdMZ1lEVlFRS0V5ZERhR2x1WVNCR2FXNWhibU5wWVd3Z1EyVnlkR2xtYVdOaGRHbHZiaUJCZFhSb2IzSnBkSGt4SERBYUJnTlZCQU1URTBOR1EwRWdRVU5USUZSRlUxUWdUME5CTXpFQ0JVQUNtWGQxTUEwR0NXQ0dTQUZsQXdRQ0FRVUFNQTBHQ1NxR1NJYjNEUUVCQVFVQUJJSUJBRGphRFEvUTduWnV0M041TUUvN2dQa1QyeG5aUS9tTERMTFVnWGhFSmRTUjg2RlkzaEd0TmE3SEVFb2tFbFF1MERPWHZEbFp3YU4xV0NmTHFCM3kraW4zazhTNzdOT2ZnNnVxcE1ENFc0YjdpZEgvR0hDTHQ5eWozYWMzdUNmQ3Ixc3doOW43QUxZYitMbGM3Sjd6TFJVajdFZ1pDc0NCd1VPTkZCRmkwVWg0c0d5VWhZM3NWN0tsV01saVpFSVhzV3YwT0VJODE4QVlYL1ErdFpvalEramZEYktRMkpVSVlNaC93UXA4WWE5Ty9oT3RVMTZIQUh5RWJTZXVML1o5QnFpVUYxQ2RZY3dVb3lWL1Nzend3eHR2eDlDRFB4YjI1dVhzMDBhdmFOZ1VKdElUZFlEazNObENhaXhvdy9nQkQ0V3VSZW9Sa3hxMGpVU3pIS1FLTXkwPQ=="

  _return_code, value = cfca_signature.check_sign(base64_signature=signature_base64, algorithm='rsa')
  print("check sign return code: {0}".format(_return_code))
  print("value: {0}".format(value))

# 验证证书
  _return_code = cfca_signature.verify_certificate(certificate_path='CFCA_ACS_TEST_CA.cer|CFCA_ACS_TEST_OCA31.cer',
                                             verify_level=4)
  print("check cer code: {0}".format(_return_code))

# 验签 + 证书
  value, _return_code = cfca_signature.check_sign_cer(base64_signature=signature_base64,
                                                 algorithm='rsa',
                                                 certificate_path='CFCA_ACS_TEST_CA.cer|CFCA_ACS_TEST_OCA31.cer',
                                                 verify_level=4)
print("value: {0}".format(value))
print("check cer code: {0}".format(_return_code))

C# 代码示例

DEMO 下载

Demo 运行环境要求:Windows Server 2008、 Windows Server 2012

SADK.Standard.x64.dll 为 CFCA 加解签 SDK,888888-NEW.pfx 为测试的加签证书(使用前请替换成商户的加签证书),将这两个文件拷贝到运行程序的根目录后运行 Demo。

项目中使用这两个文件时可以将 Sign.cs 文件中这两个文件的位置替换成实际文件的绝对路径。

c#

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace app_plus
{
        class Program
        {
                static void Main(string[] args)
                {
                        // mt();
                        // Test122();
                        Test202();
                }

                static void mt()
                {
                        string s = "{\"ordAmt\":\"420.00\",\"apiVersion\":\"2.0.0.1\",\"payChannelType\":\"W1\",\"appId\":\"wxa403cbc1ea66ee73\",\"isRaw\":\"1\",\"openId\":\"oVW8pwBOgVDD9fN0JNr4v69mP81M\",\"buyerLogonId\":\"\",\"buyerId\":\"\",\"merOperId\":\"shangshi01\",\"merPriv\":{\"merNoticeUrl\":\"https://pay.xiaogj.com/notify/chinapnrpay\"},\"termOrdId\":\"100054731905071000107418740333\",\"outOrdId\":\"100054731905071000107418740333\",\"goodsDesc\":\"网上商城订单\",\"memberId\":\"310000016000334222\",\"longitude\":\"\",\"latitude\":\"\",\"imei\":\"\",\"macIp\":\"\",\"softVersion\":\"\",\"osVersion\":\"\",\"bgRetURL\":\"\"}";
                        for (int i=0; i<10; i++)
                        {
                                new System.Threading.Thread(o =>
                                {
                                        Sign sg = new Sign();
                                        for (int j = 0; j < 100000; j++)
                                        {
                                                sg.sign(s);
                                        }
                                        Console.WriteLine("thread: completed");
                                }).Start();
                        }

                        while (true) ;
                }
                //122 文件上传demo
                static void Test122()
                {
                        string url = "https://apptrade.testpnr.com/api/fileMerchantRequest";
                        string version = "10";
                        string cmd_id = "122";
                        string mer_cust_id = "6666000000002619";
                        string attach_no = "abcd" + DateTime.Now.Ticks.ToString("x");
                        string file_name = "test.png";
                        string file_path = "C:\\" + file_name;

                        Dictionary<string, string> info = new Dictionary<string, string>();
                        info.Add("version", version);
                        info.Add("cmd_id", cmd_id);
                        info.Add("mer_cust_id", mer_cust_id);
                        info.Add("attach_no", attach_no);
                        info.Add("trans_type", "01");
                        info.Add("attach_type", "05");
                        info.Add("extension", "1");

                        string json_string = JsonConvert.SerializeObject(info, Formatting.None);
                        Sign sg = new Sign();
                        string check_value = sg.sign(json_string);

                        string boundary = "ABCD" + DateTime.Now.Ticks.ToString("x");
                        byte[] firstBoundaryBytes = System.Text.Encoding.ASCII.GetBytes("--" + boundary + "\r\n");
                        byte[] boundaryBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
                        byte[] endBoundaryBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--");

                        string url_with_param = url;
                        bool concat_start = true;
                        foreach (var key in info.Keys)
                        {
                                if (concat_start)
                                {
                                        url_with_param += "?";
                                        concat_start = false;
                                }
                                else
                                {
                                        url_with_param += "&";
                                }
                                url_with_param += key + "=" + info[key];
                        }
                        url_with_param += "&check_value=" + check_value;
                        HttpWebRequest request = request = (HttpWebRequest)WebRequest.Create(url_with_param);
                        request.Method = "post";
                        request.ContentType = "multipart/form-data; boundary=" + boundary;


                        string formItem;
                        byte[] formItemBytes;
                        Stream memStream = new System.IO.MemoryStream();

                        memStream.Write(firstBoundaryBytes, 0, firstBoundaryBytes.Length);
                        formItem = "Content-Disposition: form-data; " +
                                "name=\"attach_file\"; " +
                                "filename=\"" + file_name + "\"\r\n" +
                                "Content-Type: image/png\r\n\r\n";
                        formItemBytes = System.Text.Encoding.UTF8.GetBytes(formItem);
                        memStream.Write(formItemBytes, 0, formItemBytes.Length);
                        using (var fileStream = new FileStream(file_path, FileMode.Open, FileAccess.Read))
                        {
                                byte[] buffer = new byte[1024];
                                int bytesRead = 0;
                                while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                                {
                                        memStream.Write(buffer, 0, bytesRead);
                                }
                        }
                        memStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
                        request.ContentLength = memStream.Length;

                        using (var requestStream = request.GetRequestStream())
                        {
                                memStream.Position = 0;
                                byte[] tempBuffer = new byte[memStream.Length];
                                memStream.Read(tempBuffer, 0, tempBuffer.Length);
                                memStream.Close();
                                requestStream.Write(tempBuffer, 0, tempBuffer.Length);
                        }

                        string responseText = null;
                        try
                        {
                                HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
                                using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
                                {
                                        responseText = streamReader.ReadToEnd();
                                        Dictionary<string, string> responseJson = (Dictionary<string, string>)JsonConvert.DeserializeObject<Dictionary<string, string>>(responseText);
                                        responseText = responseJson["check_value"];
                                        responseText = sg.unsign(responseText);
                                }
                        }
                        catch (WebException e)
                        {
                                if (e.Response != null)
                                {
                                        using (var errorResponse = (HttpWebResponse)e.Response)
                                        {
                                                using (var reader = new StreamReader(errorResponse.GetResponseStream()))
                                                {
                                                        responseText = reader.ReadToEnd();
                                                }
                                        }

                                }
                        }
                        Console.WriteLine(responseText);
                        while (true) ;
                }
                //122 取现demo
                static void Test202()
                {
                        string url = "https://apptrade.testpnr.com/api/merchantRequest";
                        string version = "10";
                        string cmd_id = "202";
                        string mer_cust_id = "6666000000002619";

                        Dictionary<string, string> info = new Dictionary<string, string>();
                        info.Add("version", version);
                        info.Add("cmd_id", cmd_id);
                        info.Add("mer_cust_id", mer_cust_id);
                        info.Add("user_cust_id", "6666000000002959");
                        info.Add("order_date", "20181026");
                        info.Add("order_id", "201673233703");
                        info.Add("trans_amt", "0.39");
                        info.Add("cash_bind_card_id", "65334");
                        info.Add("fee_obj", "02050200");
                        info.Add("fee_acct_id", "2744");
                        info.Add("cash_type", "02030000");
                        info.Add("bg_ret_url", "http://192.168.0.74:8001/npayCallBack/asyncHandle.json");
                        info.Add("mer_priv", "test_mer_priv");
                        info.Add("extension", "test_extension");

                        string json_string = JsonConvert.SerializeObject(info, Formatting.None);
                        Sign sg = new Sign();
                        string check_value = sg.sign(json_string);
                        json_string = sg.unsign(check_value);

                        HttpWebRequest request = request = (HttpWebRequest)WebRequest.Create(url);
                        request.Method = "post";
                        request.ContentType = "application/x-www-form-urlencoded";

                        using (var streamWriter = new StreamWriter(request.GetRequestStream()))
                        {
                                string requestText = "version=" + version + "&" +
                                        "cmd_id=" + cmd_id + "&" +
                                        "mer_cust_id=" + mer_cust_id + "&" +
                                        "check_value=" + check_value;

                                streamWriter.Write(requestText);
                                streamWriter.Flush();
                                streamWriter.Close();
                        }

                        string responseText = null;
                        try
                        {
                                HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();
                                using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
                                {
                                        responseText = streamReader.ReadToEnd();
                                        Dictionary<string, string> responseJson = (Dictionary<string, string>)JsonConvert.DeserializeObject<Dictionary<string, string>>(responseText);
                                        responseText = responseJson["check_value"];
                                        responseText = sg.unsign(responseText);
                                }
                        } catch (WebException e) {
                                if (e.Response != null) {
                                        using (var errorResponse = (HttpWebResponse)e.Response)
                                        {
                                                using (var reader = new StreamReader(errorResponse.GetResponseStream()))
                                                {
                                                        responseText = reader.ReadToEnd();
                                                }
                                        }
                                }
                        }
                        Console.WriteLine(responseText);
                        while (true) ;
                }
        }
}

证书下载操作指引

安装证书控件

非IE浏览器下,点击邮件中的申请链接,登录安全证书下载控台。首次登录需要安装证书控件,系统提示如下图。点击【确定】,下载保存证书控件到本地,并安装。

_images/cfca_browser_alert.png
  • 安装过程中如果弹出如下的提示框,一定要选择允许。
_images/cfca_browser_bottom.png
  • 安装完成后,重起浏览器。
_images/cfca_finish.png

IE 浏览器下,进入邮件中的申请链接地址,输入联系人手机号,获取验证码(下载测试证书时,验证码随便输入4位,不做校验)。

_images/cfca_login.jpg
  • 点击【下载证书】,系统会自动下载安装。
_images/cfca_download1.jpg
  • 安装成功后提示。(注意不要忘记下载右边的【用户指南cer文件】来获取cer证书哦!
_images/cfca_success.png

导出加签证书

  • 点击浏览器菜单栏“工具”菜单,单击“Internet选项”。
_images/cfca_export.png
  • 在弹出的对话框中点击【内容】选项卡,单击【证书】按钮。
_images/cfca_export_alert.png
  • 选中之前安装的证书,点击【导出】。
_images/cfca_export_select.png
  • 选择导出私钥,点击【下一步】。
_images/cfca_export_private_key.png
  • 选择“个人信息交换”,下属二级选项可根据实际需要勾选,建议全选。点击【下一步】。
_images/cfca_export_private_key2.png
  • 输入并确认密码,点击【下一步】。

注意:请记下这里输入的密码,调用加签方法时需要用到这个密码

_images/cfca_success.png
  • 指定文件名和存放路径。点击【浏览】可更改存放路径,选择完成后点击【下一步】。
_images/cfca_export_save.png
  • 点击【完成】,获得 pfx 文件。
_images/cfca_export_finish.png

下载解签证书

_images/cfca_download2.png
  • 点击【用户指南 cer 文件】,系统会自动下载解签证书。

    CFCA_ACS_TEST_OCA31.cer 为测试环境用的解签证书,CFCA_ACS_OCA31.cer 为生产环境用的解签证书。

手机 SDK

APP+ SDK 提供了多种主流支付渠道,商户只需要一次接入即可完成多个渠道的接入。APP+ SDK 适配了 Android、iOS 移动端平台。

相关组件下载

Android SDK

iOS SDK

流程说明

_images/sdk_flow2.png

接入步骤

  • 第一步:下载SDK,并按照SDK中的接入说明文档集成SDK;
  • 第二步:联系商务申请配置SDK密钥;
  • 第三步:SDK中更换成贵司获取的商户客户号、SDK密钥、以及其他必要的参数,然后进行交易。

快捷支付接口

商户服务端提供此接口给客户端 SDK 调用。当商户 APP 发起快捷支付时,客户端 SDK 会调用此接口,跳转到汇付的快捷支付页面,用户完成支付后跳转支付结果页面。

调用方式:页面提交方式

请求参数

参数中文名称 参数名称 数据格式 是否必须 说明
设备号 device_info 变长32位 可选  
IP地址 ip_addr 变长20位 可选  
经纬度 location_val 变长20位 可选  
设备信息 dev_info_json 变长2000位 可选 该字段是由客户端 SDK 调用商户此接口时,传过来的。服务端请将该参数透传给快捷支付( APP 版)接口
支付参数 self_param_info   可选 该字段是商户的 APP 调用 客户端 SDK 时传的参数,再由客户端 SDK 透传给此接口。此字段内容商户可以自定义
扩展域 extension 变长512位 可选 用于扩展请求参数

返回参数

返回结果页面

注:如果商户服务端请求支快捷支付时传的 ret_url 不为空,则跳转到商户的 ret_url,由商户解签处理快捷支付结果。否则跳转到 APP+ 的结果页面,商户不需要处理快捷支付同步接口,只需要接收并处理异步消息。

APP 支付接口

商户服务端提供此接口给客户端 SDK 调用。当商户 APP 发起微信或者支付宝支付时,客户端 SDK 会调用此接口,获取微信或者支付宝的支付参数,然后再唤起微信或者支付宝支付。

调用方式:系统调用

请求参数

参数中文名称 参数名称 数据格式 是否必须 说明
设备号 device_info 变长32位 可选  
IP地址 ip_addr 变长20位 可选  
经纬度 location_val 变长20位 可选  
设备信息 dev_info_json 变长2000位 可选 该字段是由客户端 SDK 调用商户此接口时,传过来的。服务端请将该参数透传给 APP 支付接口
支付类型 pay_type 定长2位 必须 15:支付宝;10 : 微信APP支付;
支付参数 self_param_info   可选 该字段是商户的 APP 调用 客户端 SDK 时传的参数,再由客户端 SDK 透传给此接口。此字段内容商户可以自定义
扩展域 extension 变长512位 可选 用于扩展请求参数

返回参数

参数中文名称 参数名称 数据格式 是否必须 说明
应答返回码 resp_code 定长6位String 必须 218002:请求已受理;218003:交易失败;218098:系统超时;其他请参考 APP支付返回码
应答返回描述 resp_desc 变长String 必须 返回码的对应中文描述
支付地址 pay_url 变长1024位 必须 用于支付宝支付
支付信息 pay_info 定长16位String 必须 用于微信APP支付
扩展域 extension 变长512位的String 可选  

注意事项:

1、请将返回参数以 json 格式写入到 response 对象的 body 区,且 body 区只有返回参数,如果是 java 开发则可以添加注解@ResponseBody

body区格式:

%7B%22pay_url%22%3A%22%22%2C%22resp_desc%22%3A%22%E4%BA%8C%E7%BA%A7%E5%95%86%E6%88%B7%E5%8F%B7%E4%B8%8D%E5%AD%98%E5%9C%A8%22%2C%22platform_seq_id%22%3A%22%22%2C%22resp_code%22%3A%22218748%22%2C%22pay_info%22%3A%22%22%2C%22token_id%22%3A%22%22%2C%22order_id%22%3A%22TEST1513827504986%22%2C%22order_date%22%3A%2220171221%22%7D

2、为了防止乱码,返回参数需要做URLEncoder转码

更新记录

2021.11.03 v3.4.6

  • 新增省市县地区代码

2021.10.27 v3.4.5

  • 218银联正扫优化

2021.05.27 v3.4.4

  • 122上传文件新增类型:19-活体验证

2021.04.06 v3.4.3

  • 冻结比例优化

2021.03.25 v3.4.2

  • 交易类增加相关字段

2021.03.18 v3.4.1

  • 开户类增加相关字段

2021.02.02 v3.4.0

  • 156 新增申请商户接口
  • 155 新增手机pos交易结果通知

2021.01.28 v3.3.9

  • 154 碰一碰交易结果通知字段可选优化

2020.11.30 v3.0.3.6

  • 新增161 快捷绑卡cvv2版聚合版一阶段短信发送
  • 新增162 快捷绑卡cvv2版聚合版二阶段绑卡+支付

2020.11.26 v3.3.7

  • 160 快捷小额免密支付接口新增请参:tm_type,remark1,remark2

2020.11.04 v3.3.6

  • 160 新增快捷小额免密支付接口

2020.06.30 v3.3.5

  • 154 碰一碰交易结果通知新增返参标签id:nfc_tag_id

2020.06.19 v3.3.4

  • 150 新增申请标签数据接口
  • 151 新增停用标签数据接口
  • 152 新增修改标签数据接口
  • 153 新增标签数据查询接口
  • 154 新增碰一碰交易结果通知

2020.06.04 v3.3.3

  • 129 新增银行卡四要素验证接口
  • 106 删除独立验卡接口
  • 134 新增个人用户信息修改接口

2020.05.14 v3.3.2

  • 128 新增短信验证接口
  • 211 新增刷脸支付后台版接口

2020.05.08 v3.3.1

  • 企业网银支持列表增加兰州银行和甘肃银行

2020.04.08 v3.3.0

  • 210 新增刷脸支付接口
  • 301 交易状态查询接口增加刷脸交易查询类型trans_type:28

2019.12.13 v3.2.9

  • 218 APP支付接口新增支付类型14:APPLE PAY

2019.11.28 v3.2.8

  • 下线 215 反扫消费接口和223 反扫撤销接口

2019.10.28 v3.2.7

  • 参数规范新增说明

2019.07.31 v3.2.6

  • 104 取现绑卡/811 取现绑卡代开户请参银行代号bank_id设置可选
  • 111 绑卡短信发送接口请参银行代号bank_id设置定长8位

2019.07.17 v3.2.5

  • 203、301接口返回参数新增手续费金额字段

2019.06.29 v3.2.4

  • 更新所有涉及设备信息的接口

2019.06.25 v3.2.3

2019.03.27 v3.2.2

  • 204 接口新增 pay_type 交易类型返回参数

2019.03.21 v3.2.1

  • 209、218接口新增 limit_pay 是否禁用贷记卡字段

2019.03.14 v3.2.0

  • 102、125、120 接口更新股东信息说明

2019.02.01 v3.1.9

  • 120 接口请求参数新增结算卡标志 card_type 参数

2019.01.22 v3.1.8

2019.01.17 v3.1.7

  • 812接口请求参数说明修改
  • 118接口功能说明优化,以及参数描述优化
  • 附件中新增网银支付接口参数gate_id网关列表
  • 证书下载指引图片更换
  • 102、125接口控股股东参数描述修改

2019.01.10 v3.1.6

  • 企业开户后台版接口股东信息改为必传
  • 849接口名称改为签约代扣支付接口以及sign_seq_id参数说明修改
  • 102、125、124、122添加企业用户、个体户上传附件材料的要求说明
  • 316接口参数描述修改
  • 101个人开户接口增加个人职业分类信息
  • 102、125企业开户接口增加行业列表信息

2019.01.03 v3.1.5

2018.12.29 v3.1.4

2018.12.21 v3.1.3

  • 120接口部分参数改为必传
  • 850、849、825、847、814、811接口bg_ret_url描述修改
  • 接入指南新增 自助联调开放平台

2018.12.20 v3.1.2

  • 216接口补加tm_type字段
  • 847接口去掉充值类型中的个人网银 和 交易类型中的免注册网银支付
  • 增加接入指南中 调用接口url中的描述信息

2018.12.14 v3.1.1

2018.12.07 v3.1.0

2018.11.20 v3.0.9

2018.10.23 v3.0.6

2018.09.28 v3.0.5

2018.09.11 v3.0.3.1

2018.09.06 v3.0.3

2018.09.04 v3.0.2

2018.08.16 v3.0.1

2018.08.13 v1.1.8

  • 银行卡解绑接口 短信验证码日期、短信验证码订单号和短信验证码修改为非必传

2018.07.19 v1.1.7

2018.04.02 v1.1.4

2018.02.02 v1.1.3

2018.01.24 v1.1.1

2017.12.27 v1.1.0