Alipay, China's leading third-party online payment solutionAlipay, China's leading third-party online payment solution

银行卡支付(Web/WAP)

Antom SDK 是一个预构建的用户界面组件,用于收集银行卡信息并为您处理 3D 验证流程。集成此组件不需要您具有 PCI 认证,非常适合那些希望委托 Antom 来收集银行卡信息的用户。

用户体验

以下图表展示了在购物网站或移动网页应用上支付的用户流程:

Web 用户体验

下载.png

支付流程

以下流程说明了如何通过 Antom SDK 集成收银台支付:

WAP)-中@3x.png

  1. 用户进入结账页面。
  2. 创建支付会话请求。
    买家选择支付方式并提交订单后,您可以通过调用 支付会话创建(收银台)接口获取支付会话。
  3. 调用客户端SDK。
    在客户端,通过支付会话调用 SDK。SDK 会根据支付方式的特性处理信息收集、重定向、应用调用、二维码显示、验证等流程。
  4. 获取支付结果。
    通过以下两种方法之一获取支付结果:
  1. 获取请款结果。
    对于银行卡支付,通过以下两种方法之一获取请款结果:

集成步骤

通过以下步骤开始集成:

  1. 创建支付会话
  2. 创建并调用 SDK
  3. 获取支付结果
  4. 获取请款结果

步骤 1:创建支付会话 服务端

当买家选择 Antom 提供的支付方式时,您需要收集关键信息,如支付请求 ID、订单金额、支付方式、订单描述、支付重定向链接和支付结果通知链接,调用 支付会话创建(收银台)接口来创建支付会话,并将支付会话返回给客户端。

Antom 提供了多种语言的服务器端接口库。以下代码以 Java 为例,您需要安装 Java 6 或更高版本。

安装接口库

您可以在 GitHub 上找到最新版本。

copy
<dependency>
    <groupId>com.alipay.global.sdk</groupId>
    <artifactId>global-open-sdk-java</artifactId>
    <version>2.0.29</version>
</dependency>

初始化请求实例

创建一个单例资源来向Antom发起请求。

copy
import com.alipay.global.api.AlipayClient;
import com.alipay.global.api.DefaultAlipayClient;

import com.alipay.global.api.AlipayClient;
import com.alipay.global.api.DefaultAlipayClient;
import com.alipay.global.api.model.constants.EndPointConstants;

public class Sample {
    public static final String        CLIENT_ID            = "";
    public static final String        ANTOM_PUBLIC_KEY     = "";
    public static final String        MERCHANT_PRIVATE_KEY = "";

    private final static AlipayClient CLIENT               = new DefaultAlipayClient(
            EndPointConstants.SG, MERCHANT_PRIVATE_KEY, ANTOM_PUBLIC_KEY, CLIENT_ID);

}

创建支付会话

创建支付会话包括以下参数:

参数名称

是否必需

描述

productCode

值设置为 CASHIER_PAYMENT

paymentRequestId

由商户生成的专属 ID,每次发起支付时需使用新的 ID。

paymentAmount

支付金额,应根据订单使用币种的最小单位设置,例如,CNY 表示分,KRW 表示元。

paymentMethod

支付方式枚举

paymentRedirectUrl

根据服务器端结果的商户支付结果页面,不是一个固定的成功页面。

order

包括订单金额、订单 ID 和商户端订单描述的订单信息。

paymentNotifyUrl

支付结果通知地址,可以通过接口传递或通过门户设置为固定值。

settlementStrategy

支付的结算货币,如果商家签订了多个结算货币,需要在接口中指定。

以上参数是创建支付会话的基本参数,完整参数和特定支付方式的额外要求请参考 支付会话创建(收银台)

调用支付会话创建接口的示例代码

以下示例代码展示了如何调用 支付会话创建(收银台)接口:

copy
public static void createCardPaymentSession() {
    AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
    alipayPaymentSessionRequest.setProductCode(ProductCodeType.CASHIER_PAYMENT);

    // replace with your paymentRequestId
    String paymentRequestId = UUID.randomUUID().toString();
    alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);

    // set amount
    Amount amount = Amount.builder().currency("SGD").value("4200").build();
    alipayPaymentSessionRequest.setPaymentAmount(amount);

    // set paymentMethod
    PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType("CARD").build();
    alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);

    // set auth capture payment mode
    PaymentFactor paymentFactor = PaymentFactor.builder().isAuthorization(true).build();
    alipayPaymentSessionRequest.setPaymentFactor(paymentFactor);

    // replace with your orderId
    String orderId = UUID.randomUUID().toString();

    // set buyer info
    Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();

    // set order info
    Order order = Order.builder().referenceOrderId(orderId)
        .orderDescription("antom testing order").orderAmount(amount).buyer(buyer).build();
    alipayPaymentSessionRequest.setOrder(order);

    // replace with your notify url
    alipayPaymentSessionRequest.setPaymentNotifyUrl("https://www.yourNotifyUrl.com");

    // replace with your redirect url
    alipayPaymentSessionRequest.setPaymentRedirectUrl("https://www.yourMerchantWeb.com");

    AlipayPaymentSessionResponse alipayPaymentSessionResponse = null;
    try {
        alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
    } catch (AlipayApiException e) {
        String errorMsg = e.getMessage();
        // handle error condition
    }
}

以下代码显示了一个请求报文的示例:

copy
{
  "order": {
    "buyer": {
      "referenceBuyerId": "yourBuyerId"
    },
    "orderAmount": {
      "currency": "SGD",
      "value": "4200"
    },
    "orderDescription": "antom testing order",
    "referenceOrderId": "referenceOrderId01"
  },
  "paymentAmount": {
    "currency": "SGD",
    "value": "4200"
  },
  "paymentFactor": {
    "isAuthorization": true
  },
  "paymentMethod": {
    "paymentMethodType": "CARD"
  },
  "paymentNotifyUrl": "https://www.yourNotifyUrl.com",
  "paymentRedirectUrl": "https://www.yourMerchantWeb.com",
  "paymentRequestId": "paymentRequestId01",
  "productCode": "CASHIER_PAYMENT"
}

以下代码显示了一个响应的示例,其中包含以下参数:

  • paymentSessionData:需要返回给前端的支付会话数据。
  • paymentSessionExpiryTime:支付会话的过期时间。
copy
{
  "paymentSessionData": "UNvjVWnWPXJA4BgW+vfjsQj7PbOraafHY19X+6EqMz6Kvvmsdk+akdLvoShW5avHX8e8J15P8uNVEf/PcCMyXg==&&SG&&111",
  "paymentSessionExpiryTime": "2024-01-01T00:00:00+08:00",
  "paymentSessionId": "UNvjVWnWPXJA4BgW+vfjsQj7PbOraafHY19X+6EqMz6Ikyj9FPVUOpv+DjiIZqMe",
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": "success.",
    "resultStatus": "S"
  }
}

常见问题

问:请求参数的值可以使用中文字符吗?

答:为了避免特定支付方式的兼容性问题,请求中的字段请勿使用中文字符。

问:如何设置接收支付通知的链接?

答:在 支付会话创建(收银台)接口中指定 paymentNotifyUrl 字段,以接收支付结果的异步通知(支付通知),或者在 Antom Dashboard 中配置接收链接。如果请求和 Antom Dashboard 中都指定了链接,请求中的值优先。

步骤 2:创建并调用 SDK 客户端

SDK 是用于处理支付流程的组件。为了收集信息、根据 支付会话创建(收银台)接口中指定的支付方式在应用间切换,您需要通过创建支付会话来启动 SDK。

安装

在开始集成之前,请确保已完成以下环境准备:

  • 处理兼容性问题:为 Internet Explorer 和其他旧版浏览器提供相应的 Polyfills。建议在构建项目时使用 babel-preset-env 来解决浏览器兼容性问题。
  • 使用以下推荐的浏览器版本:
    • 移动浏览器:
      • iOS 11 及以上版本。
      • Android 5.0 及以上版本。
    • 对于计算机浏览器,请使用以下推荐版本:

image Edge

Last 2 versions

image Firefox

Last 2 versions

image Chrome

Last 2 versions

image Safari

Last 2 versions

image Opera

Last 2 versions

image Electron

Last 2 versions

请查阅 Web/WAP 端集成 SDK 资源包文档来集成 SDK 资源包。

初始化 SDK

使用 AMSCashierPayment 来创建 SDK 实例。配置对象包括以下参数:

参数名称

是否必需

描述

environment

用于传递环境信息。有效值包括:

  • sandbox:沙箱环境
  • prod:生产环境

locale

用于传递语言信息。有效值如下所示。您可以根据支付方式的地区选择要传递的值。如果传递其他值,默认使用本地语言:

  • en_US英语
  • pt_BR葡萄牙语
  • ko_KR韩语
  • es_ES西班牙语
  • ms_MY马来语
  • in_ID印尼语
  • tl_PH他加禄语
  • th_TH泰语
  • vi_VN越南语
  • fr_FR法语
  • nl_NL荷兰语
  • it_IT意大利语
  • de_DE德语
  • zh_CN简体中文
  • zh_HK繁体中文

analytics

用于配置和分析数据。包含以下值

  • enabled :可选的布尔属性。默认为 true,表示允许 SDK 上传和分析操作数据以提供更好的服务。如果不允许上传和分析数据,将其设置为 false

onLog

这是一个回调方法,用于生成 SDK 执行期间的日志错误信息和接口异常。

onEventCallback

一个回调函数,在 SDK 运行期间,当发生支付事件(如支付结果或表单提交错误)时,返回特定的事件代码。有关更多信息,请参阅 参考资料

以下示例代码展示了如何获取浏览器语言:

copy
let language = navigator.language || navigator.userLanguage;
language = language.replace("-", "_"); // Replace "-" with "_"

以下示例代码展示了如何实例化 SDK:

copy
// import { AMSCashierPayment } from '@alipay/ams-checkout'

const checkoutApp = new window.AMSCashierPayment({
  environment: "sandbox",
  locale: "en_US",
  onLog: ({code, message}) => {},
  onEventCallback: ({code, message}) => {},
});

调用 SDK

当买家在页面上选择支付方式后,您需要创建 SDK 并使用支付会话进行初始化。

使用实例对象中的 createComponentmountComponent 函数来创建支付组件:

参数名称

是否必需

描述

sessionData

使用 sessionData 参数创建配置对象:将通过 支付会话创建(收银台)接口在响应中获取的完整 paymentSessionData 参数传递给 sessionData 参数。

appearance

自定义外观主题配置,包含以下子参数:

  • showLoading :可选。布尔类型。默认值为 true,显示默认加载动画。如果不使用默认加载动画,需将此值指定为 false
  • showSubmitButton:可选。布尔类型。默认值为 false,禁用渲染支付页面的按钮。

notRedirectAfterComplete

默认值为 false,表示支付完成后会跳转回您的页面。值为空时也适用。 true 表示支付完成后不会跳转。您需要使用客户事件代码来控制银行绑卡以完成后续流程。请注意,客户端返回的支付结果码仅用作客户端页面跳转操作的参考。对于交易状态的更新,请参考服务器端 支付通知 支付结果查询 接口返回的结果。

merchantAppointParam

用于设置自定义功能,包含以下值:

  • storedCard :可选对象,用于设置存储卡的自定义功能。包含以下值:
    • needCVV :可选布尔值。默认值为 false,表示买家在支付过程中不需要输入 CVV 号码。值为空时也适用。值为true表示买家在支付过程中需要输入 CVV 号码。

嵌入式体验与弹窗体验

您可以通过弹窗或嵌入页面的方式在页面上显示 SDK。

嵌入式体验

弹窗体验

image.png

image.png

弹窗体验

弹窗体验的优势在于对页面样式影响较小,流程相对独立。

当买家在页面上选择支付方式并点击提交后,您需要调用 SDK 并弹出窗口。

copy
async function create(sessionData) {
  await checkoutApp.createComponent({ 
    sessionData: sessionData, 
    appearance:{
      showLoading: true, // Set as true by default to enable the default loading pattern
    },
    notRedirectAfterComplete: true,
  });
}
嵌入式体验

嵌入式体验将支付元素嵌入到指定视图中。您需要专注于支付列表的样式调整。嵌入内容的宽度会自动适应父容器,而高度会随着视图变化动态更新。

copy
async function create(sessionData) {
  await checkoutApp.mountComponent({ 
    sessionData: sessionData, 
    appearance:{
      showLoading: true, // Default is true, allowing configuration of whether to display a loading animation.
      showSubmitButton: false, // Configure whether the payment button is rendered by the component.
    }, 
    notRedirectAfterComplete: true,
  },'#ContainerNodeId');
}
嵌入式提交支付

在使用嵌入式体验和自定义提交按钮时, 请记得主动调用提交函数来启动提交过程。

copy
// Execute when the buyer completes the form and clicks the submit button.
checkoutApp.submit().then(({code, message})=>{})
销毁组件

在以下情况下,调用 unmount 方法来释放 SDK 组件资源:

  • 当买家切换视图离开结账页面时,释放 支付会话创建(收银台)中创建的组件资源。
  • 当买家发起多次支付时,释放之前 支付会话创建(收银台)中创建的组件资源。
  • 当买家完成支付并设置 notRedirectAfterCompletetrue 时,在获取特定支付结果代码后释放组件资源。
copy
// Free SDK component resources
checkoutApp.unmount();

常见问题

问:遇到 SDK_CREATEPAYMENT_PARAMETER_ERROR 时该怎么办?

答:收到此事件代码时,请检查传递的 sessionData 是否正确且完整。

问:遇到 SDK_PAYMENT_ERROR 或渲染视图错误时该怎么办?

答:检查接口初始化时的网络请求是否出现异常,如网络超时。确保创建支付会话请求的环境与 SDK 实例化时的环境一致。检查 支付会话创建(收银台)接口中的参数传递是否正确。如果接口异常持续存在,请联系我们进行进一步的故障排除。

问:遇到 SDK_FORM_VERIFICATION_FAILED 时该怎么办?

答:可能是因为买家没有填写所有必填项。提交时,可能会返回表示表单验证失败的错误代码。建议引导买家完善表单内容。

显示支付结果

如果设置 notRedirectAfterCompletefalse ,买家在完成支付后将被重定向到您在 支付会话创建(收银台)接口中提供的 paymentRedirectUrl 。您可以在该链接中主动查询支付结果并展示给买家。

如果 notRedirectAfterCompletetrue ,支付结果将通过 onEventCallback 函数给出。这里的支付结果仅用于前端显示,最终订单状态以服务器端为准。

您需要通过 onEventCallback结果中的数据自定义每个支付结果的处理流程。

下列是 onEventCallback的支付结果可能的事件代码:

事件代码

消息

解决方案

SDK_PAYMENT_SUCCESSFUL

支付成功。

建议将买家重定向到支付结果页面。

SDK_PAYMENT_PROCESSING

支付正在处理中。

建议您检查在onEventCallback结果数据中 paymentResultCode 的值以获取详细信息。根据提供的信息,引导买家重新尝试支付。

SDK_PAYMENT_FAIL

支付失败。

建议您检查在onEventCallback结果数据中 paymentResultCode 的值以获取详细信息。根据提供的信息,引导买家重新尝试支付。

SDK_PAYMENT_CANCEL

买家在未提交订单的情况下退出了支付页面。

在有效期内,可以使用 paymentSessionData 重新调用SDK;如果已过期,需要重新请求paymentSessionData

SDK_PAYMENT_ERROR

支付状态异常。

建议您检查在onEventCallback结果数据中 paymentResultCode 的值以获取详细信息。根据提供的信息,引导买家重新尝试支付。

以下示例代码展示了如何处理 回调函数 onEventCallback

copy
function onEventCallback({ code, result }) {
  switch (code) {
    case 'SDK_PAYMENT_SUCCESSFUL':
      // Payment was successful. Redirect buyers to the payment result page.
      break;
    case 'SDK_PAYMENT_PROCESSING':
      console.log('Check the payment result data', result);
      // Payment was being processed. Guide buyers to retry the payment based on the provided information.
      break;
    case 'SDK_PAYMENT_FAIL':
      console.log('Check the payment result data', result);
      // Payment failed. Guide buyers to retry the payment based on the provided information.
      break;
    case 'SDK_PAYMENT_CANCEL':
      // Guide buyers to retry the payment.
      break;
    case 'SDK_PAYMENT_ERROR':
      console.log('Check the payment result data', result);
      // The payment status was abnormal. Guide buyers to retry the payment based on the provided information.
      break;
    default:
      break;
  }
}

步骤 3:获取支付结果 服务端

在买家完成支付或支付超时后,Antom 会通过服务器交互将相应的支付结果发送给您,您可以通过以下方式之一获取支付结果:

  • 接收异步通知
  • 查询结果

接收异步通知

当支付成功或失败时,Antom会向您在 支付会话创建(收银台)接口的 paymentNotifyUrl 参数中指定的地址发送异步通知(支付通知)。收到 Antom 的通知后,您需要按照返回收到确认信息返回响应。

Antom允许您在 支付会话创建(收银台)接口的 paymentNotifyUrl 参数中指定链接。如果每个支付的地址相同,您也可以在 Antom Dashboard 中配置该地址。

以下代码展示了通知请求的示例:

copy
{
  "actualPaymentAmount": {
    "currency": "SGD",
    "value": "4200"
  },
  "cardInfo": {
    "avsResultRaw": "A",
    "cardBrand": "MASTERCARD",
    "cardNo": "****************",
    "cvvResultRaw": "Y",
    "funding": "DEBIT",
    "issuingCountry": "US",
    "networkTransactionId": "XXXXX",
    "paymentMethodRegion": "GLOBAL",
    "threeDSResult": {
      "cavv": "",
      "eci": ""
    }
  },
  "notifyType": "PAYMENT_RESULT",
  "paymentAmount": {
    "currency": "SGD",
    "value": "4200"
  },
  "paymentCreateTime": "2024-01-01T00:00:00+08:00",
  "paymentId": "20240101123456789XXXX",
  "paymentRequestId": "paymentRequestId01",
  "paymentResultInfo": {
    "avsResultRaw": "A",
    "cardBrand": "MASTERCARD",
    "cardNo": "****************",
    "cvvResultRaw": "Y",
    "funding": "DEBIT",
    "issuingCountry": "US",
    "networkTransactionId": "XXXXX",
    "paymentMethodRegion": "GLOBAL",
    "threeDSResult": {
      "cavv": "",
      "eci": ""
    }
  },
  "paymentTime": "2024-01-01T00:01:00+08:00",
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": "success.",
    "resultStatus": "S"
  }
}

如何验证通知的签名并做出响应,请参阅签名与验签

常见问题

问:何时会发送通知?

答:这取决于支付是否完成:

  • 如果支付成功完成,Antom 通常会在 3 到 5 秒内发送异步通知。对于像 OTC 这样的支付方式,通知可能会稍有延迟。
  • 如果支付未完成,Antom 需要先关闭订单,然后发送异步通知。不同支付方式关闭订单所需的时间会有所不同,通常默认为 14 分钟。

问:异步通知会被重新发送吗?

答:是的,对于以下情况,异步通知会在 24 小时内自动重新发送:

  • 如果由于网络原因未收到异步通知。
  • 如果您收到来自的异步通知,但您没有按照处理通知的示例代码格式对通知做出响应。

通知可以重发最多 8 次,或者直到收到正确的响应以终止传递。发送间隔如下:0 分钟,2 分钟,10 分钟,10 分钟,1 小时,2 小时,6 小时,15 小时。

问:在响应异步通知时,我需要添加数字签名吗?

答:如果您收到来自 Antom 的异步通知,您需要按照处理通知的示例代码格式返回响应,但不需要对响应进行签名。

问:我在通知中需要使用哪些关键参数?

答:请注意以下关键参数:

  • result :表示订单的支付结果。
  • paymentRequestId :用于咨询、取消和对账的支付请求 ID。
  • paymentId :表示由Antom生成的支付订单 ID,用于退款和对账。
  • paymentAmount :表示支付金额。

查询结果

您可以调用 支付结果查询 接口来发起对订单结果的查询。

参数名称

是否必需

描述

paymentRequestId

商户生成的支付请求 ID。

完整的参数集,请参考 支付结果查询 接口文档,获取全部参数及特定支付方式的额外要求。

以下示例代码展示了如何调用 支付结果查询 接口:

copy
public static void inquiryPayment() {
    AlipayPayQueryRequest alipayPayQueryRequest = new AlipayPayQueryRequest();

    // replace with your paymentRequestId
    alipayPayQueryRequest.setPaymentRequestId("yourPaymentRequestId");

    AlipayPayQueryResponse alipayPayQueryResponse = null;
    try {
        alipayPayQueryResponse = CLIENT.execute(alipayPayQueryRequest);
    } catch (AlipayApiException e) {
        String errorMsg = e.getMessage();
        // handle error condition
    }
}

以下代码展示了请求报文的示例:

copy
{
  "paymentRequestId": "paymentRequestId01"
}

以下代码展示了响应报文的示例:

copy
{
  "authExpiryTime": "2024-01-08T00:01:00+08:00",
  "cardInfo": {
    "cardBrand": "MASTERCARD",
    "funding": "DEBIT",
    "issuingCountry": "US"
  },
  "paymentAmount": {
    "currency": "SGD",
    "value": "4200"
  },
  "paymentId": "20240101123456789XXXX",
  "paymentMethodType": "CARD",
  "paymentRedirectUrl": "https://www.yourMerchantWeb.com",
  "paymentRequestId": "paymentRequestId01",
  "paymentResultCode": "SUCCESS",
  "paymentResultInfo": {
    "avsResultRaw": "A",
    "cardBrand": "MASTERCARD",
    "cardNo": "****************",
    "cvvResultRaw": "Y",
    "funding": "DEBIT",
    "issuingCountry": "US",
    "networkTransactionId": "networkTransIdXXXX",
    "paymentMethodRegion": "GLOBAL",
    "threeDSResult": {
      "cavv": "",
      "eci": ""
    }
  },
  "paymentResultMessage": "success",
  "paymentStatus": "SUCCESS",
  "paymentTime": "2024-01-01T00:01:00+08:00",
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": "success.",
    "resultStatus": "S"
  }
}

常见问题

问:我应该多久调用一次 支付结果查询 接口?

答:以 2 秒的间隔持续调用 支付结果查询 接口,直到获取最终的支付结果或收到异步支付结果通知为止。

问:我在通知中需要使用哪些关键参数?

答:请注意以下关键参数:

  • result:表示此 支付结果查询 接口调用的结果,需要根据 paymentStatus 来判断订单状态:
    • SUCCESSFAIL表示最终结果。
    • PROCESSING表示处理中。
  • paymentAmount :表示支付的金额。

步骤 4:获取请款结果 服务端

在买家完成请款或请款超时后,Antom 会通过服务器交互将相应的请款结果发送给您,您可以通过以下方法之一获取请款结果:

  • 接收异步通知
  • 查询结果

接收异步通知

请款成功或失败时,Antom 会向您在 支付会话创建(收银台)接口的 paymentNotifyUrl 参数中指定的地址发送异步通知(支付通知)。收到 Antom 的通知后,您需要按照返回收到确认信息返回响应。

Antom允许您在 支付会话创建(收银台)接口的 paymentNotifyUrl 参数中指定链接。如果每个支付的地址相同,您也可以在 Antom Dashboard 中配置该地址。

以下代码显示了成功的请款示例:

copy
{
  "captureAmount": {
    "currency": "SGD",
    "value": "4200"
  },
  "notifyType": "CAPTURE_RESULT",
  "captureId": "20240101987654321XXXX",
  "captureRequestId": "captureRequestId01",
  "captureTime": "2024-01-01T00:00:02+08:00",
  "paymentId": "20240101123456789XXXX",
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": "success.",
    "resultStatus": "S"
  }
}

以下代码展示了请款失败的示例:

copy
{
  "captureAmount": {
    "currency": "SGD",
    "value": "4200"
  },
  "notifyType": "CAPTURE_RESULT",
  "captureId": "20240101123456789XXXX",
  "captureRequestId": "captureRequestId01",
  "captureTime": "2024-01-01T00:00:02+08:00",
  "paymentId": "20240101123456789XXXX",
  "result": {
    "resultCode": "PROCESS_FAIL",
    "resultMessage": "fail.",
    "resultStatus": "F"
  }
}

如何验证通知的签名并做出响应,请参阅签名与验签

常见问题

问:异步通知会被重新发送吗?

答:是的,对于以下情况,异步通知将在 24 小时内自动重新发送:

  • 如果您因网络原因未收到异步通知。
  • 如果您收到来自 Antom 的异步通知,但您没有按照处理通知的示例代码格式进行响应。

通知最多可以重发 8 次,或者直到收到正确的响应以终止发送。发送间隔为:0 分钟,2 分钟,10 分钟,10 分钟,1 小时,2 小时,6 小时和 15 小时。

问:在响应异步通知时,我需要添加数字签名吗?

答:如果您收到来自 Antom 的异步通知,您需要按照处理通知的示例代码格式返回响应,但不需要对响应进行签名。

问:我需要使用通知中的哪些关键参数?

答:请注意以下关键参数:

  • result :表示订单的请款结果。
  • notifyType :通知类型为 CAPTURE_RESULT
  • paymentRequestId :您生成的支付请求 ID,用于查询、取消和对账。
  • paymentIdAntom 生成的支付订单 ID,用于退款和对账。
  • acquirerReferenceNo :集成新加坡和香港内银行卡支付服务的商户将在通知中收到特定的收单机构 ID。

查询结果

您可以调用 支付结果查询 接口来发起对订单结果的查询。

参数名称

是否必需

描述

paymentRequestId

商户生成的支付请求 ID

有关完整参数集,请参阅 支付结果查询 接口,获取完整的参数列表以及某些支付方式的额外要求。

以下示例代码展示了如何调用 支付结果查询 接口:

copy
public static void inquiryPayment() {
    AlipayPayQueryRequest alipayPayQueryRequest = new AlipayPayQueryRequest();

    // replace with your paymentRequestId
    alipayPayQueryRequest.setPaymentRequestId("yourPaymentRequestId");

    AlipayPayQueryResponse alipayPayQueryResponse = null;
    try {
        alipayPayQueryResponse = CLIENT.execute(alipayPayQueryRequest);
    } catch (AlipayApiException e) {
        String errorMsg = e.getMessage();
        // handle error condition
    }
}

以下是请求报文的示例:

copy
{
  "paymentRequestId": "paymentRequestId01"
}

请款状态的值

接口响应中的 transactions 字段值表示请款状态:

参数名称

描述

transactions.transactionType

值为 CAPTURE,表示 请款状态。

transactions.transactionResult

请款状态。

以下代码展示了成功的请款示例:

copy
{
  "transactions": [
    {
      "transactionType": "CAPTURE",
      "transactionStatus": "SUCCESS",
      "transactionRequestId": "captureRequestId01",
      "transactionAmount": {
        "currency": "SGD",
        "value": "4200"
      },
      "transactionTime": "2024-01-01T00:00:02+08:00",
      "transactionId": "20240101123456789XXXX",
      "transactionResult": {
        "resultStatus": "S",
        "resultCode": "SUCCESS",
        "resultMessage": "success"
      }
    }
  ]
}

以下代码展示了失败的请款示例:

copy
{
  "transactions": [
    {
      "transactionType": "CAPTURE",
      "transactionStatus": "SUCCESS",
      "transactionRequestId": "captureRequestId01",
      "transactionAmount": {
        "currency": "SGD",
        "value": "4200"
      },
      "transactionTime": "2024-01-01T00:00:02+08:00",
      "transactionId": "20240101123456789XXXX",
      "transactionResult": {
        "resultStatus": "F",
        "resultCode": "PROCESS_FAIL",
        "resultMessage": "General business failure. No retry."
      }
    }
  ]
}

以下代码展示了处理中的请款示例:

copy
{
  "transactions": [
    {
      "transactionType": "CAPTURE",
      "transactionStatus": "SUCCESS",
      "transactionRequestId": "captureRequestId01",
      "transactionAmount": {
        "currency": "SGD",
        "value": "4200"
      },
      "transactionTime": "2024-01-01T00:00:02+08:00",
      "transactionId": "20240101123456789XXXX",
      "transactionResult": {
        "resultStatus": "U",
        "resultCode": "PAYMENT_IN_PROCESS",
        "resultMessage": "payment in process"
      }
    }
  ]
}

常见问题

问:我应该多久调用一次 支付结果查询 接口?

答:以 2 秒的间隔持续调用 支付结果查询 接口,直到获取最终的支付结果或收到异步支付结果通知。

示例代码

前端完整示例代码:

copy
// Step 1: Instantiate the SDK and handle the callback event.
const onEventCallback = function({ code, result }) {
  switch (code) {
    case 'SDK_PAYMENT_SUCCESSFUL':
      // Payment was successful. Redirect buyers to the payment result page.
      break;
    case 'SDK_PAYMENT_PROCESSING':
      console.log('Check the payment result data', result);
      // Payment was being processed. Guide buyers to retry the payment based on the provided information.
      break;
    case 'SDK_PAYMENT_FAIL':
      console.log('Check the payment result data', result);
      // Payment failed. Guide buyers to retry the payment based on the provided information.
      break;
    case 'SDK_PAYMENT_CANCEL':
      // Guide buyers to retry the payment.
      break;
    case 'SDK_PAYMENT_ERROR':
      console.log('Check the payment result data', result);
      // The payment status was abnormal. Guide buyers to retry the payment based on the provided information.
      break;
    case 'SDK_END_OF_LOADING':
      // End your custom loading animation.
      break;
    default:
      break;
  }
}
const checkoutApp = new window.AMSCashierPayment({
  environment: "sandbox",
  locale: "en_US",
  onLog: ({code, message}) => {},
  onEventCallback: onEventCallback,
});
// Handle payment button events.
document
  .querySelector("#your form id")
  .addEventListener("submit", handleSubmit);

async function handleSubmit() {
  // Step 2: The server calls createPaymentSession API to obtain paymentSessionData.
  async function getPaymentSessionData() {
    const url = "Fill in the server address";
    const config = {
      // Fill in the request configuration.
    };
    const response = await fetch(url, config);
    // Obtain the value of the paymentSessionData parameter in the response.
    const { paymentSessionData } = await response.json();
    return paymentSessionData;
  }
  const paymentSessionData = await getPaymentSessionData();

  // Step 3: Create rendering components.
  await checkoutApp.createComponent({ 
    sessionData: paymentSessionData, 
    appearance:{
      showLoading: true, // Set as true by default to enable the default loading pattern.
    }, 
  });
}

自定义加载动画示例代码:

银行卡支付场景支持配置自定义加载动画:

  1. 在渲染组件时,将 showLoading 设置为 false
  2. 在调用 createComponent 函数时,在当前页面渲染自定义加载动画。
  3. 监听 onEventCallback 事件。
    1. 当收到事件代码 SDK_START_OF_LOADING 时,显示自定义加载动画。
    2. 当收到事件代码 SDK_END_OF_LOADING 时,结束自定义加载动画。
copy
async function create(sessionData) {
  await checkoutApp.createComponent({ 
    sessionData: sessionData, 
    appearance:{
      showLoading: false, // Default is true to allow the configuration whether to display a loading animation.
    }, 
  });
}

AVS 验证的示例代码:

为 AVS 验证传递预先收集的账单地址信息。

参数名称

是否必需

描述

billingAddress

如果您需要预先收集的账单地址信息以进行 AVS 验证,可以通过 submit 方法传递以下参数。

  • billingAddress:可选对象。账单地址信息用于识别和定位付款人。它包含以下参数:
    • region :必填。字符串 (2)。 ISO 3166 标准的二位字母的国家代码。
    • state :可选。字符串 (8)。州、国家或省的名称。
    • city :可选。字符串 (32)。城市、地区、郊区、城镇或村庄的名称。
    • address1 :可选。字符串 (256)。 地址行 1,例如街道地址、邮政信箱和公司名称。
    • address2 :可选。字符串 (256)。 地址行 2,例如公寓、套房、单元和建筑信息。
    • zipCode :可选。字符串 (32)。 邮政编码。
copy
// The buyer enters the address information and stores it in the billingAddress object for subsequent submissions
const billingAddress = {
  region: '',
  address1: '',
  address2: '',
  city: '',
  state: '',
  zipCode: ''
}

// Execute when the buyer completes the form and clicks the submit button.
checkoutApp.submit({billingAddress}).then(({code, message})=>{})

事件代码

您可能会看到两种类型的事件代码:

  • 状态代码:由组件运行时生命周期中的 onEventCallback 返回。
  • 错误代码:由 onEventCallback 或 onError 在组件初始化阶段返回。

类型

代码

描述

后续操作

状态代码

SDK_START_OF_LOADING

在创建支付组件时开始播放加载动画。

无需进一步操作。

SDK_END_OF_LOADING

在创建支付组件时加载动画结束。

无需进一步操作。

错误代码

SDK_INTERNAL_ERROR

SDK 内部错误发生。

请联系 Antom 技术支持解决此问题。

SDK_CREATEPAYMENT_PARAMETER_ERROR

传递给 AMSCashierPayment 方法的参数不正确。

确保参数传递正确,然后发送新请求。

SDK_INIT_PARAMETER_ERROR

传递给 createComponent 方法的参数不正确。

确保参数传递正确,然后发送新请求。

SDK_CREATECOMPONENT_ERROR

在调用 createComponent 方法时发生异常。

请联系 Antom 技术支持解决此问题。

SDK_CALL_URL_ERROR

支付方式客户端撤销失败。

请联系 Antom 技术支持解决此问题。