文档修订记录
| 版本 | 日期 | 修订说明 |
|---|---|---|
| 2.1 | 2020.07.02 | 增加POSID19字段,需要使用微信支付的语音播报功能则该字段必传 |
| 2.2 | 2021.03.10 | 1.由商户公钥参与MD5改为由服务方公钥参与MD5; 2.商户公钥更改为由服务方公钥加密后传送。 |
| 2.3 | 2021.05.06 | 修改参数字段描述 |
| 2.4 | 2021.07.03 | 增加支付位图字段,POSID19不再为必传字段 |
| 2.5 | 2021.09.03 | 增加分期期数字段,支付通知相应返回额外分期字段 |
| 2.6 | 2021.10.18 | 增加外部平台商户号字段及相关说明 |
| 2.7 | 2022.03.16 | 增加中国建设银行App环境下支付对接token等字段 |
| 2.8 | 2022.07.28 | 调整文档结构 |
| 2.9 | 2022.08.04 | 商户下单支付参数增加支付参数;支付通知接口字段描述增加DISCOUNT、ISECNY、ZHJF字段 |
| 2.10 | 2022.10.27 | 商户下单支付参数增加支付通知NOTIFY_URL字段;支付通知接口DISCOUNT、ISECNY、ZHJF字段顺序调整 |
| 2.11 | 2023.04.20 | 商户下单支付参数增加数字人民币相关字段 |
| 2.12 | 2023.06.28 | ccbParamSJ解密后明文新增GPS_TYPE坐标系类型 |
| 2.13 | 2023.10.17 | ccbParamSJ新增编码说明 |
| 2.14 | 2023.12.20 | 商户下单支付接口增加支付方式\账户位图字段及说明 |
| 2.15 | 2024.01.29 | 支付通知接口新增字段 |
| 2.16 | 2024.01.29 | 商户下单支付参数增加用户订单号USER_ORDERID |
| 2.17 | 2024.06.24 | 商户下单支付参数增加服务方二级商户信息相关字段:SUB_MCT_ID、SUB_MCT_NAME、SUB_MCT_MCC |
| 2.18 | 2024.10.28 | 商户下单支付参数增加最小积分抵扣限制字段:MINPOINTLIMIT |
| 2.19 | 2024.12.11 | 支付通知接口备注修改 |
| 2.20 | 2025.07.25 | 新增建行生活退款操作通知接口 |
文档目录
建行相关App服务方接入文档v2.20_202507251. 接入说明2. 服务方跳转说明2.1 跳转URL2.2 建行相关App环境识别2.2.1 建行生活App环境判断 2.2.2 中国建设银行App环境判断2.3 加密串验证3. 建行相关App支付接入文档3.1 服务方调用收银台方法3.1.1 在建行生活App环境收银台调用(1) iPhone系统调用(2) Android系统调用3.1.2 在中国建设银行App环境收银台调用3.2 支付成功页面回调设置3.3 其他说明4. 商户下单支付参数文档4.1 商户->银行接口参数定义4.2 MD5摘要签名(MAC校验)4.3 中文信息需要escape编码4.4 商户公钥密文4.5 外部平台商户号说明4.6 扩展域说明4.7 PAYBITMAP和ACCOUNTBITMAP说明4.8 ORDERID和USER_ORDERID说明4.9 最终参数串示例5. 基本交易流程说明5.1 业务流程图6. 建行生活输入通讯报文接口规范6.1 发送交易报文协议(1) 服务方后台与建行生活后台交易报文协议(2) 服务方前端与建行生活后台交易报文协议6.2 报文规范6.2.1 交易请求报文格式请求报文头字段说明:请求报文样例:6.2.2 交易应答报文规范应答报文头字段说明:应答报文样例:6.2.3 报文编码说明6.2.4 报文长度说明6.2.5 报文结构及数据类型报文结构6.2.6 数据类型6.3 服务接口定义6.4 报文加密及签名6.4.1 流程说明6.4.2 报文样例6.4.3 交易说明6.4.4 加解密及签名方法7. 建行生活支付通知接口7.1 背景描述7.2 字段描述7.2.1 USRINFO字段说明7.2.2 USRMSG字段说明7.2.3 SIGN字段说明7.2.4 CCB_DISCOUNT_AMT和CCB_DISCOUNT_AMT_DESC字段说明7.2.5 MRCH_ID字段说明7.2.5 CRCRD_INSTM_PRD_NUM和BIGAMT_INSTM_HDCG字段说明8. 建行生活退款操作通知接口(不能用于退款结果判断)8.1 背景描述8.2 字段描述8.2.1 SIGN字段说明9. 附录9.1 响应字典9.2 交易流水标识9.3 拓展域列表9.4 文件参考
本文为服务方在建行相关App上接入H5生活场景的技术规范。
由于完成接入后的第三方生活场景将同时上架于多个建行相关App,服务方在对接技术规范时务必着重关注有关具体建行App的适配要求,逐一适配文档所列App。
建行相关App通过分类入口跳转或订单详情跳转至服务方链接时,使用URL格式为:
url?platform=ccblife&channel=mbs&ccbParamSJ=xxxxxx&CITYID=330100&USERCITYID =440100
其中:
url为服务方页面链接地址(一般为中间页面,用于对跳转参数的解密验签处理及二次跳转);
platform=ccblife为建行生活平台标识符
channel为当前运行环境所在的App,如channel=mbs表示在中国建设银行App运行,如无此参数则默认为在建行生活App运行。
CITYID、USERCITYID为用户选择与定位城市代码,参考6位的中国城市代码,同密文参数一致
ccbParamSJ为使用服务方公钥RSA加密后再base64+encodeURIComponent的加密密文,其解密后明文为携带的用户信息,其格式为: USERID=&MOBILE=... (先进行URLDecode之后,再进行解密,解密方法同样参考《报文加密及签名》,略去签名步骤)
密文携带的基本参数如下:
| 参数名 | 参数类型 | 中文名 | 备注 |
|---|---|---|---|
| BGCOLOR | String | 背景色 | 默认为空 |
| PLATFLOWNO | String | 登录校验流水号 | |
| TIMESTAMP | String | 跳转服务方时间戳 | 13位毫秒级 |
| USERID | String | 建行生活用户ID | |
| MOBILE | String | 手机号码 | |
| CITYID | String | 用户选择城市代码 | 使用标准的中国城市代码 |
| USERCITYID | String | 用户定位城市代码 | |
| LGT | String | 经度 | |
| LTT | String | 纬度 | |
| GPS_TYPE | String | GPS坐标系 | 可能值为:gcj02(高德地图坐标)、bd09(百度地图坐标) |
| APPID | String | 小程序appid | 小程序专用参数,APP不存在 |
| OPENID | String | 用户在小程序下唯一标识 | 小程序专用参数,APP不存在 |
| ORDERID | String | 订单号 | 通过订单详情跳转会携带此字段 |
| TOKEN | String | 建行生活用户TOKEN | 仅通过手机银行访问建行生活场景时携带 |
服务方生活场景,按本章节方法识别当前运行的App环境是否为建行相关App。本章节所列App环境必须全部适配。
按如下顺序判断当前页面是否由建行生活App平台打开,满足其中任一条件即表示当前页面由建行生活App平台打开:
1)跳转url中包含platform=ccblife参数;
例:
url?platform=ccblife&channel=mbs&ccbParamSJ=xxxxxx&CITYID=330100&USERCITYID =440100
2)H5页面通过判断navigator.userAgent中含有CloudMercWebView字段
例:
Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148/CloudMercWebView
3)使用以下方法获取userAgent,并判断含有“CloudMercWebView”:
window.CCBBridge.requestNative(JSON.stringify({ action: "getUA", params: {}}), "getUACallBackFund")该js方法回调函数格式如下:
xxxxxxxxxxgetUACallBackFund("{ data:{ ua:'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148/CloudMercWebView' }, state:0, msg:""}")当前跳转url中同时包含platform=ccblife以及channel=mbs两个参数,即表示当前在中国建设银行App环境。
例:
url?platform=ccblife&channel=mbs&ccbParamSJ=xxxxxx&CITYID=330100&USERCITYID =440100
为防止加密串被非法窃取导致的越权风险,建议服务方对加密串进行唯一请求校验。 例如以下请求串被抓包截取后,不校验即可能越权访问客户信息:
可选校验方案如下:
如服务方生活场景涉及支付环节,必须按本章节要求完成文档所列建行相关App的支付接入,使用建行生活收银台完成支付。
如服务方生活场景不涉及支付环节,可略过本章节。
本章节说明了如何调起建行生活收银台,如服务方生活场景涉及支付环节,必须按本章节要求完成文档所列建行相关App调起建行生活收银台适配。
由于平台的差异性,Android 与iOS需用定义的js方法来调用建行生活收银台,其中支付参数详见《商户下单支付参数》章节,以下为参考示例:
其中REMARK2填写服务方编号(服务方编号一般为以YS开头的16位编号)
xxxxxxxxxx<script language="JavaScript">/** * 调起收银台 * @param {String} payInfo payInfo为支付参数(支付参数详见4.商户下单支付参数文档) */function MBS_DIRECT_PAY(payInfo){ window.location="mbspay://direct?"+ payInfo;}</script>xxxxxxxxxx<script language="JavaScript">/** * 调起收银台 * @param {String} payInfo payInfo为支付参数(支付参数详见4.商户下单支付参数文档) */function MBS_DIRECT_PAY(payInfo){ window.mbspay.directpay(payInfo); }</script> 将支付参数组装后(含建行生活用户token,详见支付SDK《商户下单支付参数》文档),使用服务方公钥,参考《6.4.3 交易说明》、《6.4.4 加解密及签名方法》进行RSA加密,将密文、签名、服务方编号作为get请求参数,以html跳转的方式访问建行生活收银处理URL,由建行生活服务端统一处理并以302重定向方式返回建行生活收银台页面。
其中:
建行生活收银处理URL 通讯报文协议见《6.1 发送交易报文协议》“(2) 服务方前端与建行生活后台交易报文协议”。
支付完成后默认跳转到建行生活的支付成功页面,如服务方需要跳转到自己的成功页,请调用setCache方法来设置。(setCache操作须在调起收银台(3.1.1 在建行生活App环境收银台调用)前进行)
xvar requestObj = { action:'setCache',/*设置回调地址*/ params:{ key: '', // 回调的key,与下单参数的remark2保持一致,上送服务方编号 value: '' // 回调的url,支付成功后将由建行生活收银台跳转至此url }} window.CCBBridge.requestNative(JSON.stringify(requestObj), 'callBackName');
// 注: callBackName是回调函数的名称(可自行定义),请先将回调函数挂载到window对象下;该回调仅作为地址设置成功的参考。注:此设置方法仅在建行生活App环境有效,在中国建设银行App环境需在《商户下单支付参数》提供。
支付成功跳转后,设置的回调url会增加携带如下参数:
| 字段名 | 中文名 | 备注 |
|---|---|---|
| MERCHANTID | 商户号 | |
| POSID | 柜台号 | |
| ORDERID | 订单号 | |
| PAYMENT | 订单金额 | |
| SUCCESS | 支付成功标识 | 固定为Y |
| REMARK2 | 支付备注二 | |
| realPayment | 实付金额 | 优惠后实际支付的金额 |
| ccbParamSJ | 用户信息加密串 | 与跳转服务方携带的相同 |
最终支付结果请以服务器通知为准
如服务方生活场景涉及支付环节,必须按本章节要求完成支付参数组装。
如服务方生活场景不涉及支付环节,可略过本章节。
| 字段名 | 中文名 | 类型 | 是否非空 | 是否必送 | 备注 |
|---|---|---|---|---|---|
| MERCHANTID | 商户代码 | CHAR(15) | Y | F | 由建行统一分配 |
| POSID | 柜台代码 | CHAR(9) | Y | F | 由建行统一分配,9位柜台号 |
| BRANCHID | 分行代码 | CHAR(9) | Y | F | 由建行统一分配 |
| POSID19 | 商户19位终端号 | CHAR(19) | N | F | 由建行统一分配,使用微信支付时上送。仅作为参数传递,不参与MAC校验 |
| PLATMCTID | 外部平台商户号 | CHAR(19) | Y | F | 当使用外部商户号时,建行商户号、柜台号、分行号及终端号无需上送。 当该字段有值时参与MAC校验,否则不参与MAC校验。 |
| ORDERID | 支付流水号 | CHAR(30) | Y | T | 由商户提供,最长30位,支付时上送到支付中台,支付结果查询和退款使用 |
| USER_ORDERID | 用户订单号 | CHAR(30) | Y | T | 由商户提供,最长30位,用户订单列表订单信息,订单推送和更新时订单号,支付校验订单信息 |
| PAYMENT | 付款金额 | NUMBER(16,2) | Y | T | 由商户提供,最长30位 |
| CURCODE | 币种 | CHAR(2) | Y | T | 缺省为01-人民币(只支持人民币支付) |
| TXCODE | 交易码 | CHAR(6) | Y | T | 由建行统一分配为520100 |
| REMARK1 | 备注1 | CHAR(30) | N | T | 网银不处理,直接传到城综网,该字段只支持送数字和英文 |
| REMARK2 | 备注2 | CHAR(30) | Y | T | 上送YS开头的服务方编号,与PLATFORMID保持一致 |
| TYPE | 接口类型 | CHAR(1) | Y | T | 默认送1 - 防钓鱼接口 |
| GATEWAY | 网关类型 | CHAR(100) | Y | T | 默认送0 |
| CLIENTIP | 客户端IP | CHAR(40) | N | T | 送空值即可 |
| REGINFO | 客户注册信息 | CHAR(256) | N | T | 客户在商户系统中注册的信息,中文需使用escape编码。送空值即可 |
| PROINFO | 商品信息 | CHAR(256) | N | T | 客户购买的商品信息,收银台会展示该信息,中文需使用escape编码。建议编码前长度不超过50位 |
| REFERER | 商户URL | CHAR(100) | N | T | 商户送空值即可 |
| INSTALLNUM | 分期期数 | CHAR(2) | N | F | 信用卡支付分期期数,一般为 3、6、12 等,必须为大于 1 的整数。 仅当分期支付时上送该字段,无此字段上送时,则视为普通支付。 |
| THIRDAPPINFO | 客户端标识 | CHAR(40) | Y | T | 通过建行相关App下单场景,订单中客户端标识固定设为comccbpay1234567890cloudmerchant |
| TIMEOUT | 订单超时时间 | CHAR(14) | N | F | 格式:YYYYMMDDHHMMSS(如:20120214143005) 银行系统时间> TIMEOUT时拒绝交易,若送空值则不判断超时。 当该字段有值时参与MAC校验,否则不参与MAC校验。 |
| USERID | 建行生活用户ID | CHAR(32) | N | F | 仅在中国建设银行App环境使用。 当该字段有值时参与MAC校验,否则不参与MAC校验。 |
| TOKEN | 建行生活用户TOKEN | CHAR(32) | N | F | 仅在中国建设银行App环境使用。 当该字段有值时参与MAC校验,否则不参与MAC校验。 |
| PAYSUCCESSURL | 支付成功页面URL | CHAR(128) | N | F | 仅在中国建设银行App环境使用,如需指定支付成功页面时提供,需对URL编码,生产环境必须为HTTPS。未提供则默认跳转到建行生活的支付成功页面 当该字段有值时参与MAC校验,否则不参与MAC校验。 |
| PAYBITMAP | 支付位图 | CHAR(10) | N | F | 默认为空,特定场景使用。 |
| ACCOUNTBITMAP | 支付账户位图 | CHAR(10) | N | F | 默认为空,特定场景使用。 |
| POINTAVYID | 积分二级活动编号 | VARCHAR(6) | N | F | 默认为空,特定场景使用。龙支付积分二级活动上送 010051 |
| DCEPDEPACCNO | 数字人民币收款钱包编号 | VARCHAR(32) | N | F | 默认为空,特定场景使用。数字人民币商户绑定的收款钱包编号 |
| COUPONAVYID | 有价券活动编号 | VARCHAR(32) | N | F | 默认为空,特定场景使用。 |
| ONLY_CREDIT_PAY_FLAG | 限制信用卡支付标志 | CHAR(1) | N | F | 默认为空,特定场景使用。当有价券活动编号不为空时生效,送Y限制仅信用卡能支付,送N或空不作限制 |
| FIXEDPOINTVAL | 固定抵扣积分值 | VARCHAR(16) | N | F | 默认为空,特定场景使用。上送该值时,若用户不满足积分使用条件将拒绝支付 |
| MINPOINTLIMIT | 最小使用积分抵扣限制 | VARCHAR(16) | N | F | 默认为空,特定场景使用。上送整数值时,视为最小积分抵扣数额;上送小于1的小数时,视为最小积分抵扣比例。若用户不满足积分使用条件将拒绝支付。 |
| IDENTITYCODE | 身份证后6位 | VARCHAR(256) | N | F | 默认为空,特定场景使用。仅中石化服务方可用。身份证号后6位加密串,用于身份识别。加密说明: 用服务方公钥对身份证后6位进行RSA加密,再进行base64,再进行encodeURIComponent一次。 |
| NOTIFY_URL | 支付异步通知地址 | VARCHAR(512) | N | F | 默认为空,特定场景使用。仅中石化服务方可用。支付结果异步通知地址的encodeURIComponent编码值,多个通知地址时,分隔符用英文半角符号 , 分隔。 |
| DCEP_MCT_TYPE | 数币商户类型 | CHAR(1) | N | F | 默认为空,特定场景使用。0\空-不识别为数币商户;1-融合商户;2-非融合商户 |
| DCEP_MERCHANTID | 数字人民币商户号 | CHAR(15) | N | F | 默认为空,特定场景使用。当DCEP_MCT_TYPE为2时上送值。 |
| DCEP_POSID | 数字人民币柜台号 | CHAR(9) | N | F | 默认为空,特定场景使用。当DCEP_MCT_TYPE为2时上送值。 |
| DCEP_BRANCHID | 数字人民币分行号 | CHAR(9) | N | F | 默认为空,特定场景使用。当DCEP_MCT_TYPE为2时上送值。 |
| SUB_MCT_ID | 服务方二级商户编号 | VARCHAR(20) | N | F | 默认为空,涉及银联反欺诈时使用。若支付发起方为平台类服务方,需上送第三方平台下实际发起支付的二级商户所对应的商户编号。 |
| SUB_MCT_NAME | 服务方二级商户名称 | VARCHAR(40) | N | F | 默认为空,涉及银联反欺诈时使用。若支付发起方为平台类服务方,需上送第三方平台下实际发起支付的二级商户所对应的商户名称。 |
| SUB_MCT_MCC | 服务方二级商户类别 | CHAR(4) | N | F | 默认为空,涉及银联反欺诈时使用。若支付发起方为平台类服务方,需上送第三方平台下实际发起支付的二级商户所对应的商户MCC码。 |
| EXTENDPARAMS | 扩展域 | VARCHAR(256) | N | F | 默认为空,特定场景使用。上送约定JSON格式字符串。 |
| PLATFORMPUB | 服务方公钥 | VARCHAR(256) | Y | F | 仅作为源串参加MD5摘要,不作为参数传递 |
| MAC | MD5加密串 | CHAR(32) | Y | T | 采用标准MD5算法,对以上字段进行MAC加密(32位小写),由商户实现。 |
| PLATFORMID | 服务方编号 | CHAR(16) | Y | T | 以YS开头的16位编号。仅作为参数传递,不参与MAC校验 |
| ENCPUB | 商户公钥密文 | VARCHAR(512) | Y | F | 使用服务方公钥对商户公钥后30位进行RSA加密并base64后的密文。 若商户已经上架建行生活并同步公钥,或是使用外部商户号时,可以不再上送商户公钥。仅作为参数传递,不参与MAC校验 |
| SCNID | 场景编号 | VARCHAR(32) | N | F | 默认为空,埋点使用。特色场景的唯一标识。仅作为参数传递,不参与MAC校验 |
| SCN_PLTFRM_ID | 场景平台编号 | VARCHAR(32) | N | F | 默认为空,埋点使用。场景平台唯一标识。仅作为参数传递,不参与MAC校验 |
注1:字符串中变量名必须是大写字母。
注2:是否非空指该字段是否为非空字段。Y表示上送该字段时,值不可为空;N表示值可以为空。
注3:是否必送指该字段是否上送。T表示该字段必须上送,无论是否有值;F表示字段可以不送。
注4:
采用标准MD5摘要算法对字符串数据签名(32位小写),得到MAC。
(注意和交易通讯报文的mac区分,签名时不需要额外拼接privateKey)
参与签名的字符串及其顺序如下(为上表中MAC字段之上的字段按顺序拼接):
MERCHANTID=105910100194086&POSID=313368474&BRANCHID=441000000&ORDERID=202209020000000061&USER_ORDERID=202209020000000061&PAYMENT=22.39&CURCODE=01&TXCODE=520100&REMARK1=&REMARK2=YS44000098000600&TYPE=1&GATEWAY=0&CLIENTIP=®INFO=&PROINFO=&REFERER=&THIRDAPPINFO=comccbpay1234567890cloudmerchant&TIMEOUT=20220902103420&DCEP_MCT_TYPE=1&PLATFORMPUB=MIGfMA0GCSqGSIb......
注:黑色字体对应的字段必须参与MAC,橙色的字段请根据需要上送,且有值时才参与MAC,否则无需参与MAC
使用js的escape()方法对REGINFO(客户注册信息)和PROINFO(商品信息)进行编码,数字字母信息不需编码。
例: escape(小飞侠) = %u5C0F%u98DE%u4FA0 escape(A1级牛排) = A1%u7EA7%u725B%u6392
ENCPUB: 各服务方使用自己的服务方公钥对商户公钥后30位进行RSA加密,再进行base64后,生成的密文串。
若商户已经上架建行生活并同步公钥,或是关联了外部平台商户号,可以不再上送商户公钥。
注:公钥加密方法见《建行生活输入通讯报文接口规范》的报文加密章节。
外部平台商户号用于服务方已在建行生活完成商户关联,且收款商户已上架建行生活,此时可以使用服务方关联的外部平台商户号来完成支付。 使用外部平台商户号后,原建行商户号、柜台号、分行号无需上送。 若不使用外部平台商户号,则必须上送建行商户号、柜台号、分行号。
该字段仅提供给特定服务方场景使用,内容为双方约定值,格式为JSON字符串,上送时需要encodeURI编码。 例: 善融积分:
xxxxxxxxxx{ "scene": "pointPay", // 场景 "pointAmount": "1.50", // 积分金额 "pointNum": "1050" // 积分数量}PAYBITMAP和ACCOUNTBITMAP分别为定长10位数字的位图,位图为1表示可用,为0表示不可用。两个字段可单独使用,未上送时默认全部支付方式都支持,即全为1(1111111111)。
PAYBITMAP:支付方式位图。第一位生活钱包支付,第二位龙支付,第三位微信支付,第四位数币支付,第五位信用付,第六位快贷支付,其余位图保留。 ACCOUNTBITMAP:支付账户位图,仅对龙支付及生活钱包下的卡账户生效。第一位建行借记卡,第二位建行贷记卡,第三位他行借记卡,第四位为他行贷记卡,第五位为建行钱包,其余位图保留。
注:该位图字段在判断支付方式是否可用时优先级最低,仅当商户已支持某一种支付方式时,服务方可对其决定是否使用。例如商户不支持微信支付,即使位图上送1也不会生效。
ORDERID:商户发起支付的流水号,用于建行收单支付流程,包括在支付、查询支付结果及退款交易中使用。
USER_ORDERID:用户订单号,用于同步用户在建行生活中的订单状态,包括在订单推送及状态更新时使用。
参与验签字符串+MD5码+服务方编号+商户公钥密文
MERCHANTID=105910100194086&POSID=313368474&BRANCHID=441000000&ORDERID=202209020000000061&USER_ORDERID=202209020000000061&PAYMENT=22.39&CURCODE=01&TXCODE=520100&REMARK1=&REMARK2=YS44000098000600&TYPE=1&GATEWAY=0&CLIENTIP=®INFO=&PROINFO=&REFERER=&THIRDAPPINFO=comccbpay1234567890cloudmerchant&TIMEOUT=20220902103420&DCEP_MCT_TYPE=1&MAC=f07ef63236e3bbbc1dc221b06e631f3d&PLATFORMID=YS44000098000600&ENCPUB=YzNxRGtKSkFYZURRczYvNDN6WVZkYk......
详细信息可参考《支付下单串示例.xlsx》文件
以建行生活App环境为例仅供参考

重点步骤说明:
步骤2:由服务方调用订单推送接口(A3341O031)向建行生活推送订单信息
步骤3:参考《建行相关App支付接入文档》调用收银台
步骤10、11:支付通知有两种推送方式,具体细节参考《建行生活支付通知接口》:
步骤13、16:由服务方调用订单更新接口(A3341O033)向建行生活更新订单状态。
步骤14、15:服务方可以向外联平台主动查询订单交易流水,判断订单的支付状态。外联平台接入请参考“外联接口(网银)”(或使用A3341O035)
建行生活后端交易采用HTTP Post 方式为对外通信协议。 访问地址示例:
http://ip:port(域名)/standardxml_adapter/standardxmlchannelservlet
调用HTTP Post方法: HTTP消息体内传输协议报文头、应用报文。
建行生活后端新系统通讯地址(A3341XXXX):
| 环境 | 地址 |
|---|---|
| 测试环境 | http://124.127.94.60:18088/uat_new/tp_service/txCtrl/server?txcode=xxx |
| 生产环境 | https://yunbusiness.ccb.com/tp_service/txCtrl/server?txcode=xxx |
此方式仅适用于在中国建设银行App环境。前端以页面跳转的方式访问建行生活收银处理URL。
访问地址格式:
url?txcode=A3341OM01&svcid=aaaaaaaaa&cnt=xxxxxx&mac=yyyyyyy
其中:
txcode收银处理交易码,固定为A3341OM01
svcid为YS开头的服务方编号。
cnt为将支付参数组装后(含建行生活用户token,详见支付SDK《商户下单支付参数》文档),用建行生活公钥进行加密后的RSA密文参数。
mac为MD5签名,32位大写(注意与支付参数的MAC区分)
加解密及签名详见《6.4.3 交易说明》、《6.4.4 加解密及签名方法》
url地址(仅A3341OM01):
| 环境 | 地址 |
|---|---|
| 测试环境 | http://124.127.94.60:18088/uat_new/clp_service/txCtrl |
| 生产环境 | https://yunbusiness.ccb.com/clp_service/txCtrl |
请求报文由两部分组成,交易请求报文头和交易请求报文体。其中交易请求报文头信息在报文头(CLD_HEADER)节点内,交易请求报文体信息在报文体(CLD_BODY)节点内。
| 字段标识(报元号) | 字段中文名 | 字段说明 | 数据属性 | 是否必填 | 备注 |
|---|---|---|---|---|---|
| CLD_TX_CHNL | 报文来源渠道 | 消息来源渠道。 | CHAR(20) | Y | 以YS开头的服务方编号 |
| CLD_TX_TIME | 报文交易时间 | CHAR(14) | Y | 上送交易时间,格式:yyyyMMddHHmmss | |
| CLD_TX_CODE | 交易服务ID | CHAR(64) | Y | 调用的交易名称 | |
| CLD_TX_SEQ | 交易流水标识 | CHAR(32) | Y | 用于标识唯一性 |
请求报文体信息
根据交易报文接口章节中每个交易的请求接口定义组装请求报文。
xxxxxxxxxx{ "CLD_HEADER":{ "CLD_TX_CHNL":"YSTEST", "CLD_TX_TIME":"20241231090000", "CLD_TX_CODE":"A3341O031", "CLD_TX_SEQ":"1010114131620897033814262" }, "CLD_BODY":{
}}应答报文由两部分组成,交易应答报文头和交易应答报文体。其中交易应答报文头信息在报文头(CLD_HEADER)节点内,交易应答报文体信息在报文体(CLD_BODY)节点内。
| 字段标识(报元号) | 字段中文名 | 字段说明 | 数据属性 | 是否必填 | 备注 |
|---|---|---|---|---|---|
| CLD_TX_CHNL | 报文来源渠道 | 消息来源渠道。 | CHAR(20) | Y | 以YS开头的服务方编号 |
| CLD_TX_TIME | 报文交易时间 | CHAR(14) | Y | 上送交易时间,格式:yyyyMMddHHmmss | |
| CLD_TX_CODE | 交易服务ID | CHAR(64) | Y | 调用的交易名称 | |
| CLD_TX_SEQ | 交易流水标识 | CHAR(32) | Y | 用于标识唯一性 | |
| CLD_CODE | 交易响应码 | CHAR(32) | Y | ||
| CLD_DESC | 交易响应内容 | CHAR(32) | Y |
应答报文体信息
根据交易报文接口章节中每个交易的应答接口定义组装应答报文。
xxxxxxxxxx{ "CLD_HEADER":{ "CLD_TX_CHNL":"", "CLD_TX_TIME":"20151231090000", "CLD_TX_CODE":"A3341O031", "CLD_TX_SEQ":"1010114131620897033914221", "CLD_TX_RESP":{ "CLD_CODE":"", "CLD_DESC":"" } }, "CLD_BODY":{
}}报文使用UTF-8编码
非二进制类型报元单个报元长度建议在9999位以内,整体报文大小建议在20K以内;考虑到客户登录类交易如果账户数量较多的情况,登录类交易可以在2M以内;
对交易报文接口章节中的字段进行说明
xxxxxxxxxx{ "ADDR_LIST":[ "张杨路500号14楼" ]}xxxxxxxxxx{ "SCI35022_0":{ "ADDR":"张杨路500号14楼", "ADDR_TYP":"OFF", "POSTCOD_TYP":"200122", "TEL_NO":"13601735604" }}xxxxxxxxxx{ "SCI_LIST":[ { "ADDR":"张杨路500号14楼", "ADDR_TYP":"OFF", "POSTCOD_TYP":"200122", "TEL_NO":"13601735604" }, { "ADDR":"张杨路500号14楼", "ADDR_TYP":"OFF", "POSTCOD_TYP":"200123", "TEL_NO":"13601735605" } ]}数据类型分为B、C、N、codestring。B为字节数组、C为字符串,N为数值型(长度、小数位),codestring为分类代码。它们在XML中都是以字符串存储的,B类型用Base64编码后存储。C类型非法字符以存储。
详见接口定义文档《建行生活输入通讯报文》(.xlsx)(在附件中获取)

xxxxxxxxxx{ "svcid": "服务方ID,以YS开头", "cnt": "密文xxxx", "mac": "签名yyyy"}xxxxxxxxxx{ "code": "错误码xxxx", "msg": "错误描述yyyy"}xxxxxxxxxx{ "cnt": "密文xxxx", "mac": "签名yyyy"}原始报文:
xxxxxxxxxx{ "CLD_HEADER":{ "CLD_TX_CHNL":"YSTEST", "CLD_TX_TIME":"20191112145911", "CLD_TX_CODE":"A3341O031", "CLD_TX_SEQ":"" }, "CLD_BODY":{ "USER_ID":"user123", "ORDER_ID":"order123", "ORDER_DT":"20191112145811", "TOTAL_AMT":"100.00", "PAY_AMT":"90.00", "DISCOUNT_AMT":"10.00", "ORDER_STATUS":"1", "REFUND_STATUS":"0", "MCT_NM":"XXX商户" }}加密后报文:
xxxxxxxxxx{ "cnt":"UWl3VVVIT0IzSHp6VUtpNFVmb25VcWJjMnBKdU9IclJUZ3lISGJLR3Myd21saWQvMTVvenNMNk5xWmFwUzl1clh5K2VkVmJuU1BYMg0KTzUwamNkZWRmdjc5NHdDRmJSdjF4WDl4bzAwejMwU2k2NXJ6cTVaVVU4dUt2ZmNPeVJ1cDJkTC9SOUgvODVUblNLbEVXUnErSGo3dw0KMzB2YjFaeU1acU5iRVZnb25VSTUrcmlPV2wweWUwb2xQTVFoei9CVWhDcU9qOExqR21hTDBCdGpVbVdiTyttU3Vpa0s5Y25md3g0SQ0KV0xUSk1BWjl3OHdkZ0FqamI5bXhJbFJUM3JrU3VId1RMdGF0VkdJcGovVDAvdk5nQzNUcWgvODJOQnZvYXdoYnl0Z3AwRW9FNWp5bw0KdVhmYVZDZE9IeGp4ZkpyclFFSCt5THFoZXl2MEx2OGJ1b0x0N0pYMi9zM0pJS0J1bFdSZWJHRTMrcmpEMm9sUVJiYklONkdpeDlodQ0KUEprWkFkK0UrcTV1ZFR4OXpFRlJyWVBHVURzL0RLK0JFSk5iYWZGRnllZTBrRzh2YVlmU1NxeFBWcVBrblRzZ2oxdXFqME0xTGFCNQ0KZ1drVU9vVnl4bUtXUEpYd3JqYXlkSUxVeEZ2dkwzZEpHYmV6cnUwK3d1V3A2QXBQVnRkOElaSm4NCg==", "mac":"1659E42FC9D2A2186228C4607A566D78", "svcid":"YSTEST"}服务方主动调用建行生活的接口时,需传递的是服务方编号(由建行生活分配)、RSA密文及签名三个数据。
- RSA密文 是基于RSA对全报文加密,公私钥在系统外相互同步(如,文本文档,在行内通讯软件传输),上文中显示的报文是加密前或解密后的报文格式。
- 签名 是针对源报文(未加密)+私钥获取MD5的数据,验签需要接收方先解密密文,获得源报文后自行拼接私钥获取MD5,再验证与接收的MD5签名是否一致,不一致则为报文篡改,不对报文进行处理,直接结束返回异常提示。
- 密文 使用cnt字段传输,签名使用mac传输,所以加密及签名后,实际传输的内容只有svcid=aaaaaaaaa&cnt=xxxxxx&mac=yyyyyyy(aaaaaaaaa 为服务方编号,xxxxxx为密文内容,yyyyyyy为签名内容)
本章节提供两个文件MD5Util.java、RSAUtil.java及加解密方法 (对应文件可在附件中获取)
xxxxxxxxxx// 公钥String publicKey = "";
// 私钥String privateKey = "";
/** * 加密及获取签名 */// 源报文(未加密)String msg = "";
// 公钥加密得到密文并使用base64处理String enc_msg = RSAUtil.encrypt(msg, publicKey);BASE64Encoder encoder = new BASE64Encoder();enc_msg = encoder.encode(enc_msg.getBytes("UTF-8"));enc_msg = enc_msg.replaceAll("\r\n", "").replaceAll("\r", "").replaceAll("\n", "");
// 根据源报文+私钥获得MD5签名String mac_info = MD5Util.getMD5(msg + privateKey);
/** * 解密及验签 */// base64逆处理并用私钥解密BASE64Decoder decoder = new BASE64Decoder();enc_msg = new String(decoder.decodeBuffer(enc_msg),"UTF-8");String dec_msg = RSAUtil.decrypt(enc_msg, privateKey);
// 验签String dec_mac = MD5Util.getMD5(dec_msg + privateKey);if (mac_info.equals(dec_mac)) { System.out.println("验签通过");} else { System.out.println("验签失败");}
提示:如果使用的JDK版本高于1.8,请将base64方法由sun.misc.BASE64Encoder替换为java.util.Base64,即 加密方法:
xxxxxxxxxx// BASE64Encoder encoder = new BASE64Encoder();// enc_msg = encoder.encode(enc_msg.getBytes("UTF-8"));// 替换为Encoder encoder = Base64.getEncoder();enc_msg = encoder.encodeToString(enc_msg.getBytes("UTF-8"));
// RSAUtil.java: (new BASE64Encoder()).encodeBuffer(key) 替换为Base64.getEncoder().encodeToString(key)解密方法:
xxxxxxxxxx// BASE64Decoder decoder = new BASE64Decoder();// enc_msg = new String(decoder.decodeBuffer(enc_msg), "UTF-8");// 替换为Decoder decoder = Base64.getMimeDecoder();enc_msg = new String(decoder.decode(enc_msg), "UTF-8");
// RSAUtil.java: (new BASE64Decoder()).decodeBuffer(key) 替换为Base64.getMimeDecoder().decode(key)
如服务方生活场景涉及支付环节,必须按本章节要求完成支付回调通知对接。 同时,因网络问题存在支付通知丢失的可能性,请服务方考虑通过主动查询支付流水的方式作为兜底,参考《建行生活输入通讯报文》服务方订单查询交易。
如服务方生活场景不涉及支付环节,可略过本章节。
支付结果推送接口是特殊接口,属于建行生活主动推送给服务方,所以不会附带服务方编号。 服务方接收支付通知的系统地址,需要配置在建行生活运营后台,请联系运维进行配置。
接口推送报文示例
xxxxxxxxxx{"ACC_TYPE": "WX","BRANCHID": "310000000","CCB_DISCOUNT_AMT": "","CCB_DISCOUNT_AMT_DESC": "","CLIENTIP": "11.123.44.55","CURCODE": "01","MRCH_ID": "","NT_TYPE": "YS","ORDERID": "210520133844test3yhv","PAYMENT": "0.01","PAY_TYPE": "01","POSID": "123442025","REFERER": "","REMARK1": "","REMARK2": "YS1234009000111**WXZF","SIGN":"1a4aca34f02c0efab014ff823153a2a07a35a8a8410591a992d4aa9cd7fa1f961b952236a45b4fe37867ad4a7214ecbeae21957dee9c19d3d2f5dcf09c8faca81ceb68119c8dcd53bd1e70c23f60fc03e7cd96b8c0082a1243d688c13aac0bcd9e177c559e40e782e3856ada32de8d8ce0054e35fca2022b8f91b2a1ca2c5e10","SUCCESS": "Y","TYPE": "1"}发起支付时(调用商户下单支付接口),把服务方编号通过REMARK2字段送到支付渠道,让支付渠道再推送结果给建行生活时,建行生活根据该字段来判断订单归属哪个服务方,然后指定推送订单结果给对应的服务方(需要在后台维护服务方系统地址)。
PS: 由建行生活推送给服务方的支付通知会额外携带该笔订单所使用的优惠金额;但是由网银直接推送的支付通知,只含原订单金额,不包含优惠金额,需要服务方自行向外联平台查询。
目前对于支付后通知,根据支付方式的不同,有两种通知路径:
| 路径序号 | 支付方式 | 通知路径 |
|---|---|---|
| 1 | 钱包支付、龙支付 | 建行网银→建行生活各场景服务方 |
| 2 | 钱包支付、龙支付、微信支付 | 建行网银→建行生活→建行生活各场景服务方 |
| 字段名 | 中文名 | 类型 | 备注 |
|---|---|---|---|
| NT_TYPE | 支付服务通知类型 | CHAR(9) | 当该字段有值且为为YS时,则表示此通知是由建行生活加签后发出。当该字段为CCB或为空时,则表示此通知是由建行原始通知加签后发出。该字段不参与签名 |
| PAY_TYPE | 支付方式 | CHAR(2) | 01-微信支付 02-其他支付 该字段不参与签名 |
| POSID | 商户柜台代码 | CHAR(9) | 从商户传送的信息中获得 |
| BRANCHID | 分行代码 | CHAR(9) | 从商户传送的信息中获得 |
| ORDERID | 定单号 | CHAR(30) | 从商户传送的信息中获得 |
| PAYMENT | 付款金额 | NUMBER(16,2) | 从商户传送的信息中获得 请商户务必与订单支付金 额比对,确认两者金额一致 |
| CURCODE | 币种 | CHAR(2) | 从商户传送的信息中获得 |
| REMARK1 | 备注一 | CHAR(30) | 从商户传送的信息中获得,禁止送中文(escape后的也不行) |
| REMARK2 | 备注二 | CHAR(30) | 从商户传送的信息中获得 |
| ACC_TYPE | 账户类型 | CHAR(2) | |
| SUCCESS | 成功标志 | CHAR(1) | 成功-Y,失败-N。是否支付成功,请以此字段为准 |
| TYPE | 接口类型 | CHAR(1) | 分行业务人员在 P2 员工渠道后台设置防钓鱼的开关。 1.开关关闭时,无此字段返回且不参与验签。 2.开关打开时,有此字段返回且参与验签。参数值为防钓鱼接口 |
| REFERER | 商户URL | CHAR(100) | 分行业务人员在 P2 员工渠道后台设置防钓鱼开关。 1.开关关闭时,无此字段返回且不参与验签。 2.开关打开时,有此字段返回且参与验签。 |
| CLIENTIP | 客户端IP | CHAR(40) | 客户在商户系统中的IP,即客户登陆(访问)商户系统时使用的IP)分行业务人员在 P2 员工渠道后台设置防钓鱼开关。 1.开关关闭时,无此字段返回且不参与验签。 2.开关打开时,有此字段返回且参与验签。 |
| ACCDATE | 系统记账日期 | CHAR(8) | 商户登陆商户后台设置返回记账日期的开关 1.开关关闭时,无此字段返回且不参与验签。 2.开关打开时,有此字段返回且参与验签。参数值格 式为 YYYYMMDD (如 20100907)。 |
| USRMSG | 支付账户信息 | CHAR(100) | 分行业务人员在 P2 员工渠道后台设置防钓鱼开关和 返回账户信息的开关。 1.开关关闭时,无此字段返回且不参与验签。 2.开关打开但支付失败时, 无此字段返回且不参与验签。 3.开关打开且支付成功时,有此字段返回且参与验签。参数值格式如下:“姓名|账号加密后的密文”。 |
| INSTALLNUM | 分期期数 | CHAR(2) | 从商户传送的信息中获得; 当分期期数为空或无此字 段上送时,无此字段返回 且不参与验签,否则有此字段返回且参与验签。 |
| ERRMSG | 错误信息 | CHAR(12) | 该值默认返回为空,商户无需处理,仅需参与验签即可。当有分期期数返回 时,则有ERRMSG字段返回且参与验签,否则无此字段返回且不参与验签。 |
| USRINFO | 客户加密信息 | CHAR(256) | 分行业务人员在 P2 员工渠道后台设置防钓鱼开关和客 户信息加密返回的开关。 1.开关关闭时,无此字段返回且不参与验签 2.开关打开时,有此字段返回且参数验签。参数值格式如下:“证件号密文|手机号密文”。该字段不可解密。 |
| DISCOUNT | 实付金额 | NUMBER(16,2) | 优惠之后的实际支付金额。单位:元。 目前只针对白名单商户返回,无此字段返回时不参与验签,有此字段返回时参与验签。 |
| ISECNY | 是否数币支付 | CHAR(1) | 统一支付网关,如果客户使用的是数币支付,服务器通知及页面通知会增加此字段 ISECNY=Y |
| ZHJF | 积分使用情况 | VARCHAR(100) | 返回客户的积分使用情况, 格式如下:{“APnt_Hpn_Num”:”积分发生数量”,”APntCmpt_Amt”:”积分抵扣金额”} 当综合积分字段为空或无此字段上送时,无此字段返回且不参与验签,否则有此字段返回且参与验签。 该字段参与验签的值为encode之后的参数值(URLEncoder utf-8) |
| OPENID | 客户识别号 | VARCHAR(128) | 提交建行的参数RETURN_FIELD打开对应开关才返回该字段。客户识别码,微信、支付宝、龙支付时返回。有该字段返回时(无论返回值是空还是其他),需参与验签,否则无需参与验签。 |
| SUB_OPENID | 用户子标识 | VARCHAR(128) | 提交建行的参数RETURN_FIELD打开对应开关才返回该字段。微信支付专有字段。子商户appid下用户唯一标识,如需返回则请求时需要传sub_appid。有该字段返回时(无论返回值是空还是其他),需参与验签,否则无需参与验签。 |
| PAYMENT_DETAILS | 支付详细信息 | VARCHAR(256) | 支付详细信息。当RETURN_FIELD字段第四支付详细信息。当RETURN_FIELD字段第四位上送1时返回。字段说明见下方[支付详细信息字段说明] 格式如下:{"TYPE":"ALIPAY","PAY_CHANNEL":"BANKCARD","DEBIT_CREDIT_TYPE":"DEBIT_CARD","THIRD_TRADE_NO":"2018010521001004890523646975"} 为防止特殊字符,建行会将该参数值用utf-8编码进行urlencode,因此商户需先decode之后才能拿到明文。有该字段返回时(无论返回值是空还是其他),需参与验签,否则无需参与验签。 该字段参与验签的值为encode之后的参数值(URLEncoder utf-8) |
| SHYHQ_ENTITY | 商户优惠券实体 | JSON | 目前只针对配置返回该字段的商户返回,无此字段返回且不参与验签,有此字段返回且参与验签。 商户优惠券实体涉及字段示例: SHYHQ_ENTITY={"TrdPt_DcCp_ID":"第三方优惠券编号","DcCp_Nm":"优惠券名称","Cyc_Pref_Amt":"周期优惠金额","Txn_Prft_Amt":"交易优惠金额","Prmt_Rfnd_Ind":"允许退款标志","Rght_Cgy_Inf":"权益类信息"……} “权益类信息”格式及参数参考:例: 【P6:{FL1:1,FL2:01,FL3:有价折扣券,FL4:曹操出行50%券,AM1:30.00}】; FL1-优惠度量,如积分数、券数量;FL2-清算方式,01-后结算,02-在线一笔清算、03-在线异步清算;FL3-优惠类型,如满减活动、满减券、有价券等;FL4-优惠名称,如活动描述或券名称;AM1-优惠金额,AM2-清算金额,AM3-银行出资金额,AM4-商户出资金额,AM5-优惠券面额,AM6-客户实付金额,如有价券客户购买金额,AM7-积分抵扣金额(目前是积分购买有价券专属)。 {}内字段可能持续增加,请商户做好兼容,有该字段返回时需参与验签,否则无需参与验签。 该字段参与验签的值为encode之后的参数值(URLEncoder utf-8) |
| SIGN | 数字签名 | CHAR(256) | 签名字段,对以此行以上字段的签名,由商户方比对 |
| CCB_DISCOUNT_AMT | 建行支付侧优惠金额 | CHAR(256) | 在建行支付网关产生的优惠总金额 该字段不参与签名 需使用服务方公钥解密 |
| CCB_DISCOUNT_AMT_DESC | 建行支付侧优惠定义 | CHAR(256) | 建行支付侧优惠定义(各金额之和等于建行支付侧优惠金额) 格式:优惠名称=金额|@|优惠名称=金额 例如:优惠券A=0.05|@|活动A=0.99 该字段不参与签名 需使用服务方公钥解密 |
| MRCH_ID | 商户号 | CHAR(256) | 商户编号 该字段不参与签名 需使用服务方公钥解密 |
| CRCRD_INSTM_PRD_NUM | 信用卡分期期数 | CHAR(30) | 信用卡分期期数 该字段不参与签名 需使用服务方公钥解密 |
| BIGAMT_INSTM_HDCG | 分期手续费 | CHAR(30) | 信用卡分期手续费(单位元) 该字段不参与签名 需使用服务方公钥解密 |
注1:除不参与签名的字段外,加粗字段为验签时必输字段,其余字段请判断在当且仅当该字段返回时参与验签 注2:需要使用服务方公钥解密的字段,仅当由建行生活转发支付通知时会存在
| 信息返回开关 | 证件号返回开关 | 手机号返回开关 | 返回值 |
|---|---|---|---|
| 开 | 开 | 开 | USRINFO =证件号密文|手机号密文 |
| 开 | 开 | 关 | USRINFO =证件号密文 |
| 开 | 关 | 开 | USRINFO =手机号密文 |
| 开 | 关 | 关 | USRINFO = |
| 关 | 开\关 | 开\关 | 不返回USRINFO |
| 系统编码为ISO-8859-1,服务方处理时请注意编码问题。 |
使用对称加密算法对“户名|账号”进行加密后通过商户通知接口传送到商户系统,对称加密的密钥为建行生活为场景服务方分配的专门用于支付通知的公钥后30位【注意区别于在商户服务平台下载的柜台公钥】。如:
密钥:f6528d5c335b7092fc9ec1b3020111 原串:梅九六|6214662020019275 加密串:AWWo2KKeATj6XxRglo7uaR0yZ2QQtCW%2C 使用MCipherDecode.java类中的getDecodeString(String urlString)方法进行解密,主要步骤如下:
xxxxxxxxxxMCipherDecode mcd = new MCipherDecode(key);// 设置密钥decodedString = mcd.getDecodeString(cipherdURL);// 解密byte[] tempByte = decodedString.getBytes("ISO-8859-1"); String a = new String(tempByte,"GBK"); // 进行字符转码系统编码为ISO-8859-1,商户处理时请注意编码问题。
1)支付详细信息字段说明
| 参数 | 参数名称 | 长度 | 是否必输 | 参数说明 | 样例 |
|---|---|---|---|---|---|
| TYPE | 支付方式 | 10 | N | 枚举值 支付宝:ALIPAY、微信:WEIXIN、建行:CCB、银联:UNIONPAY(暂不支付) | ALIPAY |
| PAY_CHANNEL | 支付渠道 | 30 | N | 商户可根据该字段获取支付账户的发卡机构。 1.当支付方式为微信时,详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_2 第8点、银行类型; 2.当支付方式为支付宝时,详见i.支付宝的支付渠道说明; 3.当支付方式为建行时,详见 ii.建行的支付渠道说明; 4.当支付方式为银联时,该字段返回为空。 | BANKCARD |
| DEBIT_CREDIT_TYPE | 借贷记标识 | 10 | N | 借记:DEBIT;贷记:CREDIT。 当支付方式为银联时, 该字段返回为空 | CREDIT |
| THIRD_TRA DE_NO | 第三方订单号 | 100 | N | 返回支付宝/微信订单号 当支付方式为龙支付或银联时,该字段返回为空 | 2018010521001004890523646975 |
i. 支付宝的支付渠道说明(后续可能增加,请注意兼容)
| 支付渠道代码 | 支付渠道说明 |
|---|---|
| COUPON | 支付宝红包 |
| ALIPAYACCOUNT | 支付宝余额 |
| POINT | 集分宝 |
| DISCOUNT | 折扣券 |
| PCARD | 预付卡 |
| MCARD | 商家储值卡 |
| MDISCOUNT | 商户优惠券 |
| MCOUPON | 商户红包 |
| PCREDIT | 蚂蚁花呗 |
| BANKCARD | 银行卡渠道 |
ii. 建行的支付渠道说明(后续可能增加,请注意兼容)
| 支付渠道代码 | 支付渠道说明 |
|---|---|
| LONG_WALLET | 龙支付钱包 |
| CCB_BANKCARD | 建行卡 |
| OTHER_BANKCARD | 他行卡 |
商户通知串格式
请注意 TYPE、 REFERER 、 CLIENTIP 、 ACCDATE、 INSTALLNUM、 ERRMSG、USRMSG、USRINFO、DISCOUNT、ZHJF、OPENID、SUB_OPENID、 PAYMENT_DETAILS 只有在满足条件的情况下才会返回。
商户通知串样例:
POSID=000000000&BRANCHID=110000000&ORDERID=19991101234&PAYMENT=500.00&CURCODE=01&REMARK1=&REMARK2=&ACC_TYPE=12&SUCCESS=Y&TYPE=1&REFERER=http://www.ccb.com/index.jsp&CLIENTIP=172.0.0.1&ACCDATE=20100907&INSTALLNUM=3&ERRMSG=&USRMSG=T4NJx%2FVgocRsLyQnrMZLyuQQkFzMAxQjdqyzf6pM%2Fcg%3D&USRINFO=T4NJx%2FVgocRsLyQnrMZLyuQQkFzMAxQjdqyzf6pM%2Fcg%3D&DISCOUNT=0.01&ZHJF={“APnt_Hpn_Num”:”积分发生数量”,”APntCmpt_Amt”:”积 分 抵 扣 金 额 ”}&OPENID=oUpF8uChLsBIhscta2jEtNGam5sI&SUB_OPENID=oZQ9N5fxh-dig4CtC_cNxTIZ68ZA&PAYMENT_DETAILS=%7B%22TYPE%22%3A%22ALIPAY%22%2C%22PAY_CHANNEL%22%3A%22BANKCARD%22%2C%22DEBIT_CREDIT_TYPE%22%3A%22DEBIT_CARD%22%2C%22THIRD_TRADE_NO%22%3A%222018010521001004890523646975%22%7D&SIGN=317b7dd349c1fbcabc26a20ba117a778da5a685c588be5e7378682651062a25b0885e36ee237c19a143f7271c9529a0e9bf198c8735709dc74233d96e1a276cec9d4835422bee597100b0a47d11b44dbba74bdf9cbde0587f138141ce79a3536733d5f6b53ed119c13708dca52ee8d3fcf7e67dcdb20053889adff1989a8c859
签名运算原串
请注意:红色字体对应的字段必须参与签名;其他字段在商户通知串中有返回时(无论值是否为空),需参与签名,否则无需参与签名。
参与签名运算的字符串及其顺序如下:
POSID=000000000&BRANCHID=110000000&ORDERID=19991101234&PAYMENT=500.00&CURCODE=01&REMARK1=&REMARK2=&ACC_TYPE=12&SUCCESS=Y&TYPE=1&REFERER=http://www.ccb.com/index.jsp&CLIENTIP=172.0.0.1&ACCDATE=20100907&INSTALLNUM=3&ERRMSG=&USRMSG=T4NJx%2FVgocRsLyQnrMZLyuQQkFzMAxQjdqyzf6pM%2Fcg%3D&USRINFO=T4NJx%2FVgocRsLyQnrMZLyuQQkFzMAxQjdqyzf6pM%2Fcg%3D&DISCOUNT=0.01&ZHJF={“APnt_Hpn_Num”:”积分发生数量”,”APntCmpt_Amt”:”积 分 抵 扣 金 额 ”}&OPENID=oUpF8uChLsBIhscta2jEtNGam5sI&SUB_OPENID=oZQ9N5fxh-dig4CtC_cNxTIZ68ZA&PAYMENT_DETAILS=%7B%22TYPE%22%3A%22ALIPAY%22%2C%22PAY_CHANNEL%22%3A%22BANKCARD%22%2C%22DEBIT_CREDIT_TYPE%22%3A%22DEBIT_CARD%22%2C%22THIRD_TRADE_NO%22%3A%222018010521001004890523646975%22%7D
注:字符串中变量名必须是大写字母。
例1:
NT_TYPE=YS&PAY_TYPE=01&POSID=000000000&BRANCHID=110000000&ORDERID=19991101234&PAYMENT=500.00&CURCODE=01&REMARK1=&REMARK2=&ACC_TYPE=12&SUCCESS=Y&TYPE=1&REFERER=http://www.ccb.com/index.jsp&CLIENTIP=172.0.0.1&ACCDATE=20100907&USRMSG=T4NJx%2FVgocRsLyQnrMZLyuQQkFzMAxQjdqyzf6pM%2Fcg%3D&INSTALLNUM=3&ERRMSG=&USRINFO=T4NJx%2FVgocRsLyQnrMZLyuQQkFzMAxQjdqyzf6pM%2Fcg%3D&SIGN=317b7dd349c1fbcabc26a20ba117a778da5a685c588be5e7378682651062a25b0885e36ee237c19a143f7271c9529a0e9bf198c8735709dc74233d96e1a276cec9d4835422bee597100b0a47d11b44dbba74bdf9cbde0587f138141ce79a3536733d5f6b53ed119c13708dca52ee8d3fcf7e67dcdb20053889adff1989a8c859
例2:
PAYMENT=0.01&POSID=045242025&SUCCESS=Y&PAY_TYPE=01&CCB_DISCOUNT_AMT_DESC=&REMARK1=&REMARK2=YS44000009000152**WXZF&NT_TYPE=YS&MRCH_ID=&ORDERID=210520133844test3yhv&REFERER=&CLIENTIP=11.168.99.30&SIGN=1a4aca34f02c0efab014ff823153a2a07a35a8a8410591a992d4aa9cd7fa1f961b952236a45b4fe37867ad4a7214ecbeae21957dee9c19d3d2f5dcf09c8faca81ceb68119c8dcd53bd1e70c23f60fc03e7cd96b8c0082a1243d688c13aac0bcd9e177c559e40e782e3856ada32de8d8ce0054e35fca2022b8f91b2a1ca2c5e10&ACC_TYPE=WX&CCB_DISCOUNT_AMT=&CURCODE=01&TYPE=1&BRANCHID=310000000
请注意ACC_TYPE、ACCDATE、USRMSG、INSTALLNUM、ERRMSG、USRINFO只有在满足条件的情况下才会返回。 字符串中变量名必须是大写字母。
例1:
POSID=000000000&BRANCHID=110000000&ORDERID=19991101234&PAYMENT=500.00&CURCODE=01&REMARK1=&REMARK2=&ACC_TYPE=12&SUCCESS=Y&TYPE=1&REFERER=http://www.ccb.com/index.jsp&CLIENTIP=172.0.0.1&ACCDATE=20100907&USRMSG=T4NJx%2FVgocRsLyQnrMZLyuQQkFzMAxQjdqyzf6pM%2Fcg%3D&INSTALLNUM=3&ERRMSG=&USRINFO=T4NJx%2FVgocRsLyQnrMZLyuQQkFzMAxQjdqyzf6pM%2Fcg%3D
例2:
POSID=045242025&BRANCHID=310000000&ORDERID=210520133844test3yhv&PAYMENT=0.01&CURCODE=01&REMARK1=&REMARK2=YS44000009000152**WXZF&ACC_TYPE=WX&SUCCESS=Y&TYPE=1&REFERER=&CLIENTIP=11.168.99.30
317b7dd349c1fbcabc26a20ba117a778da5a685c588be5e7378682651062a25b0885e36ee237c19a143f7271c9529a0e9bf198c8735709dc74233d96e1a276cec9d4835422bee597100b0a47d11b44dbba74bdf9cbde0587f138141ce79a3536733d5f6b53ed119c13708dca52ee8d3fcf7e67dcdb20053889adff1989a8c859
xxxxxxxxxx/*** Method: setPublicKey* description: 设置验签用公钥* * @param pkey* 商户的公钥* @return 无*/setPublicKey(String pkey)
/*** Method: verifySigature* description: 验证签名* * @param sign* 建行返回的sign签名* @param src* 签名前的源串,例如:POSID=000000&BRANCHID=110000000&ORDERID=00320995&PAYMENT=0.01&CURCODE=01&REMARK1=test1&REMARK2=test2&SUCCESS=Y* @return true-验证通过 false-验证失败*/boolean verifySigature(String sign,String src)注:
这两个字段为加密字段,加密方式 RSAUtil.encrypt->BASE64Encoder(UTF-8,并处理换行)【即建行生活接口的加密方式】。
CCB_DISCOUNT_AMT为在建行网关支付产生的优惠总额,商户可以根据(订单金额 - 优惠总额)得到实付金额
CCB_DISCOUNT_AMT_DESC为优惠明细,格式为:优惠名称=优惠金额|@|优惠名称=优惠金额 (多种优惠以|@|分隔)
该字段为加密字段,加密方式 RSAUtil.encrypt->BASE64Encoder(UTF-8,并处理换行)【即建行生活接口的加密方式】。
当商户使用商户侧分期支付时,额外返回这两个相关字段。 该字段为加密字段,加密方式 RSAUtil.encrypt->BASE64Encoder(UTF-8,并处理换行)【即建行生活接口的加密方式】。
如服务方场景需要接收退款操作消息通知,必须按本章节要求完成退款回调通知对接。 不同于支付结果推送,退款操作消息推送仅推送商户号、订单号等少量用于查询使用的信息,若需获知退款状态、金额、优惠信息和支付方式等信息,参考《建行生活输入通讯报文》服务方订单查询交易(A3341TP03)。
如服务方场景不涉及退款环节或仅通过A3341TP04服务方退款交易完成退款,已实现退款流程的闭环,可略过本章节。
订单退款操作消息推送属于建行生活主动推送给服务方,所以不会附带服务方编号。 服务方接收退款操作消息通知的回调地址,需要配置在建行生活运营后台,请联系运维进行配置。
接口推送报文示例
xxxxxxxxxx{"MRCH_ID": "1050000000000000000","NT_TYPE": "YS","ORDERID": "210520133844test3yhv","REFUND_DTM": "20250601120000", "SIGN" : "317b7dd349c1fbcabc26a20ba117a778da5a685c588be5e7378682651062a25b0885e36ee237c19a143f7271c9529a0e9bf198c8735709dc74233d96e1a276cec9d4835422bee597100b0a47d11b44dbba74bdf9cbde0587f138141ce79a3536733d5f6b53ed119c13708dca52ee8d3fcf7e67dcdb20053889adff1989a8c859"}对于服务方已支付成功的订单,存在商户直接去商户服务平台退款的情况,此时服务方无法获悉退款操作。 可能导致服务方订单状态与实际不一致以及用户在服务方场景权益未退回等情况。 建行生活支持将服务方下单场景商户的退款操作消息通知给服务方, 服务方可基于该消息去查询A3341TP03(服务方订单查询)接口判断用户是否发生了退款以及退款金额等信息, 并推送正确的订单状态,使整个交易链路闭环,确保订单状态的一致性。
| 字段名 | 中文名 | 类型 | 备注 |
|---|---|---|---|
| NT_TYPE | 支付服务通知类型 | CHAR(9) | 当该字段有值且为为YS时,则表示此通知是由建行生活加签后发出。当该字段为CCB或为空时,则表示此通知是由建行原始通知加签后发出。该字段不参与签名 |
| ORDERID | 支付流水号 | CHAR(30) | 拉起收银台时上送的ORDERID |
| MRCH_ID | 商户号 | CHAR(256) | 商户编号 |
| REFUND_DTM | 退款时间 | CHAR(14) | 退款时间。时间格式:yyyyMMddHHmmss |
注:除不参与签名的字段外,加粗字段为验签时必输字段
签名运算原串
参与签名运算的字符串及其顺序如下:
ORDERID=210520133844test3yhv&MRCH_ID=1050000000000000000&REFUND_DTM=20250601120000
注:字符串中变量名必须是大写字母。
例1:
xxxxxxxxxx{"MRCH_ID": "","NT_TYPE": "YS","ORDERID": "210520133844test3yhv","POSID": "123442025","SUCCESS": "Y", "SIGN" : "317b7dd349c1fbcabc26a20ba117a778da5a685c588be5e7378682651062a25b0885e36ee237c19a143f7271c9529a0e9bf198c8735709dc74233d96e1a276cec9d4835422bee597100b0a47d11b44dbba74bdf9cbde0587f138141ce79a3536733d5f6b53ed119c13708dca52ee8d3fcf7e67dcdb20053889adff1989a8c859"}ORDERID=210520133844test3yhv&MRCH_ID=&REFUND_DTM=20250601120000
例2:
xxxxxxxxxx{"MRCH_ID": "1050000000000000000","NT_TYPE": "YS","ORDERID": "210520133844test3yhv","REFUND_DTM": "20250601120000", "SIGN" : "317b7dd349c1fbcabc26a20ba117a778da5a685c588be5e7378682651062a25b0885e36ee237c19a143f7271c9529a0e9bf198c8735709dc74233d96e1a276cec9d4835422bee597100b0a47d11b44dbba74bdf9cbde0587f138141ce79a3536733d5f6b53ed119c13708dca52ee8d3fcf7e67dcdb20053889adff1989a8c859"}ORDERID=210520133844test3yhv&MRCH_ID=1050000000000000000&REFUND_DTM=20250601120000
317b7dd349c1fbcabc26a20ba117a778da5a685c588be5e7378682651062a25b0885e36ee237c19a143f7271c9529a0e9bf198c8735709dc74233d96e1a276cec9d4835422bee597100b0a47d11b44dbba74bdf9cbde0587f138141ce79a3536733d5f6b53ed119c13708dca52ee8d3fcf7e67dcdb20053889adff1989a8c859
| 响应码 | 说明 |
|---|---|
| CLD_ERR_00001 | 建行生活处理失败 |
| CLD_SUCCESS | 建行生活处理成功 |
行外服务方:
使用具有唯一性的交易流水号即可,不要求编码方式
行内服务方:
流水号(全局事件跟踪号),采用4段28位编码方式,如下图所示:

善融积分:
xxxxxxxxxx{ "scene": "pointPay", // 场景 "pointAmount": "1.50", // 积分金额 "pointNum": "1050" // 积分数量}限卡支付:
xxxxxxxxxx{ "scene": "uniqueCardPay", // 场景 "cardNo": "6210123456784321", // 银行卡号}xxxxxxxxxx
import java.security.MessageDigest;
public class MD5Util {
// 生成MD5 public static String getMD5(String message) throws Exception { String md5 = ""; MessageDigest md = MessageDigest.getInstance("MD5"); // 创建一个md5算法对象 byte[] messageByte = message.getBytes("UTF-8"); byte[] md5Byte = md.digest(messageByte); // 获得MD5字节数组,16*8=128位 md5 = bytesToHex(md5Byte); // 转换为16进制字符串 return md5; }
// 二进制转十六进制 private static String bytesToHex(byte[] bytes) throws Exception { StringBuffer hexStr = new StringBuffer(); int num; for (int i = 0; i < bytes.length; i++) { num = bytes[i]; if (num < 0) { num += 256; } if (num < 16) { hexStr.append("0"); } hexStr.append(Integer.toHexString(num)); } return hexStr.toString().toUpperCase(); }}xxxxxxxxxx
import java.io.ByteArrayOutputStream;import java.security.Key;import java.security.KeyFactory;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec;import javax.crypto.Cipher;
import sun.misc.BASE64Decoder;import sun.misc.BASE64Encoder;
public class RSAUtil {
/** * 加密算法RSA */ private static final String KEY_ALGORITHM = "RSA";
/** * RSA最大加密明文大小 */ private static final int MAX_ENCRYPT_BLOCK = 117;
/** * RSA最大解密密文大小 */ private static final int MAX_DECRYPT_BLOCK = 128;
/** * Method: decryptBASE64 * description: 解码返回byte * * @param key * @return * @throws Exception */ public static byte[] decryptBASE64(String key) throws Exception { return (new BASE64Decoder()).decodeBuffer(key); }
/** * Method: encryptBASE64 * description: 编码返回字符串 * * @param key * @return * @throws Exception */ public static String encryptBASE64(byte[] key) throws Exception { return (new BASE64Encoder()).encodeBuffer(key); }
/** * 获取base64加密后的字符串的原始公钥 * * @param keyStr * @return * @throws Exception */ public static Key getPublicKeyFromBase64KeyEncodeStr(String keyStr) throws Exception { byte[] keyBytes = decryptBASE64(keyStr); // 取得公钥 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); Key publicKey = KeyFactory.getInstance(KEY_ALGORITHM).generatePublic(x509KeySpec); return publicKey; }
/** * 获取base64加密后的字符串的原始私钥 * * @param keyStr * @return * @throws Exception */ public static Key getPrivateKeyFromBase64KeyEncodeStr(String keyStr) throws Exception { byte[] keyBytes = decryptBASE64(keyStr); // 取得私钥 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); Key privateKey = KeyFactory.getInstance(KEY_ALGORITHM).generatePrivate(pkcs8KeySpec); return privateKey; }
/** * Method: encrypt * description: 公钥分段加密 * * @param dataStr * 加密内容,明文 * @param publicKeyStr * 公钥内容 * @return 密文 * @throws Exception */ public static String encrypt(String dataStr, String publicKeyStr) throws Exception { System.out.println("公钥分段加密开始"); ByteArrayOutputStream out = null; String encodedDataStr = null; try { out = new ByteArrayOutputStream(); byte[] data = dataStr.getBytes("utf-8"); // 获取原始公钥 Key decodePublicKey = getPublicKeyFromBase64KeyEncodeStr(publicKeyStr); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, decodePublicKey); int inputLen = data.length; int offSet = 0; byte[] cache; int i = 0; // 对数据分段加密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_ENCRYPT_BLOCK; } byte[] encryptedData = out.toByteArray(); encodedDataStr = new String(encryptBASE64(encryptedData)); System.out.println("公钥分段加密完毕"); } catch (Exception e) { throw e; } finally { try { out.close(); } catch (Exception e2) { // TODO: handle exception } } return encodedDataStr; }
/** * Method: encrypt * description: 私钥分段解密 * * @param content * 解密内容,密文 * @param privateKeyStr * 私钥 * @return 明文 * @throws Exception */ public static String decrypt(String dataStr, String PrivateKey) throws Exception { System.out.println("私钥分段解密处理开始");
ByteArrayOutputStream out = null; String decodedDataStr = null; try { out = new ByteArrayOutputStream();
byte[] encryptedData = decryptBASE64(dataStr); // 获取原始私钥 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key decodePrivateKey = getPrivateKeyFromBase64KeyEncodeStr(PrivateKey); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, decodePrivateKey); int inputLen = encryptedData.length;
int offSet = 0; byte[] cache; int i = 0; // 对数据分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); decodedDataStr = new String(decryptedData, "utf-8"); } catch (Exception e) { throw e; } finally { try { out.close(); } catch (Exception e2) { // TODO: handle exception } } return decodedDataStr; }
}