签订支付协议(已安装招商银行APP)
1. 接口介绍
功能简述:
商户app唤起招行APP的方式来实现周期扣款的签约,或招行APP内场景商户直接进行APP周期扣款签约
应用场景:
1、 客户在招行侧未签订“周期扣款”支付协议,商户需调用该接口为客户签约。
2、 调用该接口成功后,客户即在招行侧签订协议,并成功开通招行周期扣款功能,商户侧收到“支付协议签订成功回调通知”。
3、 客户关闭支付协议的免密功能,可调用该接口重新开通,开通成功后,商户侧收到“支付协议签订成功回调通知”。
调用方式:
目前支持以下三种调用方式:
1、商户客户端集成招行SDK,通过SDK判断客户是否安装招行APP并发起签约。集成SDK方法请参考【SDK接口】,签约字段定义请参考本文档第3节jsonRequestData的参数定义。
2、商户客户端编写代码或采用其他方式,判断客户是否安装招行APP,未安装则参考本文档第2—3节内容进行调用。
3、商户不判断客户是否安装招行APP,仅对接H5签约流程,则参考本文档第2—3节内容进行调用。
约束条件:
1、秘钥,商户需通过配置管理,方便后续调整。
2、商户需要判断是否安装招行手机银行APP,已安装采用此方案。
正常流程:
1、商户APP唤起招行手机银行APP,或从招行APP内发起。
2、用户使用一网通登录后,信息校验通过后,正常签约成功。
异常流程:
1、用户信息校验不通过,界面报错,签约停止
2. 请求地址
1)招行App内的商户使用
var url = “http://cmbls/functionjump?action=gofuncid&funcid=0027024&clean=false&cmb_app_trans_parms_start=here&jsonRequestData=“ + encodeURIComponent($(“#jsonRequestData”).val());—-json组织同下方
2)在商户App内使用:
cmbmobilebank://CMBLS/FunctionJump?action=gofuncid&funcid=0027024&requesttype=post&cmb_app_trans_parms_start=here&jsonRequestData={“charset”:”UTF-8”,”sign”:”见签名处理章节”,”reqData”:{“agrNo”:”201606238888888”,”branchNo”:”0755”,”dateTime”:”20160623101430”,”lat”:”30.949505”,”lon”:”50.949506”,”merchantNo”:”123456”,”merchantSerialNo”:”2016062310143088”,”mobile”:”13888888888”,”noticePara”:””,”noticeUrl”:”http://www.xxx.com/xxx","userID":"2016062388888"}}
注意事项:jsonRequestData的值需要做urlEncode。
3. 请求报文
请求报文参数 | 类型(长度) | 必填 | 描述 | 示例 |
---|---|---|---|---|
jsonRequestData | String | M | json格式的请求参数,详见jsonRequestData定义 |
jsonRequestData参数定义
参数名 | 类型(长度) | 必填 | 描述 | 示例 |
---|---|---|---|---|
charset | String(8) | M | 编码格式,固定为UTF-8(默认) | UTF-8 |
version | String(3) | M | 固定为1.0 | 1.0 |
sign | String | M | 使用商户支付密钥对reqData内的数据进行签名 | |
signType | String | M | 固定为SHA-256 | SHA-256 |
reqData | 请求数据 | |||
dateTime | String(14) | M | 请求时间,商户发起该请求的时间,精确到秒。 格式: yyyyMMddHHmmss | 20160623101430 |
merchantSerialNo | String(30) | M | 协议开通请求流水号,商户生成。 同一交易日期唯一,长度不超过30位,数字字母都可以,建议纯数字 | 2016062310143088 |
agrNo | String(32) | M | 客户协议号,不超过32位的数字字母组合。 未签约(首次支付)客户,填写新协议号,用于协议开通;已签约(再次支付)客户,填写该客户已有的协议号。商户必须对协议号进行管理,确保客户与协议号一一对应。 | 201606238888888 |
branchNo | String(4) | M | 商户分行号,4位数字 | 0755 |
merchantNo | String(6) | M | 商户号,6位数字 | 123456 |
mobile | String(11) | O | 商户用户的手机号 | 13888888888 |
userID | String(20) | O | 用于标识商户用户的唯一ID。 商户系统内用户唯一标识,不超过20位,数字字母都可以,建议纯数字 | 123abc |
lon | String(10) | O | 经度,商户app获取的手机定位数据 | 30.949505 |
lat | String(10) | O | 纬度,商户app获取的手机定位数据 | 50.949506 |
riskLevel | String(3) | O | 用户在商户系统内风险等级标识 | |
noticeUrl | String(100) | M | 商户接收成功签约结果通知的地址 | http://www.xxx.com/xxx |
noticePara | String(256) | O | 成功签约结果通知附加参数,该参数在发送成功签约结果通知时,将原样返回商户。注意:该参数可为空,商户如果需要不止一个参数,可以自行把参数组合、拼装,但组合后的结果不能带有& 字符。 | |
returnUrl | String | O | 返回商户地址,签约成功页面上返回商户 按钮跳转地址,默认值:http://CMBNPRM ,采用默认值的需要商户app拦截该请求,自行决定跳转交互 | http://www.xxx.com/yyy |
periodType | String | M | 周期类型枚举值:D 按天M 按月N 按自然月该字段必送且只能上送一种周期类型 | D |
period | String(4) | M | 周期间隔: 字段值非空,纯数字,上送字段不能以0开头(例:001会报错); 商户送周期类型为D时,周期间隔上送值需大于等于7; 商户送周期类为M或N时,周期间隔上送值需大于等于1 | 1 |
periodMaxAmt | String(20) | M | 每期最大扣款金额: 字段值非空,纯数字,上送字段不能以0开头(例:001会报错); 单位为分,例如上送1000,相当于10.00元 | 1000 |
executeTime | String(8) | M | 周期开始时间: 格式须是yyyyMMdd或yyyyMM; 商户送周期类型为D时,该字段应上送yyyyMMdd格式; 商户送周期类型为M时,该字段应上送yyyyMMdd格式; 商户送周期类型为N时,该字段应上送yyyyMM格式; 上送yyyyMMdd格式时,dd应小于等于28;上送yyyyMM格式时,MM应不早于当前日然日期的月份 | 当前日然日期为20210420,yyyyMMdd格式下可上送 |
periodTotalCnt | String(4) | O | 周期总期数: 字段可不送或送空,若上送则控制协议有效的总期数; 上送值应为纯数字,不能以0开头(例:001会报错) | 12 |
billType | String(4) | M | 代收款项:01 移动电话;02 固定电话;03 水费;04 电费;05 煤气费;06 社保;07 小灵通;08 信用卡还款;09 烟草;10 信用卡中心;11 有线和付费电视;12 保险;13 税务;14 证券公司;15 金融机构;16 贷款还款;17 网络服务费;18 资金归集;19 教育费;20 物业管理费;21 公益捐款;22 财税库银;23 商户实时入账;24 其他 | 03 |
开通用户身份验证或银行卡校验功能时,需上送以下信息: | ||||
merchantUserIdType | String | O | 商户上送用户的证件类型,若商户端用户未实名,不需要传该字段。01 身份证 02 护照 03 其他 | 01 |
merchantUserIdNo | String | O | 商户上送用户的证件编号,需要使用商户秘钥进行AES-256 加密(秘钥需32位,不足则右侧补0),若商户端用户未实名,不需要传该字段。(生成签名串时,是直接对密文进行签名) | |
merchantUserName | String | O | 商户上送用户的姓名,需要使用商户秘钥进行AES-256 加密(秘钥需32位,不足则右侧补0),若商户端用户未实名,不需要传该字段。(生成签名串时,是直接对密文进行签名) | |
merchantCardType | String | O | 商户上送用户的银行卡类型,若商户端用户未实名,或不需要限制签约银行卡,则不需要传该字段。02 本行借记卡03 本行信用卡08 他行借记卡09 他行信用卡 | 02 |
merchantCardNo | String | O | 商户上送用户的银行卡号,需要使用商户秘钥进行AES-256 加密(秘钥需32位,不足则右侧补0),若商户端用户未实名,或不需要限制签约银行卡,不需要传该字段。(生成签名串时,是直接对密文进行签名) |
请求示例:
json报文组织:
{ "version":"1.0", "charset":"UTF-8", "sign":"见签名处理章节", "signType":"SHA-256", "reqData":{ "agrNo":"201707232442421234500", "branchNo":"0451", "dateTime":"20210413215632", "lat":"30.949505", "lon":"50.949506", "merchantNo":"000013", "merchantSerialNo":"20210413215632", "mobile":"13888888888", "returnUrl":"http://99.6.150.225:811/euserpayos/enterPage/SignJson.html", "noticeUrl":"http://www.merchant.com/path/WAPProcResult.dll", "userID":"0000000001", "noticePara":"", "merchantUserIdType":"", "merchantUserIdNo":"", "merchantUserName":"", "merchantCardType":"", "merchantCardNo":"", "merchantUserInfoEncryptType":"", "periodType":"M", "period":"1", "periodMaxAmt":"1000", "executeTime":"20210411", "periodTotalCnt":"12", "billType":"01" } }
表单组织:
<form action="请求地址" method="post" > <input type="hidden" name="jsonRequestData" value='以上json字符串' /> </form>
待签名字符串(未包含支付密钥):
首先组成待签名字符串。待签名字符串组成规则为:对reqData所有请求参数按从a到z的顺序排列,如果首字母相同,按第二个字母排列,以此类推。排序完成后按将所有键值对以&
符号拼接:
param1=value1¶m2=value2&……
样例报文:
agrNo=201606238888888&branchNo=0755&dateTime=20160623101430&lat=30.949505&lon=50.949506&merchantNo=123456&merchantSerialNo=2016062310143088&mobile=13888888888¬icePara=¬iceUrl=http://www.xxx.com/xxx&userID=2016062388888
注意:
1、所有reqData中请求参数,即便其值为空,也加入签名字符串
2、签名时,按指定的字符集将字符串转换为字节流
3、根据HTTP协议要求,如果请求参数值中有特殊字符,如&
、@
等,需进行URLEncoding处理。待签名数据为原生值而非encoding后的值。
4. 响应报文
1、网页端直接展示签约成功或失败结果,无响应报文。
2、签约成功后有异步结果通知,失败无通知。详见【支付协议签订成功回调通知】。
5. 错误码
无
6. FAQ
参考【签订支付协议(未安装招商银行APP)】 FAQ
7. 商户APP调用招商银行APP签约功能样例
Android平台样例:
Private void callCMBApp() { final String url = “cmbmobilebank://CMBLS/FunctionJump? action=gofuncid&funcid=0027013&requesttype=post&cmb_app_trans_parms_start=here &……”; try { Intent intent = new Intent(); Uri data = Uri.parse(url); intent.setData(data); intent.setAction("android.intent.action.VIEW"); startActivity(intent); } catch(Exception e) { Log.d(TAG, "Exception", e); } }
iOS平台样例:
(void)callCMBApp { NSURL *url = [NSURL URLWithString: @"cmbmobilebank://CMBLS/FunctionJump? action=gofuncid&funcid=0027013&requesttype=post&cmb_app_trans_parms_start=here&..."]; if (![[UIApplication sharedApplication] canOpenURL:url]) { //没有安装手机银行或没有添加scheme" return; } CGFloat systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue]; if (systemVersion < 10.0f) { BOOL success = [[UIApplication sharedApplication] openURL:url]; if (success) { //跳转成功 }else { //跳转失败 } }else { [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) { if (success) { //跳转成功 }else { //跳转失败 } }]; } }