完成 [接入准备](https://ideservice.alipay.com/cms/site/0izcrm) 后,商家/服务商可根据本文指引快速集成 **订单码支付 **产品。
**说明:**
- **订单码支付 **仅支持自研商家/服务商通过 [自研应用](https://ideservice.alipay.com/cms/site/02bijh) 或 [第三方应用](https://ideservice.alipay.com/cms/site/02bijh) 代调用方式,调用 API 接入。
- **订单码支付 **支持沙箱环境调试,详情可查看 [沙箱调试说明](https://ideservice.alipay.com/cms/site/0izcs5)。
# 接入方式
订单码支付适合有各类自助终端的商家,用户在自助终端通过扫码完成支付。订单码支付采用 **商家/系统服务商后台转发** 方式接入,商家先预下单到商家后台,再请求到支付宝。
## 接入流程
支付宝为了保证交易安全采取了一系列安全手段以保证交易安全。主要采用以下安全设计策略,详情可点击了解 [应用安全开发指南](https://ideservice.alipay.com/cms/site/02kg63) 。
- 采用 HTTPS 协议传输交易数据,防止数据被截获、解密。
- 采用 RSA/RSA2 非对称密钥,明确交易双方的身份,保证交易主体的正确性和唯一性。
# 支付流程
## 系统交互流程
```
sequenceDiagram
actor 用户
participant APP as 支付宝APP
participant Merchant as 商户系统
participant Alipay as 支付宝系统
Merchant->>Alipay: 1. 调用alipay.trade.precreate 请求生成二维码链接
Alipay-->>Merchant: 1.1 同步返回二维码链接
Merchant->>Merchant: 2. 将二维码链接转换成二维码
用户->>APP: 3. 打开支付宝钱包
APP->>Merchant: 3.1 用户扫码
APP->>Alipay: 3.2 输入支付密码完成支付
Alipay-->>APP: 3.3 返回支付成功信息
Alipay-->>Merchant: 3.4 若支付成功则返回异步消息
Merchant->>Alipay: 3.4.1 商户返回success
loop 启动定时任务轮询 建议3到5s一次查询交易状态
Merchant->>Alipay: 4. 调用alipay.trade.query查询订单状态
Alipay-->>Merchant: 4.1 返回查询结果
opt 若返回支付成功 code=10000 则流程结束
note over Merchant,Alipay: 支付成功(code=10000),流程结束,退出轮询
end
opt 若返回等待用户付款 code=10003 或系统异常 code=20000 或网络超时 则继续循环
note over Merchant,Alipay: 等待付款(code=10003) 或 系统异常(code=20000) 或 网络超时,继续轮询
end
opt 若在指定时间内未完成支付
Merchant->>Alipay: 5. 调用alipay.trade.cancel进行交易关闭
Alipay-->>Merchant: 5.1 同步返回撤销结果
end
end
```
1. 商家系统调用[alipay.trade.precreate(统一收单线下交易预创建接口)](https://ideservice.alipay.com/cms/site/0izl4a),获得该订单的二维码串 qr_code,开发者需要利用二维码生成工具获得最终的订单二维码图片。
2. 发起轮询获得支付结果:等待 5 秒后调用 [alipay.trade.query(统一收单交易查询接口)](https://ideservice.alipay.com/cms/site/0izl4d),通过支付时传入的商户订单号(out_trade_no)查询支付结果(返回参数 TRADE_STATUS)。
1. 如果仍然返回等待用户付款(WAIT_BUYER_PAY),则再次等待 5 秒后继续查询,直到返回确切的支付结果(成功 TRADE_SUCCESS 或 已撤销关闭 TRADE_CLOSED),或是超出轮询时间。
2. 在最后一次查询仍然返回等待用户付款的情况下,必须立即调用 [alipay.trade.cancel(统一收单交易撤销接口)](https://ideservice.alipay.com/cms/site/0izl4c)将这笔交易撤销,避免用户继续支付。
3. 除了主动轮询,当订单支付成功时,商家也可以通过设置异步通知(notify_url)来获得支付宝服务端返回的支付结果,详情可查看 [异步通知说明](https://ideservice.alipay.com/cms/site/0j2td9)。如商家由于客观原因(如无公网服务器接受支付宝请求等)无法接受异步支付通知,则忽略上图中的步骤 3.4 和 3.4.1。更多注意事项可点击查看 [异常处理](https://ideservice.alipay.com/cms/site/069hih#%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86)。
**注意:**
- 一定要对异步通知验签,确保通知是支付宝发出的。
- 由于网络异常等原因,可能会导致用户支付成功,但是商户侧未能成功接收到支付结果异步通知。因此当商家未收到支付结果通知时,必须要调用 alipay.trade.query(统一收单交易查询接口)来获取支付结果。
## 交易状态流程
随着订单支付成功、退款、关闭等操作,订单交易的每一个环节 **trade_status**(交易状态)不同。
1. 交易创建成功后,用户支付成功,交易状态转为 **TRADE_SUCCESS**(交易成功)。
2. 交易成功后,规定退款时间内没有退款,交易状态转为 **TRADE_FINISHED**(交易完成)。
3. 交易支付成功后,交易部分退款,交易状态为 **TRADE_SUCCESS**(交易成功)。
4. 交易成功后,交易全额退款,交易状态转为 **TRADE_CLOSED**(交易关闭)。
5. 交易创建成功后,用户未付款交易超时关闭,交易状态转为 **TRADE_CLOSED**(交易关闭)。
6. 交易创建成功后,用户支付成功后,若用户商品不支持退款,交易状态直接转为 **TRADE_FINISHED**(交易完成)。
**注意**:交易成功后部分退款,交易状态仍为 **TRADE_SUCCESS**(交易成功),如果一直部分退款退完所有交易金额则交易状态转为 **TRADE_CLOSED**(交易关闭),如果未退完所有交易金额,超过有效退款时间后交易状态转为 **TRADE_FINISHED**(交易完成)不可退款。
## 下单
商家可调用 [alipay.trade.precreate(统一收单线下交易预创建接口)](https://ideservice.alipay.com/cms/site/0izl4a)传入订单商品及金额的信息,支付宝将返回支付二维码字符串,商家需利用二维码生成工具将二维码字符串转换为二维码用于用户扫码支付。
**重要说明:**
1. 接口请求成功后返回 qr_code 开始计时,有效期 2 小时。
2. 涉及返佣必传 sys_service_provider_id。
3. 扫码支付不存在同步跳转,支付后只会触发异步通知。由于网络异常等原因,可能会导致用户支付成功,但是商户侧未能成功接收到支付结果异步通知。因此当商家未收到支付结果通知时,必须要调用 alipay.trade.query(统一收单交易查询接口)来获取支付结果。
### 示例代码
```java
package com.java.sdk.demo;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.ExtendParams;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.domain.GoodsDetail;
import com.alipay.api.domain.BusinessParams;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.FileItem;
import java.util.Base64;
import java.util.ArrayList;
import java.util.List;
public class AlipayTradePrecreate {
public static void main(String[] args) throws AlipayApiException {
// 初始化SDK
AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());
// 构造请求参数以调用接口
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
// 设置商户订单号
model.setOutTradeNo("20150320010101001");
// 设置订单总金额
model.setTotalAmount("88.88");
// 设置订单标题
model.setSubject("Iphone6 16G");
// 设置产品码
model.setProductCode("QR_CODE_OFFLINE");
// 设置卖家支付宝用户ID
model.setSellerId("2088102146225135");
// 设置订单附加信息
model.setBody("Iphone6 16G");
// 设置订单包含的商品列表信息
List goodsDetail = new ArrayList();
GoodsDetail goodsDetail0 = new GoodsDetail();
goodsDetail0.setGoodsName("ipad");
goodsDetail0.setQuantity(1L);
goodsDetail0.setPrice("2000");
goodsDetail0.setGoodsId("apple-01");
goodsDetail0.setGoodsCategory("34543238");
goodsDetail0.setCategoriesTree("124868003|126232002|126252004");
goodsDetail0.setShowUrl("http://www.alipay.com/xxx.jpg");
goodsDetail.add(goodsDetail0);
model.setGoodsDetail(goodsDetail);
// 设置业务扩展参数
ExtendParams extendParams = new ExtendParams();
extendParams.setSysServiceProviderId("2088511833207846");
model.setExtendParams(extendParams);
// 设置商户传入业务信息
BusinessParams businessParams = new BusinessParams();
businessParams.setMcCreateTradeIp("127.0.0.1");
model.setBusinessParams(businessParams);
// 设置可打折金额
model.setDiscountableAmount("80.00");
// 设置商户门店编号
model.setStoreId("NJ_001");
// 设置商户操作员编号
model.setOperatorId("yx_001");
// 设置商户机具终端编号
model.setTerminalId("NJ_T_001");
// 设置商户的原始订单号
model.setMerchantOrderNo("20161008001");
request.setBizModel(model);
// 第三方代调用模式下请设置app_auth_token
// request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->");
AlipayTradePrecreateResponse response = alipayClient.execute(request);
System.out.println(response.getBody());
if (response.isSuccess()) {
System.out.println("调用成功");
} else {
System.out.println("调用失败");
// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
// String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
// System.out.println(diagnosisUrl);
}
}
private static AlipayConfig getAlipayConfig() {
String privateKey = "<-- 请填写您的应用私钥,例如:MIIEvQIBADANB ... ... -->";
String alipayPublicKey = "<-- 请填写您的支付宝公钥,例如:MIIBIjANBg... -->";
AlipayConfig alipayConfig = new AlipayConfig();
alipayConfig.setServerUrl("https://openapi.alipay.com/gateway.do");
alipayConfig.setAppId("<-- 请填写您的AppId,例如:2019091767145019 -->");
alipayConfig.setPrivateKey(privateKey);
alipayConfig.setFormat("json");
alipayConfig.setAlipayPublicKey(alipayPublicKey);
alipayConfig.setCharset("UTF-8");
alipayConfig.setSignType("RSA2");
return alipayConfig;
}
}
```
### 重要入参说明
**注意**:请严格按照接口文档中的参数入参,传入非接口文档中的参数是无效的,并且可能会导致请求被拦截或其它异常。
| **请求参数** | **说明** |
| --- | --- |
| out_trade_no | 商户订单号,需要保证商家系统不重复。 |
| total_amount | 订单金额。 |
| subject | 商品的标题/交易标题/订单标题/订单关键字等。不可使用特殊字符,如 `/`,`=`,`&` 等。 |
| product_code | 产品码,固定传:QR_CODE_OFFLINE。 |
### 重要出参说明
| **请求参数** | **说明** |
| --- | --- |
| qr_code | 订单二维码(有效时间 2 小时)以字符串的格式返回,开发者需要自己使用工具根据内容生成二维码图片。 |
## 查询交易
商家可调用 [alipay.trade.query(统一收单交易查询接口)](https://ideservice.alipay.com/cms/site/0izl4d),通过商家网站唯一订单号 out_trade_no 或支付宝交易号 trade_no 查询对应订单支付情况。
### 示例代码
```java
package com.java.sdk.demo;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.FileItem;
import java.util.Base64;
import java.util.ArrayList;
import java.util.List;
public class AlipayTradeQuery {
public static void main(String[] args) throws AlipayApiException {
// 初始化SDK
AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());
// 构造请求参数以调用接口
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
AlipayTradeQueryModel model = new AlipayTradeQueryModel();
// 设置订单支付时传入的商户订单号
model.setOutTradeNo("20150320010101001");
// 设置支付宝交易号
model.setTradeNo("2014112611001004680 073956707");
// 设置银行间联模式下有用
model.setOrgPid("2088101117952222");
// 设置查询选项
List queryOptions = new ArrayList();
queryOptions.add("trade_settle_info");
model.setQueryOptions(queryOptions);
request.setBizModel(model);
// 第三方代调用模式下请设置app_auth_token
// request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->");
AlipayTradeQueryResponse response = alipayClient.execute(request);
System.out.println(response.getBody());
if (response.isSuccess()) {
System.out.println("调用成功");
} else {
System.out.println("调用失败");
// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
// String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
// System.out.println(diagnosisUrl);
}
}
private static AlipayConfig getAlipayConfig() {
String privateKey = "<-- 请填写您的应用私钥,例如:MIIEvQIBADANB ... ... -->";
String alipayPublicKey = "<-- 请填写您的支付宝公钥,例如:MIIBIjANBg... -->";
AlipayConfig alipayConfig = new AlipayConfig();
alipayConfig.setServerUrl("https://openapi.alipay.com/gateway.do");
alipayConfig.setAppId("<-- 请填写您的AppId,例如:2019091767145019 -->");
alipayConfig.setPrivateKey(privateKey);
alipayConfig.setFormat("json");
alipayConfig.setAlipayPublicKey(alipayPublicKey);
alipayConfig.setCharset("UTF-8");
alipayConfig.setSignType("RSA2");
return alipayConfig;
}
}
```
### 重要入参说明
**注意**:请严格按照接口文档中的参数入参,传入非接口文档中的参数是无效的,并且可能会导致请求被拦截或其它异常。
| **请求参数** | **说明** |
| --- | --- |
| out_trade_no | 支付时传入的商户订单号,与 trade_no 必填一个。 |
| trade_no | 支付时返回的支付宝交易号,与 out_trade_no 必填一个。 |
## 撤销交易
支付交易返回失败或支付系统超时,商家可调用 [alipay.trade.cancel(统一收单交易撤销接口)](https://ideservice.alipay.com/cms/site/0izl4c)通过商家网站唯一订单号 out_trade_no 或支付宝交易号 trade_no 撤销交易。
**重要说明**
- 如果此订单用户支付失败,支付宝将关闭此订单,用户无法继续支付。
- 如果此订单用户支付成功,支付宝将退还订单资金给用户,交易状态变为trade_close(交易关闭)。
- 仅发生支付系统超时或者支付结果未知时可调用本接口撤销交易,其它正常支付的单如需实现相同功能请调用 [alipay.trade.refund(统一收单交易退款接口)](https://ideservice.alipay.com/cms/site/0izofs)。
### 示例代码
```java
package com.java.sdk.demo;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.request.AlipayTradeCancelRequest;
import com.alipay.api.domain.AlipayTradeCancelModel;
import com.alipay.api.response.AlipayTradeCancelResponse;
import com.alipay.api.FileItem;
import java.util.Base64;
import java.util.ArrayList;
import java.util.List;
public class AlipayTradeCancel {
public static void main(String[] args) throws AlipayApiException {
// 初始化SDK
AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());
// 构造请求参数以调用接口
AlipayTradeCancelRequest request = new AlipayTradeCancelRequest();
AlipayTradeCancelModel model = new AlipayTradeCancelModel();
// 设置原支付请求的商户订单号
model.setOutTradeNo("20150320010101001");
// 设置支付宝交易号
model.setTradeNo("2014112611001004680073956707");
request.setBizModel(model);
// 第三方代调用模式下请设置app_auth_token
// request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->");
AlipayTradeCancelResponse response = alipayClient.execute(request);
System.out.println(response.getBody());
if (response.isSuccess()) {
System.out.println("调用成功");
} else {
System.out.println("调用失败");
// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
// String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
// System.out.println(diagnosisUrl);
}
}
private static AlipayConfig getAlipayConfig() {
String privateKey = "<-- 请填写您的应用私钥,例如:MIIEvQIBADANB ... ... -->";
String alipayPublicKey = "<-- 请填写您的支付宝公钥,例如:MIIBIjANBg... -->";
AlipayConfig alipayConfig = new AlipayConfig();
alipayConfig.setServerUrl("https://openapi.alipay.com/gateway.do");
alipayConfig.setAppId("<-- 请填写您的AppId,例如:2019091767145019 -->");
alipayConfig.setPrivateKey(privateKey);
alipayConfig.setFormat("json");
alipayConfig.setAlipayPublicKey(alipayPublicKey);
alipayConfig.setCharset("UTF-8");
alipayConfig.setSignType("RSA2");
return alipayConfig;
}
}
```
### 重要入参说明
**注意**:请严格按照接口文档中的参数入参,传入非接口文档中的参数是无效的,并且可能会导致请求被拦截或其它异常。
| **请求参数** | **说明** |
| --- | --- |
| out_trade_no | 支付时传入的商户订单号,与 trade_no 必填一个。 |
| trade_no | 支付时返回的支付宝交易号,与 out_trade_no 必填一个。 |
### 重要出参说明
| **请求参数** | **说明** |
| --- | --- |
| retry_flag | 是否需要重试,枚举支持:
- Y:撤销不成功,需要重新调用接口。
- N:撤销不成功,不需要重新调用接口。
|
| action | 本次撤销触发的交易动作。
- close:关闭交易,无退款 。
- refund:产生了退款。
|
# 退款流程
当交易发生之后一段时间内,由于业务原因(如金额错误,用户退款或者对账不平等等)需要退款时,商家可以调用 [alipay.trade.refund(统一收单交易退款接口)](https://ideservice.alipay.com/cms/site/0izofs)通过商家网站唯一订单号 out_trade_no 或支付宝交易号 trade_no,将对应订单支付款退还给买家,支付宝将在收到退款请求并且验证成功之后,按照退款规则将支付款按原路退到买家账号上。支持全额或部分退款。
## 系统交互流程
```
sequenceDiagram
participant 商户系统
participant 支付宝系统
商户系统->>支付宝系统: 1: 调用alipay.trade.refund接口发起退款请求
支付宝系统-->>商户系统: 1.1: 返回退款结果
alt 退款成功无需处理
else
商户系统->>支付宝系统: 2: 如果系统异常,重新发起退款请求,确保out_request_no保持一致
end
```
## 退款说明
- 支付渠道为花呗、余额等退款即时到账。
- 银行卡的退款时间以银行退款时间为准,一般情况下 2 小时内可到账。
- 商家可以在 **商家平台** > **对账中心** > [交易订单](https://b.alipay.com/page/mbillexprod/trade/order/sold) 中退款。
- 退款是否成功可以根据同步响应的 fund_change 参数来判断,返回值为 `Y` 则表示退款成功。
- 退款接口会根据外部请求号 out_request_no 幂等返回,因此同一笔交易需要多次部分退款时,必须使用不同的 out_request_no 。
### 示例代码
```java
package com.java.sdk.demo;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.alipay.api.domain.RefundGoodsDetail;
import com.alipay.api.domain.OpenApiRoyaltyDetailInfoPojo;
import com.alipay.api.FileItem;
import java.util.Base64;
import java.util.ArrayList;
import java.util.List;
public class AlipayTradeRefund {
public static void main(String[] args) throws AlipayApiException {
// 初始化SDK
AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());
// 构造请求参数以调用接口
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
AlipayTradeRefundModel model = new AlipayTradeRefundModel();
// 设置商户订单号
model.setOutTradeNo("20150320010101001");
// 设置支付宝交易号
model.setTradeNo("2014112611001004680073956707");
// 设置退款金额
model.setRefundAmount("200.12");
// 设置退款原因说明
model.setRefundReason("正常退款");
// 设置退款请求号
model.setOutRequestNo("HZ01RF001");
// 设置退款包含的商品列表信息
List refundGoodsDetail = new ArrayList();
RefundGoodsDetail refundGoodsDetail0 = new RefundGoodsDetail();
refundGoodsDetail0.setOutSkuId("outSku_01");
refundGoodsDetail0.setOutItemId("outItem_01");
refundGoodsDetail0.setGoodsId("apple-01");
refundGoodsDetail0.setRefundAmount("19.50");
List outCertificateNoList = new ArrayList();
outCertificateNoList.add("202407013232143241231243243423");
refundGoodsDetail0.setOutCertificateNoList(outCertificateNoList);
refundGoodsDetail.add(refundGoodsDetail0);
model.setRefundGoodsDetail(refundGoodsDetail);
// 设置退分账明细信息
List refundRoyaltyParameters = new ArrayList();
OpenApiRoyaltyDetailInfoPojo refundRoyaltyParameters0 = new OpenApiRoyaltyDetailInfoPojo();
refundRoyaltyParameters0.setAmount("0.1");
refundRoyaltyParameters0.setTransIn("2088101126708402");
refundRoyaltyParameters0.setRoyaltyType("transfer");
refundRoyaltyParameters0.setTransOut("2088101126765726");
refundRoyaltyParameters0.setTransOutType("userId");
refundRoyaltyParameters0.setRoyaltyScene("达人佣金");
refundRoyaltyParameters0.setTransInType("userId");
refundRoyaltyParameters0.setTransInName("张三");
refundRoyaltyParameters0.setDesc("分账给2088101126708402");
refundRoyaltyParameters.add(refundRoyaltyParameters0);
model.setRefundRoyaltyParameters(refundRoyaltyParameters);
// 设置查询选项
List queryOptions = new ArrayList();
queryOptions.add("refund_detail_item_list");
model.setQueryOptions(queryOptions);
// 设置针对账期交易
model.setRelatedSettleConfirmNo("2024041122001495000530302869");
request.setBizModel(model);
// 第三方代调用模式下请设置app_auth_token
// request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->");
AlipayTradeRefundResponse response = alipayClient.execute(request);
System.out.println(response.getBody());
if (response.isSuccess()) {
System.out.println("调用成功");
} else {
System.out.println("调用失败");
// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
// String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
// System.out.println(diagnosisUrl);
}
}
private static AlipayConfig getAlipayConfig() {
String privateKey = "<-- 请填写您的应用私钥,例如:MIIEvQIBADANB ... ... -->";
String alipayPublicKey = "<-- 请填写您的支付宝公钥,例如:MIIBIjANBg... -->";
AlipayConfig alipayConfig = new AlipayConfig();
alipayConfig.setServerUrl("https://openapi.alipay.com/gateway.do");
alipayConfig.setAppId("<-- 请填写您的AppId,例如:2019091767145019 -->");
alipayConfig.setPrivateKey(privateKey);
alipayConfig.setFormat("json");
alipayConfig.setAlipayPublicKey(alipayPublicKey);
alipayConfig.setCharset("UTF-8");
alipayConfig.setSignType("RSA2");
return alipayConfig;
}
}
```
#### 重要入参说明
**注意**:请严格按照接口文档中的参数入参,传入非接口文档中的参数是无效的,并且可能会导致请求被拦截或其它异常。
| **请求参数** | **说明** |
| --- | --- |
| out_trade_no | 支付时传入的商户订单号,与 trade_no 必填一个。 |
| trade_no | 支付时返回的支付宝交易号,与 out_trade_no 必填一个。 |
| out_request_no | 本次退款请求流水号,部分退款时必传。 |
| refund_amount | 本次退款金额。 |
#### 重要出参说明
| **请求参数** | **说明** |
| --- | --- |
| refund_fee | 该笔交易已退款的总金额。 |
### 退款到银行卡通知
退款存在退到银行卡场景下时,支付宝会调用 [alipay.trade.refund.depositback.completed(收单退款冲退完成通知接口)](https://ideservice.alipay.com/cms/site/0izoft)根据银行回执消息发送退款完成信息至应用网关地址。
**重要说明:**
- 如需触发 [alipay.trade.refund.depositback.completed(收单退款冲退完成通知接口)](https://ideservice.alipay.com/cms/site/0izoft),需要在调用 [alipay.trade.refund(统一收单交易退款接口)](https://ideservice.alipay.com/cms/site/0izofs)时,传入参数 "query_options":["deposit_back_info"]。
- 开发者需登录 [开放平台](https://openhome.alipay.com/platform/home.htm) 进入对应应用详情页,在 **开发设置 **> **FROM 平台** 中订阅 [alipay.trade.refund.depositback.completed(收单退款冲退完成通知接口)](https://ideservice.alipay.com/cms/site/0izoft)。
更多消息服务中 **FROM平台** 消息详情可点击查看 [From蚂蚁消息](https://ideservice.alipay.com/cms/site/02km9j)。

#### 消息示例
```
ISV_GATEWAY_URL?charset=GBK&biz_content=
{
"trade_no":"2014112611001004680073956707","out_trade_no":"20150320010101001","out_request_no":"HZ01RF001","dback_status":"S","dback_amount":"1.01","bank_ack_time":"2020-06-02 14:03:48","est_bank_receipt_time":"2020-06-02 14:03:48"
}
&msg_method=alipay.trade.refund.depositback.completed&utc_timestamp=1516797622752&version=1.1&sign_type=RSA2¬ify_id=d275fec564e62af6bedbcee73f3f05fi5x&app_id=2013121700999429&sign=I+Y/lvqYUEEc10EPdpntRhFIQ==
```
#### 重要参数说明
| **请求参数** | **说明** |
| --- | --- |
| trade_no | 支付宝交易订单号。 |
| dback_status | 银行卡冲退状态。
- S - 成功。
- F - 失败。银行卡冲退失败,资金自动转入用户支付宝余额。
|
| dback_amount | 银行卡冲退金额。 |
| bank_ack_time | 银行响应时间,格式为 yyyy-MM-dd HH:mm:ss。 |
| est_bank_receipt_time | 预估银行入账时间,格式为 yyyy-MM-dd HH:mm:ss。 |
# 对账流程
目前支付宝对外的常用对账方式有两种:
- 一种是通过在 **商家平台** > [对账中心](https://mbillexprod.alipay.com/enterprise/mainIndex.htm#/) 下载账单的方式来对账。
- 一种是通过调用接口的方式来实现对账,下文介绍如何通过接口获取对账单下载链接。更多后台下载及账单示例图详情可查看 [对账说明](https://ideservice.alipay.com/cms/site/0695en)。
商家可通过接口下载指定日期(当天除外)的业务明细账单文件,并结合自身业务系统实现自动对账。
## 系统交互流程
```
sequenceDiagram
participant 商户系统
participant 支付宝
商户系统->>支付宝: 1: 调用alipay.data.dataservice.bill.downloadurl.query接口
支付宝-->>商户系统: 1.1: 返回对账单下载地址
商户系统->>支付宝: 2: 通过HTTP请求对账单下载地址
支付宝-->>商户系统: 2.1: 获得对账单文件流
商户系统->>商户系统: 3: 读取文件流处理CSV文件自动对账,或保存至本地
```
1. 商家系统调用 [alipay.data.dataservice.bill.downloadurl.query(查询对账单下载地址接口)](https://ideservice.alipay.com/cms/site/0izofq),传入指定日期,获得该日期账单文件的下载地址。
2. 商家系统通过 HTTP 方式后台访问账单下载链接,将账单 csv 文件下载到本地后自行处理。
注意:该下载链接仅 30 秒,在得到链接后系统需要立刻下载账单文件。
## 示例代码
```java
package com.java.sdk.demo;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.request.AlipayDataDataserviceBillDownloadurlQueryRequest;
import com.alipay.api.response.AlipayDataDataserviceBillDownloadurlQueryResponse;
import com.alipay.api.domain.AlipayDataDataserviceBillDownloadurlQueryModel;
import com.alipay.api.FileItem;
import java.util.Base64;
import java.util.ArrayList;
import java.util.List;
public class AlipayDataDataserviceBillDownloadurlQuery {
public static void main(String[] args) throws AlipayApiException {
// 初始化SDK
AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());
// 构造请求参数以调用接口
AlipayDataDataserviceBillDownloadurlQueryRequest request = new AlipayDataDataserviceBillDownloadurlQueryRequest();
AlipayDataDataserviceBillDownloadurlQueryModel model = new AlipayDataDataserviceBillDownloadurlQueryModel();
// 设置账单类型
model.setBillType("trade");
// 设置账单时间
model.setBillDate("2025-05-01");
// 设置二级商户smid
model.setSmid("2088123412341234");
request.setBizModel(model);
// 第三方代调用模式下请设置app_auth_token
// request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->");
AlipayDataDataserviceBillDownloadurlQueryResponse response = alipayClient.execute(request);
System.out.println(response.getBody());
if (response.isSuccess()) {
System.out.println("调用成功");
} else {
System.out.println("调用失败");
// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
// String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
// System.out.println(diagnosisUrl);
}
}
private static AlipayConfig getAlipayConfig() {
String privateKey = "<-- 请填写您的应用私钥,例如:MIIEvQIBADANB ... ... -->";
String alipayPublicKey = "<-- 请填写您的支付宝公钥,例如:MIIBIjANBg... -->";
AlipayConfig alipayConfig = new AlipayConfig();
alipayConfig.setServerUrl("https://openapi.alipay.com/gateway.do");
alipayConfig.setAppId("<-- 请填写您的AppId,例如:2019091767145019 -->");
alipayConfig.setPrivateKey(privateKey);
alipayConfig.setFormat("json");
alipayConfig.setAlipayPublicKey(alipayPublicKey);
alipayConfig.setCharset("UTF-8");
alipayConfig.setSignType("RSA2");
return alipayConfig;
}
}
```
### 重要入参说明
**注意**:请严格按照接口文档中的参数入参,传入非接口文档中的参数是无效的,并且可能会导致请求被拦截或其它异常。
| **请求参数** | **说明** |
| --- | --- |
| bill_type | 固定传入 trade。 |
| bill_date | 需要下载的账单日期,最晚是当期日期的前一天。 |
### 重要出参说明
| **请求参数** | **说明** |
| --- | --- |
| bill_download_url | 账单文件下载地址,有效时长:30 秒。 |
### 下载账单文件示例代码
```java
//将接口返回的对账单下载地址传入urlStr
String urlStr = "http://dwbillcenter.alipay.com/downloadBillFile.resource?bizType=X&userId=X&fileType=X&bizDates=X&downloadFileName=X&fileId=X";
//指定希望保存的文件路径
String filePath = "/Users/fund_bill_20160405.csv.zip";
URL url = null;
HttpURLConnection httpUrlConnection = null;
InputStream fis = null;
FileOutputStream fos = null;
try {
url = new URL(urlStr);
httpUrlConnection = (HttpURLConnection) url.openConnection();
httpUrlConnection.setConnectTimeout(5 * 1000);
httpUrlConnection.setDoInput(true);
httpUrlConnection.setDoOutput(true);
httpUrlConnection.setUseCaches(false);
httpUrlConnection.setRequestMethod("GET");
httpUrlConnection.setRequestProperty("CHARSET", "UTF-8");
httpUrlConnection.connect();
fis = httpUrlConnection.getInputStream();
byte[] temp = new byte[1024];
int b;
fos = new FileOutputStream(new File(filePath));
while ((b = fis.read(temp)) != -1) {
fos.write(temp, 0, b);
fos.flush();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(fis!=null) fis.close();
if(fos!=null) fos.close();
if(httpUrlConnection!=null) httpUrlConnection.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
```