开发说明¶
企账通采用了 HTTP 协议提供各类接口,所有接口都是统一请求地址,方便商户简单、快速接入。本 API 包含 2 种调用方式,页面浏览器类和系统调用类。
- 页面浏览器类:需要从前端页面以 Form 表单的形式发起请求,浏览器会自动跳转至汇付的相关页面(如网银支付),用户在该页面完成相关业务操作后再回跳到商户指定页面,页面方式返回的是标准的表单格式。
- 系统调用类:直接从服务端发起 HTTP 请求,API 会同步返回请求结果,返回的数据格式都是规范 JSON 格式。
参数规范¶
- 所有参数值不应该包含与 JSON 格式冲突的特殊字符,如括号,逗号,双引号,冒号等;
- 金额单位为元,精确到分,如:1200.00,359.14;
- 订单日期为定长 8 位的字符串,格式为 YYYYMMDD,如 20140802;
- 订单号为变长 20 位的字符串,必须为纯数字;
- 参数为可选项时,JSON 格式中可以不包含该参数,或该参数内容为空;
订单规范¶
通过商户客户号、订单号、订单日期来标识订单的唯一性,所有接口下唯一;
由于网络的不稳定性等原因,相同订单的交易应答返回给商户时,有可能会出现以下两种情况:
1.同一订单请求多次,先支付完成的订单返回参数后通知到商户;
2.同一笔订单收到多次支付结果;
处理原则:商户以订单的成功状态为终态,商户收到订单支付成功的应答后,如果再次收到订单支付失败的应答,不做处理即可。
API 调用规范¶

举例说明:假设接口参数为: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"}
第二步:将第一步的 JSON 字符串使用 pfx 证书和密码进行加密,生成 check_value。
SignResult signResult = CFCASignature.signature(pfxFile, pfxFilePwd, params, "utf-8");
String check_value = signResult.getSign();
第三步:组装请求参数 version、cmd_id、mer_cust_id 和 check_value,以 post 方式请求接口。
String postStr = "cmd_id=101&version=10&mer_cust_id=6666000000011499&check_value=第二步生成的加签串";
HttpRequest httpRequest = HttpRequest.post("http://mertest.chinapnr.com/npay/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 应答接收规范

举例说明(以交易状态查询接口返回的数据为例):
第一步:从应答报文中取得 check_value
假设返回数据如下:
{"check_value":"B170E66B00D344F8CEA68C3A84F0ED2207805147793F806CBD3D3E166B57F511ABEB7D5D7A725ECEFDC640FDC2F7102CD8D470CB0BE18A3B4ADE870689D7FCBD4CA55DD5C2E1D6BFC3F30514B0813D8E680708B44A1C1637780CA0D998EF22C10B7E4B8954F304F226BB50F091A60C939F7C4DB513261FC47667757550C7911E"}
第二步:解签 check_value,并取得返回参数
将第一步取得的 check_value,使用 cer 证书文件和汇付的商户号(100001)进行解签,解签结果如:
VerifyResult{code='000', message='验签成功', content=[101, 121, 74, 106, 97, 71, 86, 106, 97, 49, 90, 104, 98, 72, 86, 108, 73, 106, 111, 57]}
在对 content 进行UTF-8编码转换成字符串,得到返回参数的 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 进行签名,篡改签名将导致验签失败,交易无法正常进行;
- 商户可以动态地将每笔交易的返回地址指向不同的交易网站,适合于多网站和多应用的商户;
- 商户在接口中可以自定义域,本平台返回时,会将该域原样返回,供商户实现特定的功能;
- 本平台通过后台方式向商户发送交易结果,通过分析商户的返回页面,可以准确地知道商户是否收到交易应答结果,从而对发送失败的交易采取自动重发;
加解签简介¶
本 API 对商户与汇付之间请求数据采用的是 CFCA 证书加解签方式。测试时开发人员可以在开发者站点申请下发测试用的证书。生产环境的证书是在正式商户开通后,由汇付中台人员下发的。下发证书后,商户联系人邮箱会收到如下图的邮件通知。

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

- 安装过程中如果弹出如下的提示框,一定要选择允许。

- 安装完成后,重起浏览器。

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

- 点击【下载证书】,系统会自动下载安装。

- 安装成功后提示。

导出加签证书
- 点击浏览器菜单栏“工具”菜单,单击“Internet选项”。

- 在弹出的对话框中点击【内容】选项卡,单击【证书】按钮。

- 选中之前安装的证书,点击【导出】。

- 选择导出私钥,点击【下一步】。

- 选择“个人信息交换”,下属二级选项可根据实际需要勾选,建议全选。点击【下一步】。

- 输入并确认密码,点击【下一步】。
注意:请记下这里输入的密码,调用加签方法时需要用到这个密码

- 指定文件名和存放路径。点击【浏览】可更改存放路径,选择完成后点击【下一步】。

- 点击【完成】,获得 pfx 文件。

下载解签证书

点击【用户指南 cer 文件】,系统会自动下载解签证书。
CFCA_ACS_TEST_OCA31.cer 为测试环境用的解签证书,CFCA_ACS_OCA31.cer 为生产环境用的解签证书。
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 "加签失败";
}
}
验签示例
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 "验签失败";
}
}
PHP 代码示例( Linux 版)¶
解压后,参考 phplinux/v3.4.0.1/文档/PHP版服务器端工具包(Linux版)软件使用手册.pdf
Demo 运行
1.安装对应版本的 PHP
2.安装运行时环境(glibc 库等)
3.修改 PHP 的配置文件 php.ini 修改 php.ini,使 php 允许加载扩展,并将当前扩展添加到其扩展列表中 enable_dl = On extension=libSADKExtension.so.3.4.0.1
4.在 DemoRSA 目录下替换证书和 cer 文件 pfx 为私钥文件请妥善保管不要泄露给他人 cer 文件为颁发者公钥,用来验证汇付公钥
5.配置 cfcalog.conf cfca 日志文件
6.通过命令行终端运行 Demo 文件 php huifuCFCALinuxDemo.php
Msg PKCS7-attached Sign | 为使用 pfx 证书加签 |
PKCS7-attached-Verify | 为验证汇付的签名 |
cfca_verifyCertificate | 为验证证书链合法性 |
cfca_getCertificateInfo | 为获取证书信息(非必要) |
php
<?php
class HuifuCFCA
{
private $apiUrl = 'https://eacloud.testpnr.com/api/publicRequests'; //企账通商户交易接口,此处使用的是联调环境地址
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");
}
}
/**
* 调用接口 此处是企账通的接口请求
*
* @return string
*/
public function apiRequest(){
//请求参数,依据商户自己的参数为准
$requestParam['version'] = '10';
$requestParam['cmd_id'] = 'Q01'; //交易订单查询
$requestParam['mer_cust_id'] = '6666000000002619';
$requestParam['user_cust_id'] = '6666000000054387';
$requestParam['order_date'] = '20180918';
$requestParam['order_id'] = '201809189000001';
$requestParam['trans_type'] = '01';
$requestParam['mer_priv'] = '';
//加签
$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 版)¶
解压后,参考 phpwindows/v3.4.0.1/程序/Demo/接入步骤.txt
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
class HuifuCFCA
{
private $apiUrl = 'https://eacloud.testpnr.com/api/publicRequests'; // 企账通交易接口,此处使用的是联调环境地址
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);
}
/**
* 调用接口 此处是企账通的接口请求
*
* @return string
*/
public function apiRequest(){
//请求参数,依据商户自己的参数为准
$requestParam['version'] = '10';
$requestParam['cmd_id'] = 'Q01'; //交易订单查询
$requestParam['mer_cust_id'] = '6666000000002619';
$requestParam['user_cust_id'] = '6666000000054387';
$requestParam['order_date'] = '20180918';
$requestParam['order_id'] = '201809189000001';
$requestParam['trans_type'] = '01';
$requestParam['mer_priv'] = '';
//加签
$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);
?>
结果返回机制¶
接口中提供“商户前台应答地址ret_url”,“商户后台应答地址bg_ret_url”,向用户反馈接口处理结果
- 商户前台应答地址ret_url,商户通过此参数传入商户侧的页面展示页面,汇付交易受理完跳转到该地址展示受理结果。
- 商户后台应答地址bg_ret_url,对于交易异步产生终态结果的,商户通过此参数传入后台结果回调地址,汇付在交易处理完毕后通过调用该地址通知商户交易的终态结果。