合利宝公共产品接口
概述
公共产品包含三个独立接口:商户余额查询、商户对账单下载、订单电子回单获取。 三个接口使用不同的请求地址,签名方式要求也不同。
接口决策表
| 接口 | P1_bizType | 请求地址(测试/生产) | 签名方式 |
|------|------------|----------------------|----------|
| 商户余额查询 | MerchantAccountQuery | http://test.trx.helipay.com/trx/merchant/interface.action<br>http://pay.trx.helipay.com/trx/merchant/interface.action | MD5 或 SM3WITHSM2(二选一) |
| 商户对账单 | DownloadMerchantBillNew | http://test.trx.helipay.com/trx/merchantStatement/interface.action<br>http://pay.trx.helipay.com/trx/merchantStatement/interface.action | 仅 MD5 |
| 电子回单 | MerchantTradeCertificateQuery | http://test.trx.helipay.com/trx/tradeCertificate/interface.action<br>http://pay.trx.helipay.com/trx/tradeCertificate/interface.action | 仅 MD5 |
三个接口地址完全不同,切勿混用。
请求通用规则
| 项目 | 说明 |
|------|------|
| 请求方法 | POST |
| 请求格式 | application/x-www-form-urlencoded(form 表单) |
| 字符编码 | UTF-8 |
签名规则
固定不参与签名的字段:
| 字段名 | 变量名 |
|--------|--------|
| 签名结果 | sign |
| 签名方式 | signatureType |
| 对账/回单接口特殊排除 | P5_cutNumber、P6_pdesc(对账接口文档明确标注排除签名) |
拼接规则:
- 参与签名的字段按变量名顺序拼接:
&P1值&P2值&P3值... - 空值字段也要保留连接符
- 中文不需要 URL Encode
- 尾部处理:
- MD5 签名:尾部追加
&+MD5 签名秘钥 - SM3WITHSM2 国密(仅余额查询支持):不追加任何内容
- MD5 签名:尾部追加
sign = Md5(待签名串&商户密钥)或 SM3withSM2 签名
签名秘钥获取:登录商户后台 → 产品管理 → 产品列表 → 公共产品 → 接口配置 → 签名秘钥 → 发送到邮箱。
接口一:商户余额查询
请求参数
| 字段名 | 变量名 | 必填 | 说明 |
|--------|--------|------|------|
| 交易类型 | P1_bizType | 是 | 固定 MerchantAccountQuery |
| 商户编号 | P2_customerNumber | 是 | 合利宝分配的商户号 |
| 时间戳 | P3_timestamp | 是 | 格式 yyyyMMddHHmmss,14位精确到秒 |
| 签名方式 | signatureType | 否 | MD5 或 SM3WITHSM2(不传默认 MD5) |
| 签名 | sign | 是 | 签名结果 |
返回参数
| 字段名 | 变量名 | 说明 | 参与签名 |
|--------|--------|------|----------|
| 交易类型 | rt1_bizType | MerchantAccountQuery | 是 |
| 返回码 | rt2_retCode | 0000=成功 | 是 |
| 返回信息 | rt3_retMsg | 成功/失败描述 | 是 |
| 商户编号 | rt4_customerNumber | 合利宝商户号 | 是 |
| 账户状态 | rt5_accountStatus | AVAILABLE/FROZEN/CANCELLED 等 | 是 |
| 账户余额 | rt6_balance | 元为单位 | 是 |
| 冻结余额 | rt7_frozenBalance | 因风控冻结的金额 | 是 |
| D0余额 | rt8_d0Balance | 元为单位 | 是 |
| T1余额 | rt9_T1Balance | 元为单位 | 是 |
| 币种 | rt10_currency | CNY | 是 |
| 创建时间 | rt11_createDate | yyyy-MM-dd HH:mm:ss | 是 |
| 备注 | rt12_desc | 备注信息 | 是 |
| D1余额 | rt13_d1Balance | 元为单位 | 否 |
| 充值金额 | rt14_rechargeBalance | 根据结算周期清0 | 否 |
| 可结算金额 | rt15_amountToBeSettled | 商户可出款金额 | 否 |
| 签名 | sign | MD5 或 SM3withSM2 结果 | 否 |
| 签名方式 | signatureType | MD5 或 SM3WITHSM2 | 否 |
返回示例(JSON)
{
"rt1_bizType": "MerchantAccountQuery",
"rt2_retCode": "0000",
"rt3_retMsg": "成功",
"rt4_customerNumber": "C1800000002",
"rt5_accountStatus": "AVAILABLE",
"rt6_balance": "100.50",
"rt7_frozenBalance": "0.00",
"rt8_d0Balance": "10.00",
"rt9_T1Balance": "90.50",
"rt10_currency": "CNY",
"rt11_createDate": "2017-06-20 14:02:17",
"rt12_desc": "备注信息",
"rt13_d1Balance": "0.00",
"rt14_rechargeBalance": "0.00",
"rt15_amountToBeSettled": "100.50"
}
账户状态说明
| 状态值 | 含义 | |--------|------| | AVAILABLE | 正常 | | FROZEN | 冻结 | | FREEZE_DEBIT | 冻结出帐 | | FREEZE_CREDIT | 冻结入账 | | CANCELLED | 已注销 |
接口二:商户对账单下载
重要限制
- 对账单只能在第二天早上 6 点后下载
- 对账时间限定:一个月内且不能是当前日期
- 超过每天下载次数限制会返回 0007
请求参数
| 字段名 | 变量名 | 必填 | 说明 | 参与签名 |
|--------|--------|------|------|----------|
| 交易类型 | P1_bizType | 是 | 固定 DownloadMerchantBillNew | 是 |
| 商户编号 | P2_customerNumber | 是 | 合利宝分配的商户号 | 是 |
| 对账单类型 | P3_productCode | 是 | 见对账单类型表 | 是 |
| 对账日期 | P4_billDate | 是 | 格式 yyyyMMdd,8位数字 | 是 |
| 分割序号 | P5_cutNumber | 否 | 00-23,按小时分割 | 否(排除签名) |
| 备注 | P6_pdesc | 否 | 定时结算账单必填 | 否(排除签名) |
| 签名 | sign | 是 | MD5 签名结果 | 否 |
对账单类型编码
| 编码 | 说明 | 编码 | 说明 | |------|------|------|------| | 01 | 快捷账单 | 15 | 钱包产品账单 | | 02 | 代扣账单 | 16 | 大额转账账单 | | 03 | 网银账单 | 17 | 移动收银台账单 | | 04 | 扫码账单 | 18 | 通用收银台账单 | | 05 | 鉴权账单 | 19 | 提现账单 | | 06 | 代付账单 | 20 | 延时分账账单 | | 07 | 全业务账单 | 21 | 账户支付账单 | | 08 | 虚拟账户支付账单 | 22 | 社保卡支付账单 | | 09 | POS账单 | 23 | 银联收银台账单 | | 10 | 结算账单 | 25 | 转账充值账单 | | 11 | 委托代付订单 | 26 | 充值账单 | | 12 | 网银代付账单 | 27 | 扫码管控账单 | | 13 | 商户转账账单 | 28 | 分账收账方 | | | | 29 | 全业务-账务 |
如何拿到对账单文件
接口成功时返回的是 gzip 压缩的二进制流,处理流程:
HTTP Response(二进制流)
↓ 1. 从 Response Header 获取 r_code 判断是否 0000(成功)
↓ 2. 将 Response Body 的二进制流写入文件(.gz 格式)
↓ 3. 用 gzip 解压该文件
↓ 4. 获得 CSV 格式纯文本文件(GBK 编码)
↓ 5. 解析 CSV:第一行标题、第二行汇总、第三行起交易数据
关键代码:
// 1. 发起 POST 请求,接收原始二进制响应
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost post = new HttpPost(url);
// ... 设置 form 参数
CloseableHttpResponse response = httpClient.execute(post);
// 2. 从 Response Header 判断是否成功
Header rCodeHeader = response.getFirstHeader("r_code");
String rCode = rCodeHeader != null ? rCodeHeader.getValue() : "";
if (!"0000".equals(rCode)) {
Header rMsgHeader = response.getFirstHeader("r_msg");
String rMsg = rMsgHeader != null ? URLDecoder.decode(rMsgHeader.getValue(), "UTF-8") : "";
// 对账失败,根据 r_code 和 r_msg 排查
return;
}
// 3. 读取 gzip 压缩的二进制流
Header contentLength = response.getFirstHeader("Content-Length");
byte[] gzBytes = EntityUtils.toByteArray(response.getEntity());
// 4. 写入 .gz 文件
Files.write(Paths.get("bill.gz"), gzBytes);
// 5. 解压获得 CSV(GBK 编码)
try (GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(gzBytes));
InputStreamReader isr = new InputStreamReader(gis, "GBK");
BufferedReader reader = new BufferedReader(isr)) {
String line;
while ((line = reader.readLine()) != null) {
// 解析 CSV 行数据
}
}
// 6. 可选:验证文件完整性
// r_digest = MD5(文件字节数组 + 商户密钥字节数组)
Header rDigestHeader = response.getFirstHeader("r_digest");
String expectedDigest = rDigestHeader != null ? rDigestHeader.getValue() : "";
String actualDigest = DigestUtils.md5Hex(ByteArrayUtils.concatenate(gzBytes, md5Key.getBytes()));
// 比对 expectedDigest 和 actualDigest
返回响应头
| 字段名 | 说明 |
|--------|------|
| r_code | 返回码,0000=成功 |
| r_msg | 返回信息(需 URLDecoder.decode(x, "UTF-8") 解码) |
| Content-Length | 压缩文件大小(字节) |
| r_digest | 文件 MD5 签名,用于验证文件完整性 |
文件签名验证
r_digest = MD5(文件字节数组 + 商户密钥字节数组)
接口三:电子回单获取
请求参数
| 字段名 | 变量名 | 必填 | 说明 |
|--------|--------|------|------|
| 交易类型 | P1_bizType | 是 | 固定 MerchantTradeCertificateQuery |
| 商户编号 | P2_customerNumber | 是 | 合利宝分配的商户号 |
| 产品类型 | P3_productCode | 是 | 见产品类型表 |
| 商户订单号 | P4_orderNum | 是 | 商户系统内部订单号,50字符以内 |
| 签名 | sign | 是 | MD5 签名结果 |
产品类型编码
| 编码 | 说明 | 编码 | 说明 | |------|------|------|------| | ONLINE | 网银 | TRANSFER | 代付 | | RECHARGE | 充值 | ACCOUNT_PAY | 虚拟账户支付 | | SETTLEMENT | 结算 | ACCOUNT_TRANSFER | 转账 | | ONLINETRANSFERPAY | 收款代付 | LARGEPAYMENT | 大额转账 | | APPPAY | 扫码 | QUICKPAY | 快捷 |
如何拿到回单图片
接口成功时返回的是 JPEG 格式的二进制图片流,处理流程:
HTTP Response(JPEG 二进制流)
↓ 1. 从 Response Header 获取 r_code 判断是否 0000(成功)
↓ 2. 将 Response Body 的二进制流写入文件(.jpg 格式)
↓ 3. 文件即为电子回单图片,可直接展示或存储
关键代码:
// 1. 发起 POST 请求,接收原始二进制响应
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost post = new HttpPost(url);
// ... 设置 form 参数
CloseableHttpResponse response = httpClient.execute(post);
// 2. 从 Response Header 判断是否成功
Header rCodeHeader = response.getFirstHeader("r_code");
String rCode = rCodeHeader != null ? rCodeHeader.getValue() : "";
if (!"0000".equals(rCode)) {
Header rMsgHeader = response.getFirstHeader("r_msg");
String rMsg = rMsgHeader != null ? URLDecoder.decode(rMsgHeader.getValue(), "UTF-8") : "";
// 获取回单失败,根据 r_code 排查
return;
}
// 3. 读取 JPEG 二进制流
byte[] imageBytes = EntityUtils.toByteArray(response.getEntity());
// 4. 写入图片文件
String filename = "receipt.jpg";
// 可从 Content-Disposition header 获取文件名
Header disposition = response.getFirstHeader("Content-Disposition");
if (disposition != null) {
String cd = disposition.getValue(); // 如: attachment;filename=p_20191018095004.jpg
// 解析提取 filename
}
Files.write(Paths.get(filename), imageBytes);
// 5. 可选:验证文件完整性
// r_digest = MD5(图片字节数组 + 商户密钥字节数组)
Header rDigestHeader = response.getFirstHeader("r_digest");
String expectedDigest = rDigestHeader != null ? rDigestHeader.getValue() : "";
返回响应头
| 字段名 | 说明 |
|--------|------|
| r_code | 返回码,0000=成功 |
| r_msg | 返回信息(需 URLDecoder.decode(x, "UTF-8") 解码) |
| Content-Length | 图片文件大小(字节) |
| r_digest | 文件 MD5 签名,用于验证文件完整性 |
| Content-Disposition | 如 attachment;filename=p_20191018095004.jpg |
| Content-Type | image/* |
文件签名验证
r_digest = MD5(图片字节数组 + 商户密钥字节数组)
返回码汇总
| 返回码 | 描述 | 适用接口 | |--------|------|----------| | 0000 | 成功 | 全部 | | 9999 | 失败 | 对账 | | 0001 | 输入参数错误 | 全部 | | 0002 | 非法接口名称 | 全部 | | 0003 | 账单不存在 | 对账 | | 0004 | 对账未开通或已关闭 | 对账 | | 0005 | 未激活产品对账功能 | 对账 | | 0006 | 接入IP不匹配 | 对账 | | 0007 | 超过下载限制 | 对账 | | 0008 | 未开通公共产品 | 对账 | | 9000 | 未开通此产品 | 回单 | | 9001 | 订单不存在 | 回单 | | 9002 | 订单是非成功状态 | 回单 | | 9003 | 参数[产品类型]有误 | 回单 | | 9004 | 该产品电子回单功能未启用 | 回单 | | 9005 | 系统异常 | 回单 |
注意事项
- 签名秘钥是公共产品的签名秘钥,不是扫码/快捷等其他产品的秘钥
- 对账单只能在 第二天早上 6 点后 下载
- 对账日期限定 一个月内且不能是当前日期
- 响应 Header 中的中文需要
URLDecoder.decode(x, "UTF-8")解码 - 对账单 CSV 文件使用 GBK 编码
- 本技能无 SM4 加密字段(查询类接口不涉及敏感信息)
生成时的说明要求
最终回答需要包含:
- 接口请求方式:明确告知接口是
POST form 表单格式(application/x-www-form-urlencoded),不是 JSON;三个接口使用不同的请求地址,通过请求地址区分。 - 接口字段说明:列出所有请求参数、返回参数的完整说明,明确哪些字段参与签名。
- 签名源串拼接规则:按
&P1值&P2值&P3值...顺序拼接(排除 sign),空值也需拼接。余额查询支持 MD5(尾部追加&md5Key)和 SM3WITHSM2 国密(不追加),对账和回单仅支持 MD5。 - 对账单获取方式:明确告知接口返回 gzip 压缩的二进制流,需解压后获得 GBK 编码的 CSV 文件;文件签名用
r_digest验证。 - 电子回单获取方式:明确告知接口返回 JPEG 格式的二进制图片流,直接写入文件即可;文件签名用
r_digest验证。 - 配合 helipay-sm2 技能使用:
- 签名:将拼接好的签名源串传给
helipay-sm2技能。余额查询可选 MD5 或 SM3WITHSM2,对账和回单仅支持 MD5。 - 无 SM4 加密字段(查询类接口,可忽略加密步骤)。
- 文件完整性验证:将对账/回单文件的字节数组+商户密钥传给
helipay-sm2技能进行 MD5 计算,与r_digest比对。
- 签名:将拼接好的签名源串传给
- JDK 和依赖版本:JDK8+,依赖与
helipay-sm2技能一致(Hutool 5.8.5 + BouncyCastle 1.76)。 - 明确说明:本技能只处理合利宝公共产品接口字段组装、签名源串拼接、协议规范,实际的加解密/签名/验签由
helipay-sm2技能完成。 - 提醒:签名源串的字段顺序、排除字段必须与合利宝官方文档一致;对账和回单接口的响应是二进制流(不是 JSON),需通过 HTTP Response Header 判断状态。
- 签名秘钥:使用公共产品的签名秘钥(产品管理 → 产品列表 → 公共产品 → 接口配置)。
Scan to join WeChat group