完成 [接入准备](https://opendocs.alipay.com/open/20190319114403226822/quickstart) 后,商家/服务商可根据本文指引快速接入 **周期扣款-支付并签约**。
**说明**: - **周期扣款** 产品仅支持自研商家/服务商通过 [自研应用](https://opendocs.alipay.com/open/200/105894#%E8%87%AA%E7%A0%94%E6%9C%8D%E5%8A%A1%E5%9E%8B%E5%BA%94%E7%94%A8) 或 [第三方应用](https://opendocs.alipay.com/open/200/105894#%E4%B8%89%E6%96%B9%E6%9C%8D%E5%8A%A1%E5%9E%8B%E5%BA%94%E7%94%A8) 代调用(传入 `app_auth_token`)方式,调用 API 接入。 - **周期扣款** 产品暂不支持沙箱调试。 - 为保证正常调用接口,调接口之前需要先确保应用 **上线** 状态、应用 **已绑定** 且 **已签约** 周期扣款产品,可以使用 [配置项检测工具](https://open.alipay.com/api/check?examCode=E000001956) 检查是否完成接入前的准备工作。 - **周期扣款** 产品,接口中 product_code 字段固定传参为 CYCLE_PAY_AUTH。 # 支付并签约场景 用户在小程序/商家App支付的同时签约协议,商家在支付接口传入签约相关参数 sdkExecute 方法拿到 response 返回值后,其传入给 APP支付/小程序,完成同步支付与异步签约,通过异步通知或者查询接口确认签约结果。 # 支付并签约流程图 ![支付并签约及消息部分.png](https://cdn.nlark.com/yuque/0/2022/png/179989/1668569808919-c8250c2a-3eaa-4e16-bcbc-12fafa6c65d4.png#align=left&display=inline&height=1074&originHeight=1074&originWidth=1106&size=85718&status=done&style=none&width=1106) # 创建周期扣款支付订单 商家调用 [alipay.trade.app.pay](https://opendocs.alipay.com/open/02fkau)(app 支付 2.0)接口传入用户支付信息及周期扣款信息,创建周期扣款支付订单。 ## 示例代码 ```json bizContent={ "out_trade_no":"202207151529dk01111",//商户订单号 "total_amount":0.01,//订单总金额,首次支付的金额,不算在周期扣总金额里。 "subject":"\u6d4b\u8bd5\u5468\u671f\u6263\u6b3e",//订单标题 "product_code":"CYCLE_PAY_AUTH",//产品码,固定值 "timeout_express":"90m",//超时时间 "agreement_sign_params":{//周期扣款协议信息 "personal_product_code":"CYCLE_PAY_AUTH_P",//个人签约产品码固定为CYCLE_PAY_AUTH_P "sign_scene":"INDUSTRY|CARRENTAL",//协议签约场景,参见下文sign_scene参数说明 "external_agreement_no":"20220715220701",//商户签约号,代扣协议中用户的唯一签约号 "sign_notify_url":"https://xxxx.com",//签约成功异步通知地址 "access_params":{//签约接入的方式 "channel":"ALIPAYAPP" }, "period_rule_params":{//签约规则 "period_type":"DAY",//周期类型枚举值为 DAY 和 MONTH "period":"30",//周期数,与 period_type 组合使用确定扣款周期 "execute_time":"2022-07-16",//用户签约后,下一次使用代扣支付扣款的时间 "single_amount":"0.01",//单次扣款最大金额 "total_amount":"0.02",//周期内扣允许扣款的总金额,单位为元 "total_payments":"2"//总扣款次数。 } } } ``` ```java AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","app_id","your private_key","json","GBK","alipay_public_key","RSA2"); AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest(); request.setNotifyUrl("https://www.notifyURL.com");//设置异步通知地址 request.setBizContent(参考上面bizContent值示例); AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request); System.out.println(response.getBody()); ``` ## 部分参数说明 - period_rule_params:周期管控规则参数 ,必填。
- period_type:周期类型 ,枚举值为 DAY 和 MONTH。周期类型使用 **MONTH** 的时候,计划扣款时间 execute_time **不允许传 28 日之后的日期(可以传 28 日)**,以此避免有些月份可能不存在对应日期的情况。
**说明**:周期类型使用 **DAY** 的时候,周期数 period **不允许小于 7(可以等于7)**,避免间隔日期太短,扣款过于频繁,没有周期限制的意义。 
- period:必填,周期数,与 period_type 组合使用确定扣款周期,例如 period_type 为 DAY,period = 90,则扣款周期为 90 天。
- execute_time:下次扣款的时间。非支付并签约的成功时间,必填。精确到日,格式为 yyyy-MM-dd。
- single_amount:单次扣款最大金额,必填,即每次发起扣款时限制的最大金额,单位为元。商家每次发起扣款都不允许大于此金额。
- total_amount:周期内允许扣款的总金额。
- total_payments:总扣款次数。
- total_amount:订单总金额。首次支付金额,**不算在周期扣总金额里面**。
- product_code:周期扣款产品码固定为 CYCLE_PAY_AUTH。 - personal_product_code:周期扣款个人签约产品码固定为 CYCLE_PAY_AUTH_P。 - sign_scene:签约场景,具体参数请商家接入时根据自身行业进行判断,点击查看全部 [常见场景值](https://opendocs.alipay.com/open/20190319114403226822/signscene)。例如: INDUSTRY|CARRENTAL(租车行业)。 - external_agreement_no:商家签约号,代扣协议中标示用户的唯一签约号(确保在商家系统中唯一)。用户支持一对多,即同一个商家下,同一个用户可以有多套签约关系。通过商家外部签约号和场景参数来区分签约协议。若签约时传入了签约号及场景参数,后续查询协议和解约时也必须传入。 - access_params:请按当前接入的方式进行填充,且输入值必须为文档中的参数取值范围。 - channel:目前支持以下值: - ALIPAYAPP :支付宝客户端 H5 页面签约。 - QRCODE:扫码签约。 - QRCODEORSMS:扫码签约或者短信签约。 - sign_notify_url:签约成功异步通知地址。支付后签约场景中,用户支付成功及签约成功都会触发异步通知。规则如下: - 若 [alipay.trade.app.pay](https://opendocs.alipay.com/open/02fkau)(app 支付 2.0)接口只设置 notify_url 则两条异步通知都会发送到该地址。 - 若 [alipay.trade.app.pay](https://opendocs.alipay.com/open/02fkau)(app 支付 2.0)分别设置 notify_url 及 sign_notify_url 则支付成功异步通知会发送到 notify_url,签约成功异步通知会发送到 sign_notify_url。 ## 唤起支付宝客户端并签约说明 ### 商家 App 唤起支付并签约 集成方案按照 App 支付请求支付的模式即可,可查看 [客户端 demo](https://opendocs.alipay.com/open/54/104509)。 ### 小程序唤起支付并签约 ```java AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request); String orderStr = response.getBody(); ``` 将 orderStr 参数值传入 JSAPI [my.tradePay](https://opendocs.alipay.com/mini/api/openapi-pay) 即可实现唤起收银台支付并签约。 # 支付成功异步通知 异步通知参数说明具体请参考 [APP支付异步通知说明](https://opendocs.alipay.com/open/204/105301?ref=api)。 # **签约异步通知说明** 签约异步通知仅当用户签约成功时触发,商家以 POST 方式接收签约异步通知消息。优先取接口 [alipay.trade.app.pay](https://opendocs.alipay.com/open/02fkau)(app 支付 2.0)中传的 sign_notify_url ,若没有设置 sign_notify_url 则会取 notify_url,如果都没传则取 **应用网关** 地址(商家必须在 [开放平台](https://openhome.alipay.com/platform/home.htm) **应用信息** 中配置 **应用网关**)。 ## **商家验签** 在通知返回参数列表中除去 sign、sign_type 两个参数外,凡是通知返回回来的参数皆是待验签的参数。 ## 异步通知示例 根据 status 触发条件,只有签约成功和解约成功才会返回异步,签约失败和解约失败都不会触发异步。 ```java charset=utf-8¬ify_time=2020-04-24 11:28:20&alipay_user_id=2088*****9864&alipay_open_id=031_DfFvT0Ufzk1852BLPnhuSWiztu4NqbkO35ylXPow-Y6&sign=ooWBuCDIQSumOpaGBcQz+aoAqyGh3W6EqA/gmyPYwLJ2REFijY***9XPTApI9YglZyMw+ZMhd3kb0mh4RAXMrb6me&external_agreement_no=138528528786000&version=1.0&sign_time=2020-04-24 11:28:20¬ify_id=2020042400222112820072971427431169¬ify_type=dut_user_sign&agreement_no=20205224633661163886&invalid_time=2115-02-01 00:00:00&auth_app_id=2014*****222&personal_product_code=CYCLE_PAY_AUTH_P&valid_time=2020-04-24 11:28:20&login_token=1948bbcaac503bb499a1c62dbb584d0f_86&app_id=2014*****22&sign_type=RSA2&sign_scene=INDUSTRY|CARRENTAL&status=NORMAL&alipay_logon_id=159******10 //用户Id类字段根据选用的ID标准(UID或openid)选择示例 ``` ## **重要参数说明** - status:协议状态,枚举支持。
- NORMAL:正常。 - UNSIGN:解约。
- external_agreement_no:代扣协议中标示用户的唯一签约号,商家自定义。仅签约接口传入时返回。
- agreement_no:支付宝系统中用以唯一标识用户签约记录的编号。
- notify_type:异步通知类型,枚举支持。
- dut_user_sign:当 status = NORMAL 表示签约成功。
- dut_user_unsign:当 status = UNSIGN 表示解约成功。
- sign_scene:签约协议场景。
- personal_product_code:协议产品码。
- alipay_user_id(alipay_open_id):支付宝用户唯一标识。新商户建议使用open_id替代该字段。对于新商户,user_id字段未来计划逐步回收,存量商户可继续使用。如使用open_id,请确认 应用-开发配置-openid配置管理 已启用。无该配置项,可查看[openid配置申请](https://opendocs.alipay.com/common/0ai9ok?pathHash=a43b913d)。 - alipay_logon_id:用户的支付宝登录账号。 
# 后续扣款 商家根据用户签约成功支付宝返回的协议号(agreement_no)每次主动调 [alipay.trade.pay](https://opendocs.alipay.com/open/02fkat?scene=33)(统一收单交易支付接口),完成周期扣款协议后续免密代扣操作 ## 签约成功后续扣款流程图 ![image (4).png](https://cdn.nlark.com/yuque/0/2022/png/179989/1667876315672-353c2a81-9c8b-487f-a32a-b79d31126327.png#align=left&display=inline&height=673&originHeight=1286&originWidth=1146&size=243251&status=done&style=none&width=600)**说明:**目前允许商家在约定日期及其之前5天开始扣款,如:约定扣款日为 20 号,支持商家从 15 至 20 号发起扣款。 ## 示例代码 ```java {{std::example#alipay.trade.pay|33|request|java}} ``` ## 同步返回公共参数说明 | **参数** | **类型** | **是否必填** | **最大长度** | **描述** | **示例值** | | --- | --- | --- | --- | --- | --- | | code | String | 是 | ~ | 详见下文 **结果码和处理方式**。 | 40004  | | msg | String | 是 | ~ | 返回码描述 | Business Failed | | sub_code | String | 否 | ~ | 子返回码 | AGREEMENT_NOT_EXIST | | sub_msg | String | 否 | ~ | 子返回码描述 | 协议不存在。可能原因:
1. 用户已解约;
2. 协议号传入错误,请检查。
| | sign | String | 是 | 256 | 商家请求参数的签名串,详见 [签名](https://opendocs.alipay.com/common/02khjm)。 | DZXh8eeTuAHoYE3w1 J+POiPhfDxOYBfUNn1 lkeT/V7P4zJdyojWEa6 IZs6Hz0yDW5Cp/viufU b5I0/V5WENS3OYR8zR edqo6D+fUTdLHdc+E FyCkiQhBxIzgngPdPdf p1PIS7BdhhzrsZHbRq b7o4k3Dxc+AAnFauu4V6Zdwczo= | #### code 结果码和处理方式 - 根据公共返回参数中的 code,这笔交易可能有四种状态:支付成功(10000),支付失败(40004),等待用户付款(10003)和未知异常(20000)。 - 对于 **扣款失败** 或 **未知异常**, 有如下解决方案: - 建议商家等待5分钟后,使用 [alipay.trade.query](https://opendocs.alipay.com/open/02fkaw)(统一收单交易查询接口)查询交易状态,如果交易状态是成功,则无需特殊处理;若查询 4 次后依然返回等待用户付款,商户可以选择幂等重试代扣或通过 [alipay.trade.cancel](https://opendocs.alipay.com/open/02fkax)(统一收单交易撤销接口)发起交易撤销。 | **结果码** | **说明** | **处理方式** | | --- | --- | --- | | 10000 | 支付成功 | 记录交易结果并在显示支付成功,进入后续的业务处理。 | | 40004 | 支付失败 | 记录交易结果并显示错误信息(display_message)。 | | 10003 | 等待用户付款 | 一般等待5分钟后调用交易查询接口 alipay.trade.query。 通过支付时传入的商户订单号(out_trade_no)查询支付结果(返回参数 TRADE_STATUS )。
查询4次之后若仍然返回等待用户付款(WAIT_BUYER_PAY),商户可以选择幂等重试代扣或者发起交易撤销 alipay.trade.cancel。 | | 20000 | 未知异常 | 一般等待5分钟后调用交易查询接口 alipay.trade.query。 通过支付时传入的商户订单号(out_trade_no)查询支付结果(返回参数 TRADE_STATUS )。
查询4次之后若仍然返回等待用户付款(WAIT_BUYER_PAY),商户可以选择幂等重试代扣或者发起交易撤销 alipay.trade.cancel。 | #### 注意事项 周期扣款场景下使用 [alipay.trade.pay](https://opendocs.alipay.com/open/02fkat?scene=33)(统一收单交易支付接口)时: - product_code:必填,产品码。固定为 `CYCLE_PAY_AUTH`。 - subject:必填,订单标题。不可使用特殊字符,如 /,=,& 等。 - agreement_params:必填,代扣信息。 - agreement_no:必填,支付宝系统中用以唯一标识用户签约记录的编号(用户签约成功后的协议号)。 - 如果不填卖家 seller_id,则默认为商家签约账号对应的支付宝用户 ID。 # 支付成功异步通知 异步通知参数说明具体请参考 [当面付异步通知说明](https://opendocs.alipay.com/open/194/103296)。 # 辅助功能 ## 周期扣款协议查询 商家可调用 [alipay.user.agreement.query](https://opendocs.alipay.com/open/02fkao?scene=8837b4183390497f84bb53783b488ecc)(支付宝个人代扣协议查询接口)查询用户是否完成签约操作,用户实际签约结果请以查询接口返回值为准。 - 通过协议号查询协议详情,此时请求参数中填入协议号(agreement_no),其它业务参数均可不填。 - 如果在支付宝个人协议页面签约接口接口中传递了`sign_scene` + `external_agreement_no`  2 个参数,那在对应的协议查询接口中传递 `personal_product_code` + `sign_scene` + `external_agreement_no`  3 个参数即可查询到内容。 - 如果在支付宝个人协议页面签约接口接口中没有传递 `sign_scene` + `external_agreement_no` 2 个参数,那在对应的协议查询接口中传递 `personal_product_code` +(`alipay_logon_id` 、 `alipay_user_id` 和 `alipay_open_id` 3 个参数中的任何一个参数)即可查询到内容。 ## 周期扣款协议解约 ### 商家解约 开发者可调用 [alipay.user.agreement.unsign](https://opendocs.alipay.com/open/02fkap)(个人协议解约接口)完成协议解约。 - 通过协议号解约,此时请求参数中填入协议号(agreement_no),其它业务参数均可不填。 - 通过 `personal_product_code` + `sign_scene+external_agreement_no` + `alipay_logon_id`+`alipay_user_id(alipay_open_id)` 来解约,入参值按照商家调 [alipay.user.agreement.page.sign](https://opendocs.alipay.com/open/02fkan?scene=35)(支付宝个人协议页面签约接口)中的对应值传入;如果传入 external_agreement_no,则 alipay_logon_id 与 alipay_user_id(alipay_open_id) 可不传,否则 alipay_logon_id 与 alipay_user_id(alipay_open_id) 必须传其中一个。 ### 用户解约 用户可主动在支付宝客户端进行解约(无需商家侧接口调用),解约成功后支付宝将发送解约信息给商家应用在 [支付宝开放平台](https://openhome.alipay.com/platform/home.htm) 中配置的 **应用网关** 地址。通知的内容格式请查看 [alipay.user.agreement.unsign](https://opendocs.alipay.com/open/02fkap)(个人协议解约接口)中的异步通知格式。
**注意:** - 当用户通过支付宝 APP 解约成功后,支付宝发送给商家的异步通知参数 **编码方式** 优先采用签约应用(APPID)在开放平台上配置的编码方式,若无配置默认为 **GBK** 编码。 - 若应用类型为生活号请查看 [生活号接入文档](https://opendocs.alipay.com/fw/guide/105933#CzMpJ) 激活开发者模式。 ### 解约异步通知说明 解约异步通知仅当用户解约成功或商家调解约接口成功时触发。商家以 POST 方式接收异步解约通知,如果是用户解约成功通知地址是 **应用网关** 地址(商家必须在 [开放平台](https://openhome.alipay.com/platform/home.htm) **应用信息** 中配置 **应用网关**)。如果是商家调 [alipay.user.agreement.unsign](https://opendocs.alipay.com/open/02fkap)(个人协议解约接口接口)解约优先接收接口中传的 notify_url,如果没传则取 **应用网关** 地址。 #### 异步通知示例 ```java charset=UTF-8¬ify_time=2022-08-08 10%3A44%3A45&unsign_time=2022-08-08 10%3A44%3A45&alipay_user_id=2088******772180&alipay_open_id=074a1CcTG1LelxKe4xQC0zgNdId0nxi95b5lsNpazWYoCo5&sign=$$$&external_agreement_no=dk20220808mm220281113&version=1.0¬ify_id=2022080800222104445014011428773938¬ify_type=dut_user_unsign&agreement_no=2022******3902719118&auth_app_id=20141******13222&personal_product_code=CYCLE_PAY_AUTH_P&app_id=20141******13222&sign_type=RSA2&alipay_logon_id=156******05&status=UNSIGN&sign_scene=INDUSTRY%7CCARRENTAL //用户Id类字段根据选用的ID标准(UID或openid)选择示例 ``` **注意**:UNSIGN(解约)是只有解约(解约接口或者客户端解约)才会触发返回的状态,当解约后调用 [alipay.user.agreement.query](https://opendocs.alipay.com/open/02fkao?scene=8837b4183390497f84bb53783b488ecc)(支付宝个人代扣协议查询接口)查询协议,会提示 **用户协议不存在(USER_AGREEMENT_NOT_EXIST)**,不会返回 status=UNSIGN 的状态。 # 订单支付后续 - 使用 [alipay.trade.refund](https://opendocs.alipay.com/open/02fkav)(统一收单交易退款接口)完成退款。 - 使用 [alipay.trade.cancel](https://opendocs.alipay.com/open/02fkax) (统一收单交易撤销接口)完成撤销。 - 使用 [alipay.trade.close](https://opendocs.alipay.com/open/02fkay)(一收单交易关闭接口)完成关闭交易订单。 # 延期扣款 商家可调用 [alipay.user.agreement.executionplan.modify](https://opendocs.alipay.com/open/02fkaq)(周期性扣款协议执行计划修改接口)实现延期扣款。 ## 示例 用户在1月1日开通了连续包月,使用了10天又另行购买了季度包,如果此时商家希望季度包立即优先生效,在季度包结束后能继续使用连续包月,那么原定的周期就被延后了,如果不做处理那么扣款时间就对不上。此时可以由商家调用推迟接口,将预计扣款时间推后季度包的时长。 ```java {{std::example#alipay.user.agreement.executionplan.modify||request|java}} ``` # 业务接口报错 关于业务接口报错请查看 [常见问题](https://opendocs.alipay.com/open/20190319114403226822/faq)。