目录:
- 场景介绍
1.1 医后付场景 - 接入指引
2.1 准备工作
2.2 接口调用规范
2.2.1 请求说明 - API列表
3.1 获取签约URL
3.2 签约查询
3.3 协议解约
3.4 代扣支付
3.5 交易结果查询接口
3.6 交易退款接口
3.7 交易退款结果查询接口
3.8 关闭订单
3.9 对账文件下载 - 修订记录
1. 场景介绍
商户发起获取签约URL请求,并且发送相关参数,商户可以拿到响应的签约URL,制作成二维码用户使用支付宝APP扫描,或者用签约URL唤醒支付宝APP进行扫描完成签约。然后使用签约号可以进行支付,查询,解约等操作
1.2 医后付场景
医后付,商户先对用户进行签约拿到签约号,然后可以进行支付等操作。
注意:用于签约的机器,建议能够访问外网。因为扫码签约的时候,二维码页面是由支付宝重定向生成的,内网环境,需要配置白名单进行测试。
需要开通外网白名单地址:
扫码签约二维码示例:
2. 接入指引
2.1 准备工作
第一步、在支付宝/微信的开放平台申请应用
由于第三方平台针对“签约代扣”功能做了限制,“非公立机构”无法开通该功能,创业的聚合支付平台作企业,无法挂载该功能像当面付一样进行接口调用,需要院方以公立机构的主体,使用
收款商户号对应的账号
去支付宝开放平台或微信开放平台申请应用得到appid
,生成公私钥或者密钥等加签信息,并申请开通“会员”相关功能,通过审核后,接口即可正常调用。
需要提供给平台技术支持人员的数据有:
- 支付宝
- appid(应用id)
- pid(商户号)
- 支付宝公钥
- 应用私钥
- 微信
- appid(应用id)
- mchId(商户号)
- mchKey
第二步、获取开发者数据
调用聚合支付平台接口,需要与平台商务对接后,获取开发者ID(developId),密钥(privateKey),公钥(publicKey)和对称密钥(desKey),这些参数让商户拥有调用平台接口的权限,对请求的数据进行加密以保证数据的安全性。
- 开发者ID(developerId):
developerId在所有的请求中都需要传入,与密钥公钥信息相对应,鉴别请求是否是由平台商户发起。
- 密钥(privateKey):
密钥在接口请求中用于对数据进行RSA加密,生成签名sign。
- 公钥(publicKey):
公钥用于对签名进行解密
- 对称密钥(desKey):
在线上支付中,<body>标签的中的参数,需要通过des进行对称加密,得到密文进行请求。
第三步、获取平台商户号
每个商户对接聚合支付平台,在第三方平台想要拥有的支付能力,需要在支付宝或者微信签约对应的支付方式,平台的商务会为每个商户分配一个平台商户号(merchantNo),该商户号账户下所有的交易流水都会进入到对应的支付宝和微信的账户下,并且平台账单流水都是以商户号进行隔离,这是一个非常重要的参数。
由于自助机通过获取设备信息,需要传入平台信息,
因此,除了上述参数,还需要拿到以下信息:
平台应用id(appId)
平台pid(partnerId)
第四步、下载加解密sdk和demo
- java版本:加解密工具java版本
2.2 接口调用规范
2.2.1 请求说明
接口通信地址:
测试环境:http://offlinetest.bsoftpay.com/gatewayOffline/pay/offline/execute
正式环境:由平台商务对接人员提供http请求格式:
Content-type:x-www-form-urlencoded
公共请求参数说明:
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例 |
---|---|---|---|---|---|
data | String | 是 | 300 | 请求参数转为xml格式 | <xml><paytype>2</paytype><merchant_no>10000</merchant_no></xml> |
developerId | String | 是 | 10 | 开发者id | 12345 |
funcId | String | 是 | 20 | 功能码 | P7001 |
sign | String | 是 | 100 | 将公共参数以“参数名”ASCII码顺序排序拼接成新字符串(参数名ASCII码从小到大排序(字典序))得到:“data=value1&developerId=value2&funcId=value3”,再将新的字符串经过RSA签名得到签名后的字符串 | Sa/hb9jaTZZZq89mN62DDooLv/YTvfE9ayrbzgOMsucfIPZfJGmhUia6YWK8vQ5/NQana3Pub7BDswEenm0sBg== |
- 公共返回参数说明:
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例 |
---|---|---|---|---|---|
retCode | String | 是 | 30 | 0000:表示接口业务调用正常,9999:表示处理失败,如参数错误,验签失败等(注:retCode并不表示交易行为成功或失败,某笔交易是否成功请根据对应接口返回报文的状态字段来判定) | 0000 |
retMsg | String | 是 | 100 | 接口调用异常返回信息 | 验签失败 |
3. API列表
3.1 获取签约URL
功能码:P9005
接口说明:通过该接口获得扫码签约的链接,在客户机浏览器中访问该链接,会在页面生成签约二维码,供用户扫码进行签约(注意:每次获取签约URL时,商户给用户分配的商户协议号唯一)
请求参数:
<xml>
参数 | 名称 | 类型 | 长度 | 是否必填 | 说明 | 示例 |
---|---|---|---|---|---|---|
merchant_no | 收款商户号 | String | 30 | 是 | 创业聚合支付系统为医院分配的平台商户号 | 809900000001 |
merchant_agreement_no | 商户协议号 | String | 64 | 是 | 商户给用户分配的协议号 商户内唯一 |
test |
channel_type | 渠道类型 | String | 2 | 是 | 2=支付宝 | 2 |
sign_type | 签约类型 | String | 2 | 是 | 1=扫码签约, 2=钱包h5页面签约 | 1 |
idcard | 用户身份证号 | String | 24 | 否 | 用户身份证号,用户姓名,用户身份证号和用户信息都传才能用于校验用户信息 |
61102619921108888 |
username | 用户姓名 | String | 32 | 否 | 用户姓名,用户身份证号和用户信息都传才能用于校验用户信息 |
张三 |
mobile | 手机号 | String | 32 | 否 | 用户手机号 | 13211112222 |
outer_id | 用户唯一标识 | String | 64 | 否 | 商户端用户唯一标识 | 1 |
- 响应参数:
参数 | 名称 | 类型 | 长度 | 是否必输 | 说明 | 示例 |
---|---|---|---|---|---|---|
return_code | 返回状态码 | String | 16 | 否 | SUCCESS/OK代表成功 FAIL=代表失败 | SUCCESS |
return_msg | 返回信息 | String | 128 | 否 | 返回信息 | OK |
merchant_agreement_no | 商户协议号 | String | 64 | 是 | 商户给用户分配的协议号 商户内唯一 |
|
sign_url | 签约url | String | 1000 | 是 | 用于签约的url, 成功必传使用前先用URLDecoder 解码 |
1 |
outerid | 用户唯一标识 | String | 64 | 否 | 商户端用户唯一标识,返回请求传入的值 | 4200000376201908224052992001 |
- Java请求示例:
String data = "<xml>" + "<merchant_agreement_no>test</merchant_agreement_no>" + "<idcard>61102619921108888</idcard>" + "<username>测试者</username>" + "<mobile>123213213</mobile>" + "<merchant_no>1001003</merchant_no>" + "<channel_type>2</channel_type>" + "<sign_type>1</sign_type>" + "<outer_id>12321</outer_id>" + "</xml>"; List<NameValuePair> list = new ArrayList<NameValuePair>(); NameValuePair valu1 = new BasicNameValuePair("data",data); NameValuePair valu2 = new BasicNameValuePair("developerId",[your developerId]); NameValuePair valu3 = new BasicNameValuePair("funcId","P9005"); String privateKey = [your privateKey]; String signData = "data="+data+"&developerId=[your developerId]&funcId=P9005"; String sign = SecurityUtil.signRSA(signData,privateKey,"utf-8"); NameValuePair valu4 = new BasicNameValuePair("sign",sign); list.add(valu1); list.add(valu2); list.add(valu3); list.add(valu4); String xml = null; try { CloseableHttpResponse response = HttpClients.custom().build().execute(RequestBuilder.post().setUri("http://offlinetest.bsoftpay.com/gatewayOffline/pay/offline/execute").setEntity(new UrlEncodedFormEntity(list, Consts.UTF_8)).build()); xml = EntityUtils.toString(response.getEntity()); } catch (Exception e) { e.printStackTrace(); } System.out.println(xml);
- 返回示例:
developerId=12345&funcId=P9005&retCode=0000&retMsg= &data=<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <xml> <return_code>SUCCESS</return_code> <return_msg>生成连接成功</return_msg> <merchant_agreement_no>test</merchtestant_agreement_no> <sign_url>alipays%3A%2F%2Fplatformapi%2Fstartapp%3FappId%3D60000157%26appClearTop%3Dfalse%26startMultApp%3DYES%26sign_params%3Dalipay_sdk%253Dalipay-sdk-java-3.7.4.ALL%2526app_id%253D2019122060095079%2526biz_content%253D%25257B%252522access_params%252522%25253A%25257B%252522channel%252522%25253A%252522ALIPAYAPP%252522%25257D%25252C%252522external_agreement_no%252522%25253A%25252240%252522%25252C%252522personal_product_code%252522%25253A%252522GENERAL_WITHHOLDING_P%252522%25252C%252522sign_scene%252522%25253A%252522INDUSTRY%25257CMEDICAL%252522%25257D%2526charset%253Dutf-8%2526format%253Djson%2526method%253Dalipay.user.agreement.page.sign%2526sign%253DMFoOTtXEDqrGK1F0nmJ8pQenba8LJ5mlRe5MhivqLeOkpThueIXRLjYaE3Z8U8EUBd5e25khHkhiVcFCjWIdJmWKhFkRKTNzVmZJueV2cZYGOtnaf0ZajWgQJMY3Md2Rhm0o6zT6mH0UBwipcaYv%25252FbxCDAkOTWKNOtP1uZePko5m0N7%25252BSCeBYdGH6dnAOc9tAHpbBmjQyFq0izVtHf4Fyt3Gftux1qXD2vz91qqKfvXoi%25252B80eYt2HH6ovtrSpuDa502YtdTP1gw7tuIandWFCKhvEUeTkDNDEB8izU6e8k9%25252FlFg2YykbKuXR2%25252Be2U4INnSRv1NXOxSuop%25252Bn2rBhOSg%25253D%25253D%2526sign_type%253DRSA2%2526timestamp%253D2019-12-24%252B11%25253A19%25253A52%2526version%253D1.0</sign_url> <outerid>1</outerid> </xml> &sign=Apu4i49RBQkh94n5BVEA/Ao35tjfT8BsTPA9fOqKUmbKJ37Pszfi0sS9R15OLEpXJYo6p2v+uw1fr/BE+PSxHg==
- 异常返回示例:
developerId=12345&funcId=P9005&retCode=9999&retMsg=签约功能还未开通&sign=XD1unE4I2pM/jWMXy1o7NwVB2H3yfkmxluH2qz3xRt+mB8VQNSLhKnz79+5PuRfz9Q4y44CKCyL7S21iQzOHbg==
- 注意:签名sign生成之后,在请求发送之前,需要对签名字符串进行urlEncode编码,否则字符串在传递过程中可能会不完整,从而导致“验证签名失败”
3.2 签约查询
- 功能码:P9006
- 接口说明:获取签约协议状态。
- 请求参数:
<xml>
参数 | 名称 | 类型 | 长度 | 是否必填 | 说明 | 示例 |
---|---|---|---|---|---|---|
merchant_no | 收款商户号 | String | 30 | 是 | 创业聚合支付系统为医院分配的平台商户号 | 809900000001 |
merchant_agreement_no | 商户协议号 | String | 64 | 是 | 商户给用户分配的协议号 商户内唯一 |
test |
- 响应参数:
参数 | 名称 | 类型 | 长度 | 是否必输 | 说明 | 示例 |
---|---|---|---|---|---|---|
return_code | 返回状态码 | String | 16 | 否 | SUCCESS/OK代表成功 FAIL=代表失败 | SUCCESS |
return_msg | 返回信息 | String | 128 | 否 | 返回信息 | OK |
merchant_agreement_no | 商户协议号 | String | 64 | 是 | 商户给用户分配的协议号 商户内唯一 |
|
status | 签约状态 | String | 2 | 是 | 0-未签约,1=已签约 ,2=解约 | 1 |
valid_time | 渠道生效时间 | String | 10 | 否 | 签约生效时间 | 20170520114919 |
invalid_time | 渠道失效时间 | String | 10 | 否 | 签约失效时间 | 20170520114919 |
sign_time | 渠道签约时间 | String | 10 | 否 | 签约失效时间 | 20170520114919 |
unsign_time | 渠道解约时间 | String | 10 | 否 | 渠道解约时间 | 20170520114919 |
outerid | 用户唯一标识 | String | 64 | 否 | 商户端用户唯一标识,返回请求传入的值 | 4200000376201908224052992001 |
- Java请求示例:
String data = "<xml>" + "<merchant_no>1001003</merchant_no>" + "<merchant_agreement_no>test</merchant_agreement_no>" + "</xml>"; List<NameValuePair> list = new ArrayList<NameValuePair>(); NameValuePair valu1 = new BasicNameValuePair("data",data); NameValuePair valu2 = new BasicNameValuePair("developerId",[your developerId]); NameValuePair valu3 = new BasicNameValuePair("funcId","P9006"); String privateKey = [your privateKey]; String signData = "data="+data+"&developerId=[your developerId]&funcId=P9006"; String sign = SecurityUtil.signRSA(signData,privateKey,"utf-8"); NameValuePair valu4 = new BasicNameValuePair("sign",sign); list.add(valu1); list.add(valu2); list.add(valu3); list.add(valu4); String xml = null; try { CloseableHttpResponse response = HttpClients.custom().build().execute(RequestBuilder.post().setUri("http://offlinetest.bsoftpay.com/gatewayOffline/pay/offline/execute").setEntity(new UrlEncodedFormEntity(list, Consts.UTF_8)).build()); xml = EntityUtils.toString(response.getEntity()); } catch (Exception e) { e.printStackTrace(); } System.out.println(xml);
- 返回示例:
developerId=12345&funcId=P9005&retCode=0000&retMsg= &data=<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <xml> <return_code>SUCCESS</return_code> <return_msg>操作成功</return_msg> <return_code>test</merchtestant_agreement_no> <valid_time>20170520114919</valid_time> <invalid_time>20170520114919</invalid_time> <sign_time>1</sign_time> <unsign_time>1</unsign_time> <outerid>1</outerid> </xml> &sign=Apu4i49RBQkh94n5BVEA/Ao35tjfT8BsTPA9fOqKUmbKJ37Pszfi0sS9R15OLEpXJYo6p2v+uw1fr/BE+PSxHg==
- 异常返回示例:
developerId=12345&funcId=P9005&retCode=9999&retMsg=该商户号不存在&sign=XD1unE4I2pM/jWMXy1o7NwVB2H3yfkmxluH2qz3xRt+mB8VQNSLhKnz79+5PuRfz9Q4y44CKCyL7S21iQzOHbg==
3.3 协议解约
- 功能码:P9007
- 接口说明:保证每次获取签约URL时,商户给用户分配的商户协议号唯一。
- 请求参数:
<xml>
参数 | 名称 | 类型 | 长度 | 是否必填 | 说明 | 示例 |
---|---|---|---|---|---|---|
merchant_no | 收款商户号 | String | 30 | 是 | 创业聚合支付系统为医院分配的平台商户号 | 809900000001 |
merchant_agreement_no | 商户协议号 | String | 64 | 是 | 商户给用户分配的协议号 商户内唯一 |
test |
- 响应参数:
参数 | 名称 | 类型 | 长度 | 是否必输 | 说明 | 示例 |
---|---|---|---|---|---|---|
return_code | 返回状态码 | String | 16 | 否 | SUCCESS/OK代表成功 FAIL=代表失败 | SUCCESS |
return_msg | 返回信息 | String | 128 | 否 | 返回信息 | OK |
merchant_agreement_no | 商户协议号 | String | 64 | 是 | 商户给用户分配的协议号 商户内唯一 |
|
status | 签约状态 | String | 2 | 是 | 0-未签约,1=已签约 ,2=解约 | 3 |
valid_time | 渠道生效时间 | String | 10 | 否 | 签约生效时间 | 20170520114919 |
invalid_time | 渠道失效时间 | String | 10 | 否 | 签约失效时间 | 20170520114919 |
- Java请求示例:
String data = "<xml>" + "<merchant_no>1001003</merchant_no>" + "<merchant_agreement_no>test</merchant_agreement_no>" + "</xml>"; List<NameValuePair> list = new ArrayList<NameValuePair>(); NameValuePair valu1 = new BasicNameValuePair("data",data); NameValuePair valu2 = new BasicNameValuePair("developerId",[your developerId]); NameValuePair valu3 = new BasicNameValuePair("funcId","P9007"); String privateKey = [your privateKey]; String signData = "data="+data+"&developerId=[your developerId]&funcId=P9007"; String sign = SecurityUtil.signRSA(signData,privateKey,"utf-8"); NameValuePair valu4 = new BasicNameValuePair("sign",sign); list.add(valu1); list.add(valu2); list.add(valu3); list.add(valu4); String xml = null; try { CloseableHttpResponse response = HttpClients.custom().build().execute(RequestBuilder.post().setUri("http://offlinetest.bsoftpay.com/gatewayOffline/pay/offline/execute").setEntity(new UrlEncodedFormEntity(list, Consts.UTF_8)).build()); xml = EntityUtils.toString(response.getEntity()); } catch (Exception e) { e.printStackTrace(); } System.out.println(xml);
- 返回示例:
developerId=12345&funcId=P9007&retCode=0000&retMsg= &data=<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <xml> <return_code>SUCCESS</return_code> <return_msg>生成连接成功</return_msg> <status>3</status> <merchant_agreement_no>test</merchtestant_agreement_no> <valid_time>20170520114919</valid_time> <invalid_time>20170520114919</invalid_time> </xml> &sign=Apu4i49RBQkh94n5BVEA/Ao35tjfT8BsTPA9fOqKUmbKJ37Pszfi0sS9R15OLEpXJYo6p2v+uw1fr/BE+PSxHg==
- 异常返回示例:
developerId=12345&funcId=P9005&retCode=9999&retMsg=该商户号不存在&sign=XD1unE4I2pM/jWMXy1o7NwVB2H3yfkmxluH2qz3xRt+mB8VQNSLhKnz79+5PuRfz9Q4y44CKCyL7S21iQzOHbg==
3.4 代扣支付
- 功能码:P7001
- 接口说明:代扣支付,必传签约协议号。
- 请求参数:
<xml>
参数 | 名称 | 类型 | 长度 | 是否必填 | 说明 | 示例 |
---|---|---|---|---|---|---|
treatment_id | 诊疗卡卡号 | String | 30 | 是 | 患者的诊疗卡卡号 | 123 |
merchant_no | 收款商户号 | String | 30 | 是 | 创业聚合支付系统为医院分配的平台商户号 | 809900000001 |
username | 支付者姓名 | String | 30 | 是 | 付款者姓名 | 张三 |
order_no | 业务单号 | String | 30 | 是 | 商户业务系统的唯一订单号 | BX20190722902141 |
paytype | 支付渠道 | String | 2 | 是 | 2=支付宝; 3=微信 | 2 |
trade_type | 交易类型 | String | 2 | 是 | 10=签约代扣 |
10 |
total_amt | 支付金额 | Price | 20.2 | 是 | 以元为单位 | 0.01 |
spbill_create_ip | 用户IP | String | 10 | 是 | 客户端实际ip(微信需要) | 183.156.115.113 |
order_subject | 商品标题 | String | 150 | 是 | 如:门诊、住院预交、住院结算、自助缴费等 | 门诊 |
order_detail | 商品描述 | String | 300 | 是 | 如:门诊挂号、门诊结算、住院预交、住院结算、自助挂号、自助结算、自助住院预交等 | 门诊挂号 |
merchant_agreement_no | 商户签约协议号 | String | 64 | 是 | 商户给用户分配的协议号,用户签约的唯一标识 商户内唯一,必传 |
|
sub_merchant | 分店号 | String | 30 | 否 | 商户内部区分订单字段 | 001 |
paytimeout | 订单超时时间 | String | 3 | 否 | 单位是: m (分钟) 如果不填,默认是 6分钟,如果填,必须大于5分钟 | 6 |
mobile | 手机号码 | String | 15 | 否 | 用户手机号 | 13211112222 |
remark | 备注 | String | 200 | 否 | 备注 |
- 响应参数:
参数 | 名称 | 类型 | 长度 | 是否必输 | 说明 | 示例 |
---|---|---|---|---|---|---|
return_code | 返回状态码 | String | 16 | 否 | SUCCESS/OK代表成功 FAIL=代表失败 WAIT=待支付 不能以此作为支付成功标志,支付结果以status为准 |
SUCCESS |
return_msg | 返回信息 | String | 128 | 否 | 返回信息 | OK |
status | 支付状态 | String | 2 | 否 | 1=成功;0=支付中 需要调用查询接口轮询查询订单状态 |
1 |
pay_orderno | 支付渠道流水号 | String | 32 | 否 | 支付宝或微信流水号 | 4200000376201908224052992001 |
order_no | 平台流水号 | String | 32 | 否 | 商户内部流水号 | 34411000 |
out_tradeno | 业务单号 | String | 32 | 否 | 聚合支付平台流水号 | BX20190722902141 |
time_end | 支付完成时间 | String | 32 | 否 | 支付完成时间,格式:yyyyMMddHHmmss | 20190722205306 |
amt | 实际支付金额 | Price | 16.2 | 否 | 实际支付金额 | 0.01 |
receipt_amount | 商户收到的金额 | Price | 16.2 | 否 | 商户收到的金额(相当于订单支付金额) | 0.01 |
- Java请求示例:
String data = "<xml>" + "<treatment_id>123123123123</treatment_id>" + "<merchant_no>1001003</merchant_no>" + "<username>测试者</username>" + "<order_no>"+ "xw20190722001"+"</order_no>" + "<paytype>3</paytype>" + "<trade_type>2</trade_type>" + "<total_amt>0.01</total_amt>" + "<spbill_create_ip>192.168.11.1</spbill_create_ip>" + "<order_subject>测试</order_subject>" + "<order_detail>测试</order_detail>" + "<merchant_agreement_no>130195331105619585</merchant_agreement_no>" + "</xml>"; List<NameValuePair> list = new ArrayList<NameValuePair>(); NameValuePair valu1 = new BasicNameValuePair("data",data); NameValuePair valu2 = new BasicNameValuePair("developerId",[your developerId]); NameValuePair valu3 = new BasicNameValuePair("funcId","P7001"); String privateKey = [your privateKey]; String signData = "data="+data+"&developerId=[your developerId]&funcId=P7001"; String sign = SecurityUtil.signRSA(signData,privateKey,"utf-8"); NameValuePair valu4 = new BasicNameValuePair("sign",sign); list.add(valu1); list.add(valu2); list.add(valu3); list.add(valu4); String xml = null; try { CloseableHttpResponse response = HttpClients.custom().build().execute(RequestBuilder.post().setUri("http://offlinetest.bsoftpay.com/gatewayOffline/pay/offline/execute").setEntity(new UrlEncodedFormEntity(list, Consts.UTF_8)).build()); xml = EntityUtils.toString(response.getEntity()); } catch (Exception e) { e.printStackTrace(); } System.out.println(xml);
- 返回示例:
developerId=12345&funcId=P7001&retCode=0000&retMsg= &data=<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <xml> <return_code>SUCCESS</return_code> <return_msg>OK</return_msg> <status>1</status> <pay_orderno>4200000376201907220000000000</pay_orderno> <order_no>34411000</order_no> <out_tradeno>WX15637998177239200001</out_tradeno> <time_end>20190722205306</time_end> <amt>0.01</amt> <receipt_amount>0.01</receipt_amount> </xml> &sign=Apu4i49RBQkh94n5BVEA/Ao35tjfT8BsTPA9fOqKUmbKJ37Pszfi0sS9R15OLEpXJYo6p2v+uw1fr/BE+PSxHg==
- 异常返回示例:
developerId=12345&funcId=P7001&retCode=9999&retMsg=商户协议号:tet未签约&sign=XD1unE4I2pM/jWMXy1o7NwVB2H3yfkmxluH2qz3xRt+mB8VQNSLhKnz79+5PuRfz9Q4y44CKCyL7S21iQzOHbg==
- 注意:签名sign生成之后,在请求发送之前,需要对签名字符串进行urlEncode编码,否则字符串在传递过程中可能会不完整,从而导致“验证签名失败”
3.5 交易结果查询接口
- 功能码:P2005
- 接口说明:通过该接口获取某个订单的支付结果
- 请求参数:
<Data>
参数 | 名称 | 类型 | 长度 | 是否必填 | 说明 | 示例 |
---|---|---|---|---|---|---|
order_no | 业务单号 | String | 32 | 是 | 商户内部业务单号 | WX2019072200001 |
merchant_no | 收款商户号 | String | 32 | 是 | 商户号 | 809900000001 |
- 响应参数:
参数 | 名称 | 类型 | 长度 | 是否必输 | 说明 | 示例 |
---|---|---|---|---|---|---|
TradeNo | 平台流水号 | String | 32 | 是 | 聚合支付平台流水号 | 34411000 |
PayTradeNo | 渠道流水号 | String | 32 | 是 | 各个支付渠道返回的流水号 | 4200000376201907220000000000 |
OrderNo | 业务单号 | String | 32 | 是 | 商户内部业务单号 | WX2019072200001 |
Amt | 实际支付金额 | Price | 16.2 | 是 | 用户实际付款金额 | 0.01 |
PayTime | 实际支付时间 | String | 16 | 是 | yyyy-MM-dd hh:mm:ss | 2019-07-22 21:37:31 |
PayStatus | 支付状态 | String | 6 | 是 | 0=未支付;1=支付成功;2=支付失败;-1=关闭或撤销 | 1 |
receipt_amount | 商户收到的金额 | Price | 16.2 | 是 | 相当于订单支付金额 | 0.01 |
- JAVA请求示例:
String data = "<Data>" + "<order_no>WX2019072200001</order_no>\n" + "<merchant_no>809900000001</merchant_no>\n"+ "</Data>"; List<NameValuePair> list = new ArrayList<NameValuePair>(); NameValuePair valu1 = new BasicNameValuePair("data",data); NameValuePair valu2 = new BasicNameValuePair("developerId",[your developerId]"); NameValuePair valu3 = new BasicNameValuePair("funcId","P2005"); String privateKey = [your privateKey]; String signData = "data="+data+"&developerId=[your developerId]&funcId=P2005"; String sign = SecurityUtil.signRSA(signData,privateKey,"utf-8"); NameValuePair valu4 = new BasicNameValuePair("sign",sign); list.add(valu1); list.add(valu2); list.add(valu3); list.add(valu4); String xml = null; try { CloseableHttpResponse response = HttpClients.custom().build().execute(RequestBuilder.post().setUri("http://offlinetest.bsoftpay.com/gatewayOffline/pay/offline/execute").setEntity(new UrlEncodedFormEntity(list, Consts.UTF_8)).build()); xml = EntityUtils.toString(response.getEntity()); } catch (Exception e) { e.printStackTrace(); } System.out.println(xml);
- 返回示例:
developerId=66337&funcId=P2005&retCode=0000&retMsg= &data=<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Data> <TradeNo>34411000</TradeNo> <PayTradeNo>4200000376201907220000000000</PayTradeNo> <OrderNo>WX2019072200001</OrderNo> <Amt>0.01</Amt> <receipt_amount>0.01</receipt_amount> <PayTime>2019-07-22 21:37:31</PayTime> <PayStatus>1</PayStatus> </Data> &sign=JxUbXFPS4Kp3bS9ipmznDoAwBd3TzLX4Df8xd5VFR97Z1Kyb5XiJNxZ4LXA1RIlOafm+BmmnPXZXDfykss3geg==
- 注意: P2005功能中请求参数是用
<Data></Data>
包围,不是<xml></xml>
3.6 交易退款接口
- 功能码:P2008
- 接口说明:当交易发生之后一段时间内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付款退还给买家(原路返回)。注意的地方:微信超过1年的订单无法提交退款,支付宝超过3个月的订单无法提交退款,可以一笔订单多次退款,但是累计金额不能超过原支付金额
- 请求参数:
<Data>
参数 | 名称 | 类型 | 长度 | 是否必填 | 说明 | 示例 |
---|---|---|---|---|---|---|
RequestNo | 退款订单号 | String | 32 | 是 | 商户内部唯一退款单号 | TK20190722001 |
PayType | 退款渠道 | String | 2 | 是 | 2=支付宝;3=微信 | 2 |
Amt | 退款金额 | Price | 16.2 | 是 | 退款金额不得超过原支付金额 | 0.01 |
TradeNo | 原支付业务单号 | String | 32 | 是 | 商户原支付订单号 | WX2019072200001 |
merchant_no | 商户号 | String | 32 | 是 | 平台商户号 | 809900000001 |
sub_merchant | 分店号 | String | 32 | 否 | 商户内部区分单号 | 001 |
- 响应参数:
参数 | 名称 | 类型 | 长度 | 是否必输 | 说明 | 示例 |
---|---|---|---|---|---|---|
RequestNo | 退款订单号 | String | 32 | 是 | 申请退款订单号 | TK20190722001 |
Amt | 退款金额 | Price | 16.2 | 是 | 申请退款金额 | 0.01 |
- JAVA请求示例:
String data = "<Data>" + "<RequestNo>TK123127893456798765491</RequestNo>" + "<PayType>3</PayType>" + "<Amt>0.01</Amt>" + "<TradeNo>YMP011494322477660</TradeNo>" + "<merchant_no>809900000001</merchant_no>" + "</Data>"; List<NameValuePair> list = new ArrayList<NameValuePair>(); NameValuePair valu1 = new BasicNameValuePair("data",data); NameValuePair valu2 = new BasicNameValuePair("developerId",[your developerId]); NameValuePair valu3 = new BasicNameValuePair("funcId","P2008"); String privateKey =[your privateKey]; String signData = "data="+data+"&developerId=[your developerId]&funcId=P2008"; String sign = SecurityUtil.signRSA(signData,privateKey,"utf-8"); NameValuePair valu4 = new BasicNameValuePair("sign",sign); list.add(valu1); list.add(valu2); list.add(valu3); list.add(valu4); String xml = null; try { CloseableHttpResponse response = HttpClients.custom().build().execute(RequestBuilder.post().setUri("http://offlinetest.bsoftpay.com/gatewayOffline/pay/offline/execute").setEntity(new UrlEncodedFormEntity(list, Consts.UTF_8)).build()); xml = EntityUtils.toString(response.getEntity()); } catch (Exception e) { e.printStackTrace(); } System.out.println(xml);
- 返回示例:
developerId=12345&funcId=P2008&retCode=0000&retMsg= &data=<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Data> <RequestNo>TK123127893456798765491</RequestNo> <Amt>0.01</Amt> </Data> &sign=XUvpouNiWkQF7bQsS2GTz+x7InmbxNz0reUhi1qqIIVg6AvLv5BKOqRzGpEm/N214pBPmiZpsygsOMKvYgLFqg==
- 注意: P2008功能中请求参数是用
<Data></Data>
包围,不是<xml></xml>
3.7 交易退款结果查询接口
- 功能码:P2009
- 接口说明:提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用微信零钱或者支付宝余额宝、花呗等支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态(20分钟、3 个工作日都是大概时间,不一定为准,有可能提前,有可能延迟)
- 请求参数:
<Data>
参数 | 名称 | 类型 | 长度 | 是否必填 | 说明 | 示例 |
---|---|---|---|---|---|---|
RequestNo | 退款订单号 | String | 32 | 是 | 商户内部唯一退款单号 | TK20190722001 |
PayType | 退款渠道 | String | 2 | 是 | 2=支付宝;3=微信 | 2 |
- 响应参数:
参数 | 名称 | 类型 | 长度 | 是否必输 | 说明 | 示例 |
---|---|---|---|---|---|---|
RequestNo | 退款订单号 | String | 32 | 是 | 申请退款订单号 | TK20190722001 |
Amt | 退款金额 | Price | 16.2 | 是 | 当code为1时这里会显示退款金额 | 0.01 |
Code | 退款状态 | String | 2 | 是 | -1交易不存在 1 成功 2 失败 | 1 |
Msg | 错误信息描述 | String | 100 | 是 | 当code为2时这里会显示错误信息 | 0.01 |
- 返回示例:
developerId=12345&funcId=P2009&retCode=0000&retMsg= &data=<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Data> <RequestNo>TK20190722001</RequestNo> <Amt>0.01</Amt> <Code>1</Code> <Msg>OK</Msg> </Data> &sign=pkXTgvceROvF0JPq7Bmwxv654YoAImkSNblr/xTE75h6ZS1hUSSl5OAjEXptiJ0EW5vT9AvmFWGeW6uQGE6aKg==
- 注意: P2009功能中请求参数是用
<Data></Data>
包围,不是<xml></xml>
3.8 关闭订单
功能码:P7002
接口说明:需要重新发起支付时,关闭该订单(刷卡付场景,扫码付无需关闭订单)
场景描述:当接入应用系统调用支付指令接口(P7001)后,遇到网络等原因,超时未获取到结果的情况下,可以调用本接口进行关闭(撤销)此次支付订单(用于非正常支付场景)
特别注意:如果是刷卡付(B扫C)的应用场景,若付款人已支付,渠道商会进行退款,聚合支付平台不会有退款记录- 情况一实际未支付,订单关闭(撤销), 接入的应用系统一定要作废本地业务单据。
- 情况二实际已支付,若是刷卡付(B扫C)的应用场景,关闭(撤销)订单时,会原路退回支付款,接入的应用系统一定要作废本地业务单据。若是扫码付(C扫B)的应用场景,则系统会提示该笔“已支付不允许关闭”,遇到该情况,接入应用可以继续获取支付结果来同步本地业务单据状态或者重新发起业务付款流程,原业务单据走异常退款方式(接入应用研发异常退款功能直接调用P2008)
请求参数:
<xml>
参数 | 名称 | 类型 | 长度 | 是否必填 | 说明 | 示例 |
---|---|---|---|---|---|---|
order_no | 业务单号 | String | 32 | 是 | 商户内部唯一订单号 | ZF20190722001 |
merchant_no | 收款商户号 | String | 32 | 是 | 平台商户号 | 809900000001 |
- 响应参数:
参数 | 名称 | 类型 | 长度 | 是否必输 | 说明 | 示例 |
---|---|---|---|---|---|---|
ReturnCode | 返回状态码 | String | 16 | 是 | SUCCESS=关闭成功;FAIL=关闭失败 | SUCCESS |
ReturnMsg | 返回消息 | String | 128 | 是 |
- 请求示例:
String data = "<xml>" + "<order_no>ZF20190722001</order_no>" + "<merchant_no>809900000001</merchant_no>" + "</xml>"; List<NameValuePair> list = new ArrayList<NameValuePair>(); NameValuePair valu1 = new BasicNameValuePair("data",data); NameValuePair valu2 = new BasicNameValuePair("developerId",[your developerId]); NameValuePair valu3 = new BasicNameValuePair("funcId","P7002"); String privateKey = [your privateKey]; String signData = "data="+data+"&developerId=[your developerId]&funcId=P7002"; String sign = SecurityUtil.signRSA(signData,privateKey,"utf-8"); NameValuePair valu4 = new BasicNameValuePair("sign",sign); list.add(valu1); list.add(valu2); list.add(valu3); list.add(valu4); String xml = null; try { CloseableHttpResponse response = HttpClients.custom().build().execute(RequestBuilder.post().setUri("http://offlinetest.bsoftpay.com/gatewayOffline/pay/offline/execute").setEntity(new UrlEncodedFormEntity(list, Consts.UTF_8)).build()); xml = EntityUtils.toString(response.getEntity()); } catch (Exception e) { e.printStackTrace(); } System.out.println(xml);
- 返回示例:
developerId=12345&funcId=P7002&retCode=0000&retMsg= &data=<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <xml> <ReturnCode>SUCCESS</ReturnCode> <ReturnMsg>OK</ReturnMsg> </xml> &sign=WkYUWPi+bnecNPTrhKnmvVWrnnCGvgxEkqwwrdMmu6LWMwUm6iFOhMlsRdvibFGr9SBqWY4pIew5e732xmXZOw==
3.9 对账文件下载
- 功能码:P7003
- 接口说明:下载对账文件(每日对账文件会第二天12:10左右生成)
- 请求参数:
<xml>
参数 | 名称 | 类型 | 长度 | 是否必填 | 说明 | 示例 |
---|---|---|---|---|---|---|
MerchantNo | 收款商户号 | String | 32 | 是 | 商户内部唯一订单号 | 809900000001 |
BalanceDate | 对账日期 | String | 10 | 是 | 日期格式:yyyymmdd | 20190722 |
SubMerchant | 门店号 | String | 32 | 否 | 平台商户号 | 001 |
- 响应参数:
名称 | 类型 | 长度 | 是否必输 | 说明 | 示例 |
---|---|---|---|---|---|
商户号 | String | 32 | 是 | 平台商户号 | 809900000001 |
门店号 | String | 32 | 否 | 商户内部区分号 | 001 |
订单号 | String | 16 | 是 | 业务订单号 | ZF20190722001 |
支付渠道 | String | 1 | 是 | 2=支付宝;3=微信 | 2 |
交易类型 | String | 1 | 是 | 1=app支付;2=退款;3=扫码付;4=刷卡付;5=公众号支付;6=H5支付;7=刷脸付;-1=未知支付(造成原因:支付平台掉单,无法确定支付类型,出现这种情况请尽快联系支付平台,查明原因) | 1 |
交易时间 | String | 16 | 是 | 时间格式:yyyyMMddhhmmss | 20190722122134 |
交易金额 | Price | 16.2 | 是 | 实际交易金额 医保支付做为总金额 |
0.01 |
医保金额 | Price | 16.2 | 否 | 医保支付金额 医保支付返回 |
0.01 |
自费金额 | Price | 16.2 | 否 | 自费金额 医保支付返回 |
0.01 |
- 请求示例:
<xml> <MerchantNo>809900000001</MerchantNo> <BalanceDate>20190722</BalanceDate> </xml>
- 返回文件格式:txt (以TAB键作为分隔符)
商户号 门店号 订单号 支付渠道 交易类型 交易时间 交易金额 1243 001 334567 2 1 20170111091233 10.00 1244 001 334568 3 2 20170111091244 100.00
4. 修订记录
日期 | 修订内容 | 修订人 |
---|---|---|
2019-12-19 | 接入支付宝代扣流程 | 熊超 |