:::info **注意:独立签约后扣款能力仅对部分商家定向开放,如有疑问请咨询 4007585858。** ::: 完成 [@接入准备(repo#0039c0#c0b5a442#08b368)](/repo#0039c0#c0b5a442#08b368) 后,商家/服务商可根据本文指引快速接入 **商家扣款-独立签约后扣款**。
**说明**: - **商家扣款** 产品仅支持自研商家/服务商通过 [自研应用](https://opendocs.alipay.com/common/02bijh#%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/common/02bijh#%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 接入。{% if site_identifier=='/open-v3' %}{% else %} - **商家扣款** 产品暂不支持沙箱调试。{% endif %} - **独立签约后扣款场景**指用户在H5页面/小程序/商家APP/PC页面中先行确认服务内容等信息完成协议签约操作,后续商家根据用户签约协议号等参数完成扣款,简化用户操作实现自动续费。 - **商家扣款 **产品,接口中 product_code 字段固定传参为 GENERAL_WITHHOLDING。 # 页面签约流程图 ![先签约后代扣-签约及消息部分.png](https://cdn.nlark.com/yuque/0/2022/png/179989/1668498171717-fb13c889-14b7-4321-b1d5-2dfa48c9c690.png#height=890&id=BxHsC&originHeight=890&originWidth=970&originalType=binary&ratio=1&rotation=0&showTitle=false&size=72828&status=done&style=none&title=&width=970) # 创建签约协议内容 商家通过调用[@alipay.user.agreement.page.sign(支付宝个人协议页面签约接口)(API#alipay.user.agreement.page.sign#api_url)](/API#alipay.user.agreement.page.sign#api_url)传入相关信息创建签约协议内容。 ## 示例代码 ```json bizContent={ "product_code":"GENERAL_WITHHOLDING",//商家扣款场景固定为 GENERAL_WITHHOLDING "personal_product_code":"CYCLE_PAY_AUTH_P",//使用商家扣款产品时必传,其它支付产品无需传入 "sign_scene":"INDUSTRY|DEFAULT_SCENE",//签约场景 "external_agreement_no":"dk20220712102811111",//商户签约号 "sign_validity_period":"2m",//当前用户签约请求的协议有效周期 "access_params":{//接入渠道 "channel":"ALIPAYAPP" }, "period_rule_params":{//周期管控规则 "period_type":"DAY",//周期类型枚举值为DAY和MONTH "period":"9",//周期数 "execute_time":"2022-07-13",//商户发起首次扣款的时间 "single_amount":"0.01",//每次发起扣款时限制的最大金额单位为元 "total_amount":"0.02",//周期内允许扣款的总金额,单位为元 "total_payments":"2"//总扣款次数 }, "identity_params":{// 非必填,用户实名信息参数 "user_name":"\u5f20\u4e09", "cert_no":"61102619921108888", "identity_hash":"ac8c238bc68fca1c35933db1efa1d79accc014db5dc42fb3a43c421d47c2dbfa", "sign_user_id":"2088202888530893","sign_open_id":"031_DfFvT0Ufzk1852BLPnhuSWiztu4NqbkO35ylXPow-Y6" } } ``` ```java AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","app_id","your private_key","json","GBK","alipay_public_key","RSA2"); AlipayUserAgreementPageSignRequest request = new AlipayUserAgreementPageSignRequest(); request.setBizContent(参考上面bizContent值示例); request.setNotifyUrl("https://www.notifyURL.com");//设置异步通知地址 // 若想获取跳转链接使用pageExecute GET方式转换二维码可使用 alipayClient.pageExecute(request,"get") // 商家扣款场景使用小程序/h5 接口跳转至签约页面时请使用 alipayClient.sdkExecute AlipayUserAgreementPageSignResponse response = alipayClient.sdkExecute(request); ``` ## 重要参数说明 - period_rule_params:周期管控规则参数 ,必填。 - period_type:周期类型 ,枚举值为 DAY 和 MONTH。周期类型使用 **MONTH** 的时候,计划扣款时间 execute_time **不允许传 28 日之后的日期(可以传 28 日)**,以此避免有些月份可能不存在对应日期的情况。
**说明**:周期类型使用 **DAY** 的时候,周期数 period **不允许小于 30(可以等于 30)**。 - period:必填,周期数,与 period_type 组合使用确定扣款周期,例如 period_type 为 DAY,period = 90,则扣款周期为 90 天。 - execute_time:商家发起首次扣款的时间,必填。精确到日,格式为 yyyy-MM-dd。 - single_amount:单次扣款最大金额,必填,即每次发起扣款时限制的最大金额,单位为元。商家每次发起扣款都不允许大于此金额。 - total_amount:周期内允许扣款的总金额。 - total_payments:总扣款次数。 - product_code:商家扣款产品码固定为GENERAL_WITHHOLDING。 - personal_product_code:商家扣款周期性业务模式的个人签约产品码固定为 CYCLE_PAY_AUTH_P。 - sign_scene:签约场景码,具体参数请商家完成产品签约后,根据业务场景或用户购买商品的差异性对应新增模版及场景码。
**说明**:登录 **商家平台** > [产品大全](https://b.alipay.com/page/product-mall/all-product)** **>** 商家扣款 **>** 功能管理 **>** 修改 **>** 设置模版 可**新增模版及场景码。商家在确认新增模版及场景码完成后,签约接入时需要传入模版中实际填写的场景码。场景码格式详情可查看 [@常见场景码值(repo#0039c0#e2781ac5#08bg92)](/repo#0039c0#e2781ac5#08bg92)。 - sign_validity_period:当前用户签约请求的协议有效周期。 - return_url:跳转商家处理地址。则签约流程中会在上文**页面签约流程图**中的**步骤 11**跳转至此地址并在处理完成后回跳继续流程,没有传这个参数则不跳转。 - notify_url:异步通知地址。 - external_agreement_no:商家签约号,签约协议中标示用户的唯一签约号(确保在商家系统中唯一)。用户支持一对多,即同一个商家下,同一个用户可以有多套签约关系。通过商家外部签约号和场景参数来区分签约协议。若签约时传入了签约号及场景参数,后续查询协议和解约时也必须传入。 - access_params:请按当前接入的方式进行填充,且输入值必须为文档中的参数取值范围。扫码或者短信页面签约需要拼装 http 的请求地址访问中间页面,支付宝客户端 H5 页面签约可直接拼接 schema 的请求地址。 - channel:目前支持以下值: - ALIPAYAPP :支付宝客户端 H5 页面签约。 - QRCODE:扫码签约。 - QRCODEORSMS:扫码签约或者短信签约。 - 用户实名信息参数填入 identity_params 中(包括 identity_hash);如果商家已获得用户实名信息,需要与支付宝实名信息比对一致性,则将用户实名信息生成摘要信息填入 identity_params中 的 identity_hash。详情可查看 [@常见问题(repo#0039c0#b282297f#08bcgy)](/repo#0039c0#b282297f#08bcgy)-entity_params.identity_hash 实名信息中的hash值如何生成?
**注意**:此时如不需要再跳转实名授权,则 merchant_process_url 参数应不传。特殊场景才会使用,如无需要不用关注。 - 第三方主体类型(third_party_type),目前支持 PARTNER 和 MERCHANT,默认 PARTNER,目前有 airbnb 和之前的 uber 是 MERCHANT 类型(存在父子关系)。 # 唤起签约说明 ## PC转二维码唤起签约页 ![](https://intranetproxy.alipay.com/skylark/lark/0/2023/png/34756639/1693986994398-bcb7dd2e-e452-49fb-a726-8a5fa221fa33.png#height=1282&id=txQUh&originHeight=2052&originWidth=2116&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=1322)PC 转二维码 bizContent 示例值: ```json bizContent={ "personal_product_code":"CYCLE_PAY_AUTH_P",//商家扣款产品时必传 "sign_scene":"INDUSTRY|DEFAULT_SCENE",//签约场景码示例 "external_agreement_no":"dk20220712102811111",//商户签约号 "access_params":{//接入渠道 "channel":"ALIPAYAPP" } } ``` PC 转二维码生成签约字符串: ```java AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","app_id","your private_key","json","GBK","alipay_public_key","RSA2"); AlipayUserAgreementPageSignRequest request = new AlipayUserAgreementPageSignRequest(); request.setBizContent(参考上面的bizContent); //pageExecute get方式,生成url AlipayUserAgreementPageSignResponse response = alipayClient.pageExecute(request,"get"); //生成的url地址去除https://openapi.alipay.com/gateway.do signParams = response.getBody().replace("https://openapi.alipay.com/gateway.do?",""); //生成唤起客户端。把signParams使用 UTF-8 字符集整体做一次 encode return 'alipays://platformapi/startapp?appId=60000157&appClearTop=false&startMultApp=YES&sign_params='+ encode(signParams); ``` **注意**: 1. PC转二维码签约为用户使用客户端设备扫码签约,交易场景默认为“移动设备”。 2. `alipays://platformapi/startapp?appId=60000157&appClearTop=false&startMultApp=YES&sign_params=`(该链接里面的 APPID 为固定值,不可修改)。 3. [@alipay.user.agreement.page.sign(支付宝个人协议页面签约接口)(API#alipay.user.agreement.page.sign#api_url)](/API#alipay.user.agreement.page.sign#api_url)使用`alipayClient.pageExecute(request,"get")`生成签约字符串。 4. 使用二维码生成工具把签约字符串转成二维码,用户扫码签约。 5. PHP 语言生成的签约字符串有可能会被转义,需要 htmlspecialchars 处理之后的签约字符串生成二维码。 ## App内唤起签约页 ### iOS 接入方式 #### 导入说明 ##### 接入客户端支付宝 SDK 查看 [@SDK&DEMO(repo#0039c0#361aba89#0f6y00)](/repo#0039c0#361aba89#0f6y00) 获取 **支付SDK:AlipaySDK(15.8.28+)**或者 **独立签约SDK:APDeductSDK**。
启动 IDE(如 Xcode),把下载的 SDK 压缩文件中以下文件拷贝到项目文件夹下,并导入到项目工程中。在需要调用 AlipaySDK 的文件中,增加头文件引用。 ```csharp #import // 或 #import ``` **接口说明** ```csharp /** * 独立签约 * * @param signParams 签约字符串 * @param schemeStr 调用签约的app注册在info.plist中的scheme * @param universalLink 调用签约的app注册的universalLink * @param block 签约结果回调Block */ + (void)callDeduct:(NSString *)signParams fromScheme:(NSString *)schemeStr fromUniversalLink:(NSString *)universalLink andCompletion:(AFServiceResultBlock)block; ``` ##### 配置应用回跳 Scheme 在本工程 plist 文件如下位置配置用于跳转到该应用的 scheme:
(此处 Demo 配置的 scheme 为 `afauthdemo`) ![](https://gw.alipayobjects.com/zos/skylark-tools/public/files/f3150b8cdc5e2024b34f06a197231200.png#clientId=uc2510eaf-1364-4&height=382&id=B2mwH&originHeight=886&originWidth=1728&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=u4dc1675d-7669-46cf-aab1-ef2d80a4cb2&title=&width=746) #### 调用样例 ##### **拼装 url 参数** [@alipay.user.agreement.page.sign(支付宝个人协议页面签约接口)(API#alipay.user.agreement.page.sign#api_url)](/API#alipay.user.agreement.page.sign#api_url)使用 alipayClient.sdkExecute(request) 请求,生成的签约字符串(sign_params)如下: ```java biz_content=%7B%22access_params%22%3A%7B%22channel%22%3A%22ALIPAYAPP%22%7D%2C%22external_agreement_no%22%3A%22shiyun20191231_15%22%2C%22external_logon_id%22%3A%22%E5%A4%96%E9%83%A8%E7%99%BB%E9%99%86%E5%A5%BD%22%2C%22personal_product_code%22%3A%22GENERAL_WITHHOLDING_P%22%2C%22sign_scene%22%3A%22INDUSTRY%7CMULTI_MEDIA%22%7D&sign=HrpbNe2rIXkA1ZOjG65J1M2jVNPrBr7ka7APCB9bo2KABMdu9OqR4vx%2FaTvvJl9RSpuOLYoVYN%2BBQjczXiPJw4s7vpQS6TvaIFnbOQsH4K8YAEu3r9gxGm0OyuXYKanzZUSRujsGQYrhAwUT3k%2Bkd2eM6ta5hUymyuQJYA093PFwIIv5BMDz334z%2B%2BMz2OrnW5b78d556wYxYlrELw15RhLtvR1oHeSMo4WKK3suPEVVWF2YB%2Be6WQE8cGOQ7NiWtTytiqePeBkZNXuJJQjqoQ6WltTXDaeICDJESst0FKM6j0AtOctzIKb9o8uLwpF70dkYzyFe6ATqsdkb%2Foajzg%3D%3D×tamp=2020-01-13+10%3A33%3A07&sign_type=RSA2&charset=UTF-8&app_id=2017090501336035&method=alipay.user.agreement.page.sign&version=1.0 ``` ##### **调用 SDK 接口唤起签约** ```csharp - ( void ) doDeduct { [APDeductSDK callDeduct:sign_params fromScheme:AP_DEMO_SCHEME fromUniversalLink:AP_DEMO_ULINK andCompletion:^(AFServiceResponse * _Nonnull response) { // 该接口上的block只有在跳转钱包授权过程中压后台app被系统kill掉时才会被回调 if ( AFResSuccess == response . responseCode ) { NSLog ( @ "%@" , response . result ); /* 数据样例 { "alipay_user_agreement_page_sign_response": { "app_id": "2017090501336035", "external_agreement_no": "shiyun20191231_01", "valid_time": "2020-01-07 11:46:17", "sign_scene": "INDUSTRY|MULTI_MEDIA", "external_logon_id": "外部登陆号", "timestamp": "2020-01-07 11:46:18", "sign_time": "2020-01-07 11:46:17", "agreement_no": "20204907001538464331", "invalid_time": "2115-02-01 00:00:00", "personal_product_code": "GENERAL_WITHHOLDING_P", "code": "10000", "auth_app_id": "xxx", "charset": "UTF-8", "alipay_logon_id": "131******14", "msg": "Success", "status": "NORMAL" }, "sign": "xxx", "sign_type": "RSA2", "return_url": "" } */ } }]; } ``` ##### **结果获取** 由于 iOS 的 UniversalLink 机制在某些场景下存在无法正常跳转的问题,这里需要针对 scheme 跳转与UniversalLink 都做处理。
**scheme 回跳处理**
调用接口 ```objectivec /** 处理钱包服务回跳APP的URL @param url 回跳URL @param block 业务结果回掉的block,详情见调用接口入参上的block。注意此接口上的block只有在跳转钱包后,当前APP被系统回收的情况下回跳才生效 */ + (void)handleResponseURL:(NSURL *)url withCompletion:(AFServiceResultBlock)block; ``` 调用方式 ```objectivec - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { if ([url.host isEqualToString:@"apmqpdispatch"]) { [AFServiceCenter handleResponseURL:url withCompletion:^(AFServiceResponse *response) { if (AFResSuccess == response.responseCode) { NSLog(@"%@", response.result); } }]; return YES; } return YES; } ``` **Universal Link 回跳处理(可选)**
调用接口 ```objectivec /** * 处理支付宝app支付后通过universalLink跳回商户app携带的支付结果处理 * * @param userActivity 系统接口传入的userActivity * @param block 支付结果回调 为nil时默认使用支付接口的completionBlock * @return YES表示能处理,NO表示不能处理 */ + (BOOL)handleOpenUniversalLink:(NSUserActivity *)userActivity withCompletion:(AFServiceResultBlock)block; ``` 调用方式 ```objectivec - (BOOL)application:(UIApplication *)app continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray> * _Nullable))restorationHandler { BOOL isHandle = [AFServiceCenter handleOpenUniversalLink:userActivity withCompletion:^(AFServiceResponse *response) { if (AFResSuccess == response.responseCode) { NSLog(@"%@", response.result); } }]; if (isHandle) { return YES; } return YES; } ``` ##### 结果回调 AFServiceResponse ```java /** 钱包服务调用结果状态吗 - AFResSuccess: 默认值,业务调用成功,结果数据参见result字段 - AFResInvalidService: service枚举值错误 - AFResInvalidURL: 钱包回跳URL错误 - AFResRepeatCall: 业务重复调用(3s内) - AFResOpenURLErr: 跳转失败 */ ``` #### Universal Links 配置(可选) 独立签约App接入方式支持了App token 校验功能,该功能在 iOS 系统下依赖 Universal Link 的引入,详情可查看 [@Universal Links配置(repo#0039c0#b31ed629#0f5100)](/repo#0039c0#b31ed629#0f5100)。 ### Android 接入方式 #### 导入说明 ##### 接入客户端支付宝 SDK 请参考 [Android 支付宝 SDK 集成流程](https://opendocs.alipay.com/open/00dn75) 直到 **运行权限 **一节为止的指导,接入 **含有独立签约功能的支付宝 SDK**。 ##### 配置应用回跳 Scheme 在使用支付宝 SDK 的独立签约功能时,签约业务完成后,支付宝 App 将以 Intent 跳转的形式将结果传递给您的 App。为此,您需要配置一个 App 特有的 Scheme 以接收业务结果。
请在您 App 的 AndroidManifest.xml 配置文件中增加以下配置(请将其中的 `__alipaysdkdemo__` 替换为您的 App 特有的 Scheme): ```html ``` #### 调用样例 ##### 拼装参数 调用 `OpenAuthTask.execute()` 时的参数: ```java /** * @param schema 您之前在 AndroidManifest 上配置的 App 特有 Scheme,如上文中的 __alipaysdkdemo__ * @param bizType 对于独立签约业务,值固定为 BizType.Deduct * @param params 随 bizType 各不相同的业务参数。对于独立签约业务,仅需要一个参数 "sign_params"。 * @param callback 业务完成后的结果回调 * @param useBrowserLanding 是否在用户未安装支付宝的情况下,展示一个 H5 页面引导用户安装支付宝 */ execute ( String schema , BizType bizType , Map < String , String > params , Callback callback , boolean useBrowserLanding ); ``` 上述参数中,`params` 参数内的 `sign_params` 是业务参数,拼接格式参考本文 **创建签约协议内容** 章节的 **示例代码**。 `sign_params` 值如下示例: ```java biz_content=%7B%22access_params%22%3A%7B%22channel%22%3A%22ALIPAYAPP%22%7D%2C%22external_agreement_no%22%3A%22shiyun20191231_15%22%2C%22external_logon_id%22%3A%22%E5%A4%96%E9%83%A8%E7%99%BB%E9%99%86%E5%A5%BD%22%2C%22personal_product_code%22%3A%22GENERAL_WITHHOLDING_P%22%2C%22sign_scene%22%3A%22INDUSTRY%7CMULTI_MEDIA%22%7D&sign=HrpbNe2rIXkA1ZOjG65J1M2jVNPrBr7ka7APCB9bo2KABMdu9OqR4vx%2FaTvvJl9RSpuOLYoVYN%2BBQjczXiPJw4s7vpQS6TvaIFnbOQsH4K8YAEu3r9gxGm0OyuXYKanzZUSRujsGQYrhAwUT3k%2Bkd2eM6ta5hUymyuQJYA093PFwIIv5BMDz334z%2B%2BMz2OrnW5b78d556wYxYlrELw15RhLtvR1oHeSMo4WKK3suPEVVWF2YB%2Be6WQE8cGOQ7NiWtTytiqePeBkZNXuJJQjqoQ6WltTXDaeICDJESst0FKM6j0AtOctzIKb9o8uLwpF70dkYzyFe6ATqsdkb%2Foajzg%3D%3D×tamp=2020-01-13+10%3A33%3A07&sign_type=RSA2&charset=UTF-8&app_id=2017090501336035&method=alipay.user.agreement.page.sign&version=1.0 ``` ##### 结果获取 Android 平台在调用会传入 callback 参数,具体示例如下。 ```java /** * 通用跳转授权业务的回调方法。 * 您需要避免在 onResult() 中持有 Activity 等对象的强引用来避免内存泄漏。必要时 * 建议使用 WeakRef。 */ final OpenAuthTask.Callback openAuthCallback = new OpenAuthTask.Callback(){ @Override public void onResult (int resultCode,String memo,Bundle bundle){ if( resultCode == OpenAuthTask.OK){ // 对业务完成的结果做后续处理 showAlert (activityRef,String.format( "业务成功,结果码: %s\n结果信息: %s\n结果数据: %s" , resultCode , memo , bundleToString ( bundle ))); } else { // 对业务失败的结果做后续处理 showAlert ( activityRef, String.format ( "业务失败,结果码: %s\n结果信息: %s\n结果数据: %s" , resultCode , memo , bundleToString ( bundle ))); } } }; ``` 在 `onResult` 的 `resultCode` 参数中可能出现的错误码(返回码)。 ```java OpenAuthTask.OK = 9000 - 调用成功 OpenAuthTask.Duplex = 5000 - 3 秒内快速发起了多次调用而失败。 OpenAuthTask.NOT_INSTALLED = 4001 - 用户未安装支付宝 App。 OpenAuthTask.SYS_ERR = 4000 - 其它错误,如参数传递错误。 ``` ## 小程序内唤起签约页 1. 接入小程序 [JSAPI支付产品](https://opendocs.alipay.com/mini/05xmim?pathHash=e9ca29c2)。 使用 [my.paySignCenter](https://opendocs.alipay.com/mini/006v6d)(小程序独立签约接口)。使用该方法可以区分来自APP和小程序的不同签约页请求。 2. [@alipay.user.agreement.page.sign(支付宝个人协议页面签约接口)(API#alipay.user.agreement.page.sign#api_url)](/API#alipay.user.agreement.page.sign#api_url)使用 `alipayClient.sdkExecute()`把生成的签约字符串使用 URLEncoder 处理后再返回。
**注意**:小程序场景调用 [@alipay.user.agreement.page.sign(支付宝个人协议页面签约接口)(API#alipay.user.agreement.page.sign#api_url)](/API#alipay.user.agreement.page.sign#api_url)无需设置 return_url,商户监听接口的同步通知结果,然后做出对应的引导。 ```java AlipayUserAgreementPageSignResponse response = alipayClient.sdkExecute(request); String signStr = URLEncoder.encode(response.getBody(), "UTF-8"); ``` # 页面签约通知说明 ## 签约同步通知说明 - 商家请求[@alipay.user.agreement.page.sign(支付宝个人协议页面签约接口)(API#alipay.user.agreement.page.sign#api_url)](/API#alipay.user.agreement.page.sign#api_url)接口时如果传了 return_url,用户签约成功跳转到 return_url,同步通知会在商家传入的 return_url 后面拼接返回。如果商家接口中未传入 return_url 则用户签约完成后不再返回商家,直接回到支付宝客户端首页。 - 有些时候会出现商家 App 在支付宝签约阶段被关闭导致无法正确收到同步结果,商家可以将同步签约结果仅作为一个签约结束的通知(**忽略执行验签**),实际签约是否成功,完全依赖服务端异步通知,如果商家未接入异步通知,则可通过签约查询接口获取签约结果。 ### 签约成功同步通知示例 ``` http://api.test.alipay.net/atinterface/receive_notify.htm?agreement_no=20170627457298962889&status=NORMAL&external_logon_id=13852852877&sign_type=RSA&charset=UTF-8&auth_app_id=2017060101317939&invalid_time=2017-08-27+11%3A40%3A13&personal_product_code=CYCLE_PAY_AUTH_P&version=1.0&code=10000&msg=Success&sign=quJNMiI1sVlm8hFoRx5fu%2FzZ5lQoMDkT%2BdZAWWaEQDOxNaKYjr0FdFzr4L7HfUFf6wDr05Yve2%2FkhsADulgoGwrL2w7AzmQCitZTvzUveVte9imm9mGTNK%2F7uXa%2BkWYDZM8a3iygOPItr0htghHM7CQZh5gdt8k5nIdVtmYk2YY%3D×tamp=2017-06-27+11%3A40%3A15&sign_scene=INDUSTRY%7CCARRENTAL&valid_time=2017-06-27+11%3A40%3A13&external_agreement_no=test212&app_id=2017060101317939&method=alipay.user.agreement.page.sign&alipay_logon_id=1382877&sign_time=2017-06-27+11%3A40%3A14 ``` ## 签约异步通知说明 签约异步通知仅当用户签约成功时触发。商家以 POST 接收方式接收异步签约通知,优先接收接口[@alipay.user.agreement.page.sign(支付宝个人协议页面签约接口)(API#alipay.user.agreement.page.sign#api_url)](/API#alipay.user.agreement.page.sign#api_url)中传的 notify_url,若没传则取**应用网关 **地址(商家必须在[开放平台](https://openhome.alipay.com/platform/home.htm) **应用信息**中配置**应用网关**)。 ### 商家验签 在通知返回参数列表中除去 sign、sign_type 两个参数外,凡是通知返回回来的参数皆是待验签的参数。 ### 异步通知示例 根据 status 触发条件,只有签约成功和解约成功才会返回异步,签约失败和解约失败都不会触发异步。 ```json charset=utf-8¬ify_time=2020-04-24 11:28:20&alipay_user_id=2088*****9864&alipay_open_id=074a1CcTG1LelxKe4xQC0zgNdId0nxi95b5lsNpazWYoCo5&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&next_deduct_time=2022-06-15 //用户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:用户的支付宝登录账号。 - next_deduct_time:周期扣协议,预计下次扣款时间。 # 签约成功后扣款 商家根据用户签约成功支付宝返回的协议号(agreement_no)每次主动调 [@alipay.trade.pay(统一收单交易支付接口)(API#alipay.trade.pay#api_url)](/API#alipay.trade.pay#api_url),完成后续扣款操作。
**注意**:为保障用户体验,扣费操作不可在晚上执行,请于北京时间 **7:00~22:00** 期间发起扣款。 ## 扣款流程图 ![image (3).png](https://cdn.nlark.com/yuque/0/2022/png/179989/1667875653350-ff2b08f8-2009-4bbe-9546-63cf7f79c977.png#height=673&id=zg0ap&originHeight=1286&originWidth=1146&originalType=binary&ratio=1&rotation=0&showTitle=false&size=243251&status=done&style=none&title=&width=600)**注意:**允许商家在扣款日 execute_time前 5 天开始扣款,例:约定扣款日为 20 号,支持商家从 15 至 20 号发起扣款。 ## 示例代码 ```java {{std::example#alipay.trade.pay|b4d9c9906e14451b99c8de390ae20fea|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(统一收单交易查询接口)(API#alipay.trade.query#api_url)](/API#alipay.trade.query#api_url)查询交易状态,如果交易状态是成功,则无需特殊处理;若查询 4 次后依然返回等待用户付款,商户可以选择幂等重试扣款或通过 [@alipay.trade.cancel(统一收单交易撤销接口)(API#alipay.trade.cancel#api_url)](/API#alipay.trade.cancel#api_url)发起交易撤销。 | **结果码** | **说明** | **处理方式** | | --- | --- | --- | | 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(统一收单交易支付接口)(API#alipay.trade.pay#api_url)](/API#alipay.trade.pay#api_url)时: - product_code:必填,产品码。固定为GENERAL_WITHHOLDING。 - subject:必填,订单标题。不可使用特殊字符,如 /,=,& 等。 - agreement_params:必填,签约信息。 - agreement_no:必填,支付宝系统中用以唯一标识用户签约记录的编号(用户签约成功后的协议号)。 - 如果不填卖家 seller_id,则默认为商家签约账号对应的支付宝用户 ID。 ## 支付异步通知参数 支付成功异步通知参数说明具体请查看 [异步通知说明](https://opendocs.alipay.com/open/0amki1?pathHash=f6ef64bf)。 # 辅助功能 ## 商家扣款协议查询 商家可调用 [@alipay.user.agreement.query(支付宝个人代扣协议查询接口)(API#alipay.user.agreement.query#api_url)](/API#alipay.user.agreement.query#api_url)查询用户是否完成签约操作,用户实际签约结果请以查询接口返回值为准。 - 如果在支付宝个人协议页面签约接口中传递了`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)`2 个参数中的任何一个参数)即可查询到内容。 ## 商家扣款协议解约 ### 商家解约 开发者可调用 [@alipay.user.agreement.unsign(支付宝个人代扣协议解约接口)(API#alipay.user.agreement.unsign#api_url)](/API#alipay.user.agreement.unsign#api_url)完成协议解约。 - 通过协议号解约,此时请求参数中填入协议号(agreement_no),其它业务参数均可不填。 - 通过`personal_product_code`+`sign_scene+external_agreement_no`+`alipay_logon_id+alipay_user_id(alipay_open_id)`来解约,入参值按照商家调[@alipay.user.agreement.page.sign(支付宝个人协议页面签约接口)(API#alipay.user.agreement.page.sign#api_url)](/API#alipay.user.agreement.page.sign#api_url)中的对应值传入;如果传入 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(支付宝个人代扣协议解约接口)(API#alipay.user.agreement.unsign#api_url)](/API#alipay.user.agreement.unsign#api_url)中的异步通知格式。
**注意:** - 当用户通过支付宝 APP 解约成功后,支付宝发送给商家的异步通知参数**编码方式**优先采用签约应用(APPID)在开放平台上配置的编码方式,若无配置默认为**GBK**编码。 - 若应用类型为生活号请查看[生活号接入文档](https://opendocs.alipay.com/fw/guide/105933#CzMpJ)激活开发者模式。 ### 解约异步通知说明 解约异步通知仅当用户解约成功或商家调解约接口成功时触发。商家以 POST 方式接收异步解约通知,如果是用户解约成功通知地址是 **应用网关** 地址(商家必须在 [开放平台](https://openhome.alipay.com/platform/home.htm) **应用信息** 中配置 **应用网关**)。如果是商家调 [@alipay.user.agreement.unsign(支付宝个人代扣协议解约接口)(API#alipay.user.agreement.unsign#api_url)](/API#alipay.user.agreement.unsign#api_url)接口解约优先接收接口中传的 notify_url,如果没传则取 **应用网关** 地址。 #### 异步通知示例 ```json 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(支付宝个人代扣协议查询接口)(API#alipay.user.agreement.query#api_url)](/API#alipay.user.agreement.query#api_url)查询协议,会提示 **用户协议不存在(USER_AGREEMENT_NOT_EXIST)**,不会返回 status=UNSIGN 的状态。 ## 订单支付后续 - 使用 [@alipay.trade.refund(统一收单交易退款接口)(API#alipay.trade.refund#api_url)](/API#alipay.trade.refund#api_url)完成退款。 - 使用 [@alipay.trade.cancel(统一收单交易撤销接口)(API#alipay.trade.cancel#api_url)](/API#alipay.trade.cancel#api_url)完成撤销。 - 使用 [@alipay.trade.close(统一收单交易关闭接口)(API#alipay.trade.close#api_url)](/API#alipay.trade.close#api_url)完成关闭交易订单。 ## 延期扣款 商家可调用 [@alipay.user.agreement.executionplan.modify(周期性扣款协议执行计划修改接口)(API#alipay.user.agreement.executionplan.modify#api_url)](/API#alipay.user.agreement.executionplan.modify#api_url)实现延期扣款。
例:用户在 1 月 1 日开通了连续包月,使用了 10 天又另行购买了季度包,如果此时商家希望季度包立即优先生效,在季度包结束后能继续使用连续包月,那么原定的周期就被延后了,如果不做处理那么扣款时间就对不上。此时可以由商家调用推迟接口,将预计扣款时间推后季度包的时长。 ### 示例代码 ```java {{std::example#alipay.user.agreement.executionplan.modify||request|java}} ``` # 接口报错 接口异常信息及解决方案,详情可查看 [@常见问题(repo#0039c0#b282297f#08bcgy)](/repo#0039c0#b282297f#08bcgy)。