返回 Skill 列表
extension
分类: 开发与工程无需 API Key

合利宝接口对接_公共产品V001

合利宝接口对接,公共产品的接口(账单、电子回单、商户余额查询接口文档)

person作者: LuckyKhubModelScope

合利宝公共产品接口

概述

公共产品包含三个独立接口:商户余额查询、商户对账单下载、订单电子回单获取。 三个接口使用不同的请求地址,签名方式要求也不同。

接口决策表

| 接口 | 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_cutNumberP6_pdesc(对账接口文档明确标注排除签名) |

拼接规则

  1. 参与签名的字段按变量名顺序拼接:&P1值&P2值&P3值...
  2. 空值字段也要保留连接符
  3. 中文不需要 URL Encode
  4. 尾部处理:
    • MD5 签名:尾部追加 &+MD5 签名秘钥
    • SM3WITHSM2 国密(仅余额查询支持):不追加任何内容
  5. sign = Md5(待签名串&商户密钥) 或 SM3withSM2 签名

签名秘钥获取:登录商户后台 → 产品管理 → 产品列表 → 公共产品 → 接口配置 → 签名秘钥 → 发送到邮箱。

接口一:商户余额查询

请求参数

| 字段名 | 变量名 | 必填 | 说明 | |--------|--------|------|------| | 交易类型 | P1_bizType | 是 | 固定 MerchantAccountQuery | | 商户编号 | P2_customerNumber | 是 | 合利宝分配的商户号 | | 时间戳 | P3_timestamp | 是 | 格式 yyyyMMddHHmmss,14位精确到秒 | | 签名方式 | signatureType | 否 | MD5SM3WITHSM2(不传默认 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 判断状态。
  • 签名秘钥:使用公共产品的签名秘钥(产品管理 → 产品列表 → 公共产品 → 接口配置)。