退款
您可以通过本文了解 Antom 的退款规则及如何对成功的交易发起退款。
退款规则
退款的相关规则如下:
- 手续费:退款是否退回支付手续费,以及退款是否额外收费,依照双方合约执行。
- 退款结算汇率:当结算币种和支付币种不一致时,退款结算汇率按照发起退款请求当日 Antom 汇率进行结算。
- 退款限制:不同的支付方式存在不同的限制差异,具体包括以下几种情况:
- 不支持退款
- 不支持部分退款
- 从支付成功的时间起,超出一定时间后不允许退款
以上具体信息详见支持的支付方式。
- 退款返回:指在极端情况下,由于用户在银行侧的账户状态不正常等原因,导致发生调用 退款 接口后返回退款成功,但是用户未能成功收到资金的情况。此时,Antom 会结算相应的资金,并通过结算账单的方式发送通知,需要您自行决定如何处理这一笔资金。
退款方式
在支付成功后,您可以通过以下两种方法发起退款:
- 调用接口:您可以通过调用 退款 接口对成功支付的交易发起退款。
- 使用 Antom Dashboard 退款:关于如何发起退款并查看退款结果,请参阅退款。
退款流程
下图为退款流程图:
图 1. 退款流程图
注意:
- 调用 退款 接口后,可能返回以下三种情况:
- 退款通知:如果退款成功则一定会发送退款通知。在退款失败的情况下,如果是退款请求非法导致受理异常,则不会有退款通知。
退款步骤
根据以下步骤开始集成:
- 发起退款请求
- 获取退款结果
步骤 1:发起退款请求
根据支付方式的不同,调用接口退款时退款可能是同步或者是异步发生的,因此退款分为同步退款和异步退款两种逻辑:
- 同步退款:调用接口退款后,通常会直接响应退款成功或失败的状态。但不排除系统异常或支付渠道处理异常等小概率情况导致返回其他状态。
- 异步退款:调用接口退款后,响应退款处理中。需要您主动查询退款结果或等待退款结果通知来获取退款最终状态。
同步和异步退款所支持的支付方式信息如下:
同步退款 | 异步退款 |
电子钱包类型的支付方式 | 非同步退款支持的其它支付方式均为异步退款,所有支付方式请参考支持的支付方式。 |
收单机构为 2C2P HK 和 2C2P SG 时的 Mastercard 和 Visa 卡 |
同步和异步退款所支持的退款相关接口信息如下:
以下示例代码展示了如何调用 退款 接口:
public static void refund() {
AlipayRefundRequest alipayRefundRequest = new AlipayRefundRequest();
// 替换为您的 refundRequestId
String refundRequestId = UUID.randomUUID().toString();
alipayRefundRequest.setRefundRequestId(refundRequestId);
alipayRefundRequest.setPaymentId("20181129190741010007000000XXXX");
alipayRefundRequest.setRefundReason("demo refund");
// 设置退款金额
Amount amount = Amount.builder().currency("USD").value("1000").build();
alipayRefundRequest.setRefundAmount(amount);
AlipayRefundResponse alipayRefundResponse;
try {
alipayRefundResponse = CLIENT.execute(alipayRefundRequest);
} catch (AlipayApiException e) {
String errorMsg = e.getMessage();
// 处理错误情况
}
}
使用接口发起退款时若不满足相关退款要求,将收到 Antom 返回的对应错误码:
错误码 | 说明 |
| 支付未成功。 |
| 退款日期超出了退款有效期。 |
| 支付所使用的支付方式不支持取消交易或退款。 |
| 此交易不支持部分退款。 |
| 账户余额不足。 |
以下是发起 退款 请求的关键参数:
参数名称 | 是否必需 | 描述 |
refundRequestId | 是 | 商户端唯一的退款 ID。 |
paymentId | 是 | 该笔退款所对应的 Antom 分配的原始交易的 ID。 |
refundAmount | 是 | 退款金额。需要大于等于最小退款金额(通常为最小支付金额),且小于等于交易剩余可退金额。 退款金额的币种须和 支付 接口中的支付金额的币种(paymentAmount.currency)保持一致。 |
refundNotifyUrl | 否 | Antom 向您发送退款异步通知的地址。 |
以下是一个退款请求的示例代码:
{
"paymentId": "20181129190741010007000000XXXX",
"refundReason": "amsdemorefund",
"refundRequestId": "20181129190741020007000000XXXX",
"refundAmount": {
"currency": "USD",
"value": "1000"
}
}
以下代码展示了一个响应的示例,其中包含以下参数:
{
"result": {
"resultCode": "SUCCESS",
"resultStatus": "S",
"resultMessage": "Success"
},
"refundAmount": {
"value": "1000",
"currency": "USD"
},
"refundTime": "2020-10-10T12:01:01+08:30",
"paymentId": "20181129190741010007000000XXXX",
"refundRequestId": "20181129190741020007000000XXXX",
"refundId": "40181129190741020007000000XXXX"
}
响应中 result.resultStatus 字段的值代表该笔交易的退款状态,请您根据指引进行处理:
步骤 2:获取退款结果
Antom 会通过服务器交互将相应的退款结果发送给您,您可以通过以下方法之一获取退款结果:
- 接收来自 Antom 的异步通知
- 主动查询退款结果
接收退款通知
完成以下操作以接收来自 Antom 的 退款通知:
1. 设置接收通知的 webhook URL
您可以选择以下两种方法中的一种来设置接受通知的 webhook URL:
- 若您的每个订单都有单独的通知 URL,建议您在每笔请求中设置 webhook URL。您可以通过 退款 接口请求的 refundNotifyUrl 参数传入该笔订单的接收异步通知 URL。
- 若您的所有订单都有一个统一的通知 URL,您可以在 Antom Dashboard > 开发者 > 通知地址 中设置 webhook URL。具体操作请参阅通知地址。
以下是退款异步通知请求的代码示例:
{
"notifyType": "REFUND_RESULT",
"refundAmount": {
"currency": "USD",
"value": "100"
},
"refundId": "40181129190741020007000000XXXX",
"refundRequestId": "20181129190741020007000000XXXX",
"refundStatus": "SUCCESS",
"refundTime": "2020-10-10T12:01:01+08:30",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}
下表展示了退款异步通知请求中 result.resultStatus 可能返回的值,请您根据指引进行处理:
result.resultStatus | 信息 | 后续操作 |
| 退款成功。 | 无需进一步操作。 |
| 退款失败。 | 您可更换 refundRequestId 再次重试或联系 Antom 技术支持。 |
2. 异步通知验签
若您收到 Antom 的异步通知,需要您在返回中按照示例代码格式返回响应,但无需做加签处理。
您需要对 Antom 发送的退款通知进行验签。
/**
* receive notify
*
* @param request request
* @param notifyBody notify body
* @return Result
*/
@PostMapping("/receiveNotify")
@ResponseBody
public Result receiveNotify(HttpServletRequest request, @RequestBody String notifyBody) {
// 从 HTTP 请求中获取所需的参数
String requestUri = request.getRequestURI();
String requestMethod = request.getMethod();
// 从请求头中获取所需的参数
String requestTime = request.getHeader("request-time");
String clientId = request.getHeader("client-id");
String signature = request.getHeader("signature");
try {
// 对通知进行验签
boolean verifyResult = WebhookTool.checkSignature(requestUri, requestMethod, clientId,
requestTime, signature, notifyBody, ANTOM_PUBLIC_KEY);
if (!verifyResult) {
throw new RuntimeException("Invalid notify signature");
}
// 反序列化通知体
JSONObject jsonObject = JSON.parseObject(notifyBody);
String notifyType = (String)jsonObject.get("notifyType");
if("REFUND_RESULT".equals(notifyType)){
AlipayRefundNotify paymentNotify = jsonObject.toJavaObject(AlipayRefundNotify.class);
if (paymentNotify != null && "SUCCESS".equals(paymentNotify.getResult().getResultCode())) {
// 处理您自身的业务逻辑
// 例如,支付信息和买家之间的关系保存在数据库中
System.out.println("receive payment notify: " + JSON.toJSONString(paymentNotify));
return Result.builder().resultCode("SUCCESS").resultMessage("success.").resultStatus(ResultStatusType.S).build();
}
}
// 其他类型的通知
} catch (Exception e) {
// 处理错误情况
return Result.builder().resultCode("FAIL").resultMessage("fail.").resultStatus(ResultStatusType.F).build();
}
return Result.builder().resultCode("SYSTEM_ERROR").resultMessage("system error.").resultStatus(ResultStatusType.F).build();
}
无论订单是否退款成功,每个通知请求均需按以下固定格式响应:
{
"result": {
"resultCode": "SUCCESS",
"resultStatus": "S",
"resultMessage": "success"
}
}
查询退款结果
除了通过异步通知获取退款结果,您还可以调用 退款查询 接口主动查询退款结果,使用退款阶段中的 refundRequestId 查询退款状态。
以下代码展示了如何调用 退款查询 接口:
public static void inquiryRefund() {
AlipayInquiryRefundRequest alipayInquiryRefundRequest = new AlipayInquiryRefundRequest();
// 替换为您的 refundId
alipayInquiryRefundRequest.setRefundId("yourRefundId");
AlipayInquiryRefundResponse alipayInquiryRefundResponse = null;
try {
alipayInquiryRefundResponse = CLIENT.execute(alipayInquiryRefundRequest);
} catch (AlipayApiException e) {
String errorMsg = e.getMessage();
// 处理错误情况
}
}
以下代码展示了一个响应报文的示例:
{
"refundAmount": {
"currency": "USD",
"value": "1000"
},
"refundId": "40181129190741020007000000XXXX",
"refundRequestId": "20181129190741020007000000XXXX",
"refundStatus": "SUCCESS",
"refundTime": "2024-12-10T22:02:02-08:00",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}
下表展示了退款查询的响应中 refundStatus 字段可能返回的值,请您根据指引进行处理:
refundStatus | 信息 | 后续操作 |
| 退款成功。 | 无需进一步操作。 |
| 退款失败。 | 建议更换 refundRequestId 重试。如果问题未解决,联系 Antom 技术支持排查问题。 |
PROCESSING | 退款处理中。 | 建议继续查询,直到获取终态结果或收到退款异步通知。 |
常见问题
问:发起退款后会立即返回退款结果吗?
答:并非所有支付方式都可以同步返回终态退款结果,请以 退款通知 的异步通知结果为准。
问:退款成功后,买家多久能收到退款到账?
答:退款成功代表支付方式侧已受理买家的退款请求,资金到账的具体时间取决于支付方式侧。
问:卡支付订单在未发起请款前可以申请退款吗?
答:不可以,订单只有请款后才能发起退款请求。