周期扣款

签订支付协议(已安装招商银行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. 请求报文

请求报文参数类型(长度)必填描述示例
jsonRequestDataStringMjson格式的请求参数,详见jsonRequestData定义

jsonRequestData参数定义

参数名类型(长度)必填描述示例
charsetString(8)M编码格式,固定为UTF-8(默认)UTF-8
versionString(3)M固定为1.01.0
signStringM使用商户支付密钥对reqData内的数据进行签名
signTypeStringM固定为SHA-256SHA-256
reqData请求数据


dateTimeString(14)M请求时间,商户发起该请求的时间,精确到秒。
格式:yyyyMMddHHmmss
20160623101430
merchantSerialNoString(30)M协议开通请求流水号,商户生成。
同一交易日期唯一,长度不超过30位,数字字母都可以,建议纯数字
2016062310143088
agrNoString(32)M客户协议号,不超过32位的数字字母组合。
未签约(首次支付)客户,填写新协议号,用于协议开通;已签约(再次支付)客户,填写该客户已有的协议号。商户必须对协议号进行管理,确保客户与协议号一一对应。
201606238888888
branchNoString(4)M商户分行号,4位数字0755
merchantNoString(6)M商户号,6位数字123456
mobileString(11)O商户用户的手机号13888888888
userIDString(20)O用于标识商户用户的唯一ID。
商户系统内用户唯一标识,不超过20位,数字字母都可以,建议纯数字
123abc
lonString(10)O经度,商户app获取的手机定位数据30.949505
latString(10)O纬度,商户app获取的手机定位数据50.949506
riskLevelString(3)O用户在商户系统内风险等级标识
noticeUrlString(100)M商户接收成功签约结果通知的地址http://www.xxx.com/xxx
noticeParaString(512)O成功签约结果通知附加参数,该参数在发送成功签约结果通知时,将原样返回商户。注意:该参数可为空,商户如果需要不止一个参数,可以自行把参数组合、拼装,但组合后的结果不能带有&字符。
returnUrlStringO返回商户地址,签约成功页面上返回商户按钮跳转地址,默认值:http://CMBNPRM,采用默认值的需要商户app拦截该请求,自行决定跳转交互http://www.xxx.com/yyy
periodTypeStringM周期类型枚举值:
D 按天
M 按月
N 按自然月
该字段必送且只能上送一种周期类型
D
periodString(4)M周期间隔:
字段值非空,纯数字,上送字段不能以0开头(例:001会报错);
商户送周期类型为D时,周期间隔上送值需大于等于7;
商户送周期类为M或N时,周期间隔上送值需大于等于1
1
periodMaxAmtString(20)M每期最大扣款金额:
字段值非空,纯数字,上送字段不能以0开头(例:001会报错);
单位为分,例如上送1000,相当于10.00元
1000
executeTimeString(8)M周期开始时间:
格式须是yyyyMMdd或yyyyMM;
商户送周期类型为D时,该字段应上送yyyyMMdd格式;
商户送周期类型为M时,该字段应上送yyyyMMdd格式;
商户送周期类型为N时,该字段应上送yyyyMM格式;
上送yyyyMMdd格式时,dd应小于等于28;上送yyyyMM格式时,MM应不早于当前日然日期的月份

当前日然日期为20210420,yyyyMMdd格式下可上送20210428,yyyyMM格式下可上送202104

periodTotalCntString(4)O周期总期数:
字段可不送或送空,若上送则控制协议有效的总期数;
上送值应为纯数字,不能以0开头(例:001会报错)
12
billTypeString(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
开通用户身份验证或银行卡校验功能时,需上送以下信息:
merchantUserIdTypeStringO商户上送用户的证件类型,若商户端用户未实名,不需要传该字段。
01 身份证 
02 护照 
03 其他
01
merchantUserIdNoStringO商户上送用户的证件编号,需要使用商户秘钥进行AES-256加密(秘钥需32位,不足则右侧补0),若商户端用户未实名,不需要传该字段。(生成签名串时,是直接对密文进行签名)
merchantUserNameStringO商户上送用户的姓名,需要使用商户秘钥进行AES-256加密(秘钥需32位,不足则右侧补0),若商户端用户未实名,不需要传该字段。(生成签名串时,是直接对密文进行签名)
merchantCardTypeStringO商户上送用户的银行卡类型,若商户端用户未实名,或不需要限制签约银行卡,则不需要传该字段。
02 本行借记卡
03 本行信用卡
08 他行借记卡
09 他行信用卡
02
merchantCardNoStringO商户上送用户的银行卡号,需要使用商户秘钥进行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&param2=value2&……

样例报文:

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

注意:
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 {                    
                 //跳转失败               
                 }         
         }];     
     } 
}