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

SDK

回调数据

回调函数可以返回各种类型的数据或值,例如事件代码和支付相关信息。这部分将介绍通过回调函数返回的事件代码、银行卡支付信息和风险控制详情。

事件代码

事件代码通过不同的回调函数在不同时间返回,主要包括以下三种类型:

  • 状态代码
  • 错误代码
  • 支付结果代码

状态代码

在组件运行周期中通过 onEventCallback 方法返回,并根据特定事件进行后续处理。

  • SDK_START_OF_LOADING : 组件创建时开始显示加载动画。当配置为隐藏加载动画并使用自定义动画时,则此时渲染自定义动画。
  • SDK_END_OF_LOADING : 组件创建时加载动画结束。当配置为隐藏加载并使用自定义动画时,此时可以隐藏动画。
  • SDK_CALL_URL_ERROR : 该事件代码在事件信息中代表以下情况之一:
    • 跳转到商户页面失败。
    • 跳转到 3D 验证页面失败。
    • 在调用 支付会话创建(收银台) 请求时, 参数 paymentRedirectUrl 没有指定或指定错误。

在 Web 或 WAP 场景中,重定向链接通常没有异常,建议您验证跳转链接。在应用场景下,如果此异常频繁出现,请联系 Antom 技术支持以解决重定向或调用问题。

  • SDK_CALL_URL_SUCCESS : 商户页面加载成功。
  • SDK_DUPLICATE_SUBMISSION_BEHAVIOR : 表单重复提交。商户可以通过提示信息告知用户,无需重复点击提交。
  • SDK_FORM_VERIFICATION_FAILED : 表单提交后验证失败。SDK 将在信息收集页面显示表单错误代码,允许用户重新提交支付。
  • SDK_PAYMENT_AUTHORIZATION_SUCCESSFUL : 支付流程完成。如果已配置支付后不重定向的方法,建议继续监听对应的支付事件代码以处理后续流程。否则,此事件代码可以忽略,直接跳转到支付结果页面。
  • SDK_PAYMENT_CHALLENGE : 触发 3D 验证,发卡行需要与买家进一步交互才能验证支付。无需处理,SDK 会自动重定向到验证页面。

错误代码

在组件初始化阶段通过 onEventCallback onError 方法返回,并根据特定事件进行后续处理。

  • SDK_INTERNAL_ERROR: SDK 内部错误。请联系 Antom 技术支持。
  • SDK_CREATEPAYMENT_PARAMETER_ERROR: mountComponent 方法指定的参数异常。请检查参数是否正确,并重新初始化组件。
  • SDK_INIT_PARAMETER_ERROR: AMSCashierPayment 方法指定的参数异常。请检查参数是否正确,并重新实例化 SDK。
  • SDK_CREATECOMPONENT_ERROR: 组件初始化异常。请联系 Antom 技术支持。
  • SDK_SUBMIT_NETWORK_ERROR : 网络原因导致接口调用失败。这可能发生在submit方法提交时。请尝试再次提交。

支付结果代码

在支付过程结束时通过 onEventCallback 方法返回,并根据特定事件进行后续处理。

  • SDK_PAYMENT_SUCCESSFUL : 支付成功。首次支付时买家需手动取消 SDK,银行卡令牌支付模式下 SDK会自动关闭。建议跳转到支付结果页面。
  • SDK_PAYMENT_PROCESSING : 支付处理中。建议您的服务器检查支付状态或等待支付结果通知。
  • SDK_PAYMENT_FAIL : 支付失败。建议您根据 paymentResultCode 错误代码提示,引导用户重新支付。
  • SDK_PAYMENT_ERROR : 支付状态异常。建议您的服务器检查支付状态或等待支付结果通知。

支付失败或异常状态描述

下表提供了支付失败或支付状态异常时的支付结果代码及相应的处理建议。根据接收到的支付结果代码,您可以采取进一步的行动。

paymentResultCode

paymentResultMessage

建议

ACCESS_DENIED

访问被拒绝。

权限不足。请联系 Antom 技术支持以了解具体原因。

CURRENCY_NOT_SUPPORT

不支持该货币。

不支持的货币。请联系 Antom 技术支持以了解具体原因。

FRAUD_REJECT

交易因风险控制无法继续处理。如果用户已支付交易,交易将被退款。

欺诈拒绝。如果出现以下情况,请联系技术支持:

  • 需要申诉。
  • 买家在两周内未收到退款。

INVALID_CARD

银行卡无效。可能是信用卡号无法识别,银行卡没有对应的发卡行,或者卡号格式错误。

无效银行卡。建议更换银行卡并重试。

INVALID_EXPIRY_DATE_FORMAT

expiryYear 或者 expiryMonth 格式错误。

银行卡有效期错误。建议检查填写的银行卡有效期。

ISSUER_REJECTS_TRANSACTION

发卡行拒绝交易。

发卡行拒绝。建议换张银行卡重新尝试或者联系发卡行。

INVALID_MERCHANT_STATUS

限制导致的商户状态异常。

商户状态异常。请联系 Antom 技术支持以获取具体原因。

MERCHANT_KYB_NOT_QUALIFIED

商户的 KYB 状态导致支付失败。商户未完成 KYB 合规,或 KYB 状态不适用于此交易。

请联系 Antom 技术支持以获取具体原因。

NO_PAY_OPTIONS

交易不支持该币种。

币种不受支持。请检查支付方式是否支持该币种,或者支付方式和币种是否与合同一致。如有问题,请联系 Antom 技术支持以获取具体原因。

ORDER_IS_CLOSED

您发起的请求具有与已关闭交易相同 的 paymentRequestId。

订单已关闭。请发起新的请求并重试。

PAYMENT_AMOUNT_EXCEED_LIMIT

支付金额超过了合同或支付方式允许的最大金额。

金额超出限制。请检查支付金额是否超出限制,或尝试使用较低的金额重试。请联系 Antom 技术支持获取具体的支付限额信息。

PAYMENT_COUNT_EXCEED_LIMIT

支付次数超过了支付方式规定的最大限制。

使用次数超出限制。请联系 Antom 技术支持获取具体的支付限额信息。

PAYMENT_NOT_QUALIFIED

商户未达到支付条件,可能是因为未注册、未签约代扣协议或被禁止支付。

商户无权限。具体原因请联系 Antom 技术支持。

PROCESS_FAIL

发生常见的业务失败。

支付失败。获取 Antom 技术支持前请勿重试。

RISK_REJECT

由于风险控制,交易无法进一步处理。如果用户已为交易付款,交易将被退款。

风险控制拒绝。如果买家在两周内未收到退款,请联系 Antom 技术支持。

SUSPECTED_CARD

怀疑银行卡存在欺诈行为,例如银行卡被盗或受限。

风险控制拒绝。建议更换银行卡重试或联系发卡行。

SUSPECTED_RISK

由于疑似安全问题,交易无法进一步处理。您可以在工作日后一天重试交易。如果交易不安全且用户已付款,交易将被退款。

风险控制拒绝。如果出现以下情况,请联系技术支持:

  • 需要申诉。
  • 买家在两周内未收到退款。

USER_AMOUNT_EXCEED_LIMIT

支付金额超过了用户的支付限额。

金额超过限制。请用小于或等于您账户中的可用余额的金额重新发起支付,或联系 Antom 技术支持。

USER_BALANCE_NOT_ENOUGH

用户在相应支付方式中的余额不足,无法完成支付。

用户余额不足,请充值或选择其他支付方式。

USER_KYC_NOT_QUALIFIED

由于用户的 KYC 状态,支付失败。用户可能未完成 KYC 认证,或者 KYC 状态不满足此交易要求(例如,支付金额或产品信息的限制)。

请用户先完成 KYC 认证。

USER_PAYMENT_VERIFICATION_FAILED

用户在支付方被限制支付。

用户未完成验证,具体原因请联系 Antom 技术支持。

USER_STATUS_ABNORMAL

支付方式端的用户状态异常。

用户状态异常,具体原因请联系 Antom 技术支持。

PAYMENT_IN_PROCESS

支付正在处理中。

支付处理中。

UNKNOWN_EXCEPTION

由于未知原因,接口调用失败。

未知异常,具体原因请联系 Anotm 技术支持。

CARD_NOT_SUPPORTED

用于交易的银行卡不支持。

银行卡不支持,请更换银行卡后重试。

INVALID_EXPIRATION_DATE

支付方式 的 paymentMethodMetaData.expiryYear 或 paymentMethodMetaData.expiryDate 值无效。

银行卡的有效期不正确。建议检查银行卡的有效期是否填写正确。

INVALID_CARD_NUMBER

用于交易的银行卡号无效。

银行卡号不正确。建议更换银行卡并重试。如果重试后仍有问题,请联系 Antom 技术支持以获取具体原因。

银行卡支付

在银行卡支付的情况下,一旦支付处理达到成功或失败的最终状态,您将在调用onEventCallback函数后在响应中收到 cardPaymentResultInfo 参数。请参阅下表以了解 cardPaymentResultInfo 的子参数:

注意: 如果支付流程完成,用户被重定向到跳转链接,您将不会收到参数 cardPaymentResultInfo

参数

描述

cardNo

可选 字符串 (32 个字符)

部分显示的卡号,可用于向用户展示。

支付会话创建(收银台) 接口中的 paymentMethodType 的值为 CARD 且商户没有 PCI 资质时,此参数返回。

cardBrand

可选 字符串 (256)

银行卡品牌,可用于向用户显示。

支付会话创建(收银台) 接口中的 paymentMethodType 的值为 CARD 时返回此参数。

cardBin

可选 字符串 (32)

卡号的前六位数字。

lastFour

可选 字符串 (4)

卡号的最后四位数字。

issuerName

可选 字符串 (256)

银行卡卡的发卡银行。

发行国家

可选 字符串 (2 字符)

银行卡的发行国家。此参数的值遵循 ISO 3166 国家代码标准的二位字母国家代码。

支付会话创建(收银台) 接口中的 paymentMethodType 的值为 CARD 时,返回此参数。

资金来源

可选 字符串(32个字符)

银行卡的资助类型。有效值包括:

  • CREDIT:表示信用卡。
  • DEBIT:表示借记卡。
  • PREPAID:表示预付费卡。
  • CHARGE:表示充值卡。
  • DEFERRED_DEBIT:表示延期借记卡。

当以下所有条件满足时,返回此参数:

  • 支付方式类型 paymentMethodType 的值为CARD
  • 卡号 cardNo 是有效的。
  • 信息可在 Antom 的卡数据库中查到。

avsResultRaw

可选 字符串 (128 个字符)

原始的 AVS 结果。请参阅 AVS 结果代码以检查有效值。

当发卡行将此信息传递给 Antom 时,此参数将返回。

cvvResultRaw

可选 字符串 (128)

原始的卡验证值(CVV),卡安全码(CSC)或卡验证代码(CVC)结果。参见 CVV 结果代码 以检查有效值。

当发卡行将此信息传递给 Antom 时,此参数将返回。

holdName

可选 字符串 (32)

持卡人姓名。

指纹

可选 字符串(256个字符)

此特定的卡号的指纹 ID。您可以使用此属性来检查两个注册了您的服务的客户是否使用了相同的卡号。

过期月份

可选 字符串 (2 位)

银行卡的过期月份。输入两位数字表示月份。例如,如果过期月份是二月,此参数的值为 02

当以下所有条件满足时,此参数返回:

  • 您已获得 PCI 资格。
  • paymentMethodType 的值为 CARD
  • Antom 银行卡数据库中有可用信息。

过期年份

可选 字符串 (2 位)

银行卡的过期年份。输入年份的最后两位数字。例如,如果过期年份是 2025,此参数的值为 25

当以下所有条件满足时,此参数返回:

  • 您已获得 PCI 资格。
  • paymentMethodType 的值为 CARD
  • Antom 卡数据库中提供了此信息。

返回的银行卡信息示例代码:

copy
{
    "result": {
        "resultCode": "SUCCESS",
        "resultStatus": "S",
        "resultMessage": "Success"
    },
    "paymentStatus": "SUCCESS",
    "paymentResultCode": "SUCCESS",
    "paymentResultMessage": "success",
    "cardPaymentResultInfo": {
        "avsResultRaw": "4",
        "cardBin": "409280",
        "cardBrand": "VISA",
        "cardNo": "************8888",
        "cvvResultRaw": "1",
        "expiryMonth": "02",
        "expiryYear": "27",
        "fingerprint": "",
        "funding": "DEBIT",
        "holdName": "Tom Jay",
        "issuerName": "BANCO ITAUCARD, S.A.",
        "issuingCountry": "BR",
        "lastFour": "0000"
    }
}

风险控制

在银行卡支付的情况下,一旦支付处理达到成功或失败的最终状态,且您已 与Antom签署了风险控制服务,您将在调用 onEventCallback 函数后,在响应中收到popRiskDecisionResultInfo 参数。查看下表以了解popRiskDecisionResultInfo 的子参数:

注意: 如果支付流程完成,用户被重定向到 跳转链接,您将不会收到 popRiskDecisionResultInfo 参数。

参数

描述

riskDecision

可选 字符串(16个字符)

Antom 的风险控制决策。有效值为:

  • ACCEPT: 表示 Antom 建议接受支付。
  • REJECT: 表示 Antom 建议拒绝支付。

当您与 Antom 签署了风险控制服务时,此参数将返回。

riskAuthDecision

可选 字符串 (16 个字符)

Antom 推荐的认证方法。有效值包括:

  • 3D: 对此交易推荐使用 3D 认证。
  • NON_3D: 对此交易推荐使用非 3D 认证。

当您与 Antom 签署风险控制服务时,将返回此参数。

返回的风险控制信息示例代码:

copy
{
    "result": {
        "resultCode": "SUCCESS",
        "resultStatus": "S",
        "resultMessage": "Success"
    },
    "paymentStatus": "SUCCESS",
    "paymentResultCode": "SUCCESS",
    "paymentResultMessage": "success",
    "popRiskDecisionResultInfo": {
        "riskDecision": "ACCEPT",
        "riskAuthDecision": "NON_3D"
    }
}

客户端 SDK 完整示例代码

以下代码示例说明了集成过程中的关键步骤。代码中不包括调用 支付会话创建(收银台)接口的示例,需要自行处理服务器端接口的调用。

Web/WAP 集成过程

支持桌面浏览器或移动浏览器支付的集成解决方案。以下是两种集成方法的示例代码:

  • 使用 npm 集成 SDK 包
  • 集成 SDK 包的 CDN 资源
  • 🔲 npmCDN
copy
import { AMSCashierPayment } from "@alipay/ams-checkout";
// Step 1: Instantiate the SDK and handle the callback event.
const onEventCallback = function({ code, result }) {
  switch (code) {
    case code:
      'SDK_PAYMENT_SUCCESSFUL';
      // Payment was successful. Redirect users to the payment result page.
      break;
    case code:
      'SDK_PAYMENT_PROCESSING';
      console.log('Check the payment result data', result);
      // Payment was being processed. Guide users to retry the payment based on the provided information.
      break;
    case code:
      'SDK_PAYMENT_FAIL';
      console.log('Check the payment result data', result);
      // Payment failed. Guide users to retry the payment based on the provided information.
      break;
    case code:
      'SDK_PAYMENT_CANCEL';
      // Guide the user to retry the payment.
      break;
    case code:
      'SDK_PAYMENT_ERROR';
      console.log('Check the payment result data', result);
      // The payment status was abnormal. Guide users to retry the payment based on the provided information.
      break;
    case code:
      'SDK_END_OF_LOADING';
      // End the custom loading animation.
      break;
    default:
      break;
  }
}
const checkoutApp = new 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.
  // Best practice
  await checkoutApp.createComponent({ 
    sessionData: paymentSessionData, 
    appearance:{
      showLoading: true, // Set as true by default to enable the default loading pattern.
    },
  });
}
  • 🔲
copy
// Step 1: Instantiate the SDK and handle the callback event.
const onEventCallback = function({ code, result }) {
  switch (code) {
    case code:
      'SDK_PAYMENT_SUCCESSFUL';
      // Payment was successful. Redirect users to the payment result page.
      break;
    case code:
      'SDK_PAYMENT_PROCESSING';
      console.log('Check the payment result data', result);
      // Payment was being processed. Guide users to retry the payment based on the provided information.
      break;
    case code:
      'SDK_PAYMENT_FAIL';
      console.log('Check the payment result data', result);
      // Payment failed. Guide users to retry the payment based on the provided information.
      break;
    case code:
      'SDK_PAYMENT_CANCEL';
      // Guide the user to retry the payment.
      break;
    case code:
      'SDK_PAYMENT_ERROR';
      console.log('Check the payment result data', result);
      // The payment status was abnormal. Guide users to retry the payment based on the provided information.
      break;
    case code:
      'SDK_END_OF_LOADING';
      // End the 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.
  // Best practice
  await checkoutApp.createComponent({ 
    sessionData: paymentSessionData, 
    appearance:{
      showLoading: true, // Set as true by default to enable the default loading pattern.
    }, 
  });
}

Android 设备的集成流程

以下示例代码展示了如何在 Android 设备上集成 client SDK。

copy
AMSCashierPaymentConfiguration configuration = new AMSCashierPaymentConfiguration();
configuration.setLocale(new Locale("en", "US"));
// When the showLoading parameter is set to true (default value), use the internal loading page. When false, the merchant can customize the loading animation through the event in onPaymentEventCallback.
configuration.setOption("showLoading", "true");
// Set the sandbox environment instead of the online production environment.
configuration.setOption("sandbox", "true");
// Configure whether the payment button is rendered by the SDK component.
configuration.setOption("showSubmitButton", "true");
// Set up checkout callback monitoring.
configuration.setOnCheckoutListener(new OnCheckoutListener() {
    @Override
    public void onEventCallback(String eventCode, AMSEventResult eventResult) {
        Log.e(TAG, "onEventCallback eventCode=" + eventCode + " eventResult=" + eventResult.toString());
      
        if (!TextUtils.isEmpty(eventCode)) {
            if ("SDK_PAYMENT_SUCCESSFUL".equals(eventCode)) {
                // Payment was successful. Suggest redirecting to the payment result page.
            } else if ("SDK_PAYMENT_PROCESSING".equals(eventCode)) {
                // Payment is being processed. We suggest that your server check the payment status or wait for the payment result notification.
            } else if ("SDK_PAYMENT_FAIL".equals(eventCode)) {
                // Payment failed. We suggest that you follow the paymentResultCode error code prompt and guide the user to pay it again.
            }else if ("SDK_PAYMENT_CANCEL".equals(eventCode)) {
                // The buyer did not click to pay and closed the payment window. The SDK can be re-called with paymentSessionData within the validity period. If it has expired, paymentSessionData needs to be requested again.
            } else if ("SDK_PAYMENT_ERROR".equals(eventCode)) {
                // The payment status was abnormal. We suggest that your server check the payment status or wait for the payment result notification.
            }
        }
    }
});
// Create the AMSCashierPayment instantiation.
AMSCashierPayment checkout = new AMSCashierPayment.Builder(activity, configuration).build();

checkout.mountComponent(activity, sessionData);

checkout.onDestroy();

iOS设备的集成流程

以下示例代码展示了如何在 iOS 设备上集成 client SDK。

copy
#import <AMSComponent/AMSComponent-Swift.h>

AMSCashierPaymentConfiguration *componentConfig = [AMSCashierPaymentConfiguration new];
componentConfig.locale = @"en_US";
// Set sandbox environment instead of online production environment
NSDictionary *options = @{@"showLoading": @"true", @"sandbox": @"true"};
componentConfig.options = options;

[[AMSCashierPayment shared] initConfiguration:componentConfig];

[AMSCashierPayment shared].paymentDelegate = self;
[AMSCashierPayment shared].loggerDelegate = self;
[[AMSCashierPayment shared] createComponent:paymentSessionData];

NSString *dataString = @"{\"billingAddress\":{\"zipCode\":\"310000\",\"region\":\"CN\"}}";
[[AMSCashierPayment shared] submit: dataString];

#pragma AMSPaymentProtocol
- (void)onEventCallback:(NSString *)eventCode eventResult:(AMSEventResult *)eventResult
{
    if ([eventCode isEqualToString:@"SDK_PAYMENT_SUCCESSFUL"]) {
        // Payment was successful. Suggest redirecting to the payment result page.
    } else if ([eventCode isEqualToString:@"SDK_PAYMENT_PROCESSING"]) {
        // Payment is being processed. It is recommended that your server check the payment status or wait for the payment result notification.

    } else if ([eventCode isEqualToString:@"SDK_PAYMENT_FAIL"]) {
        // Payment failed. We suggest that you follow the paymentResultCode error code prompt and guide the user to pay it again.

    } else if ([eventCode isEqualToString:@"SDK_PAYMENT_CANCEL"]) {
        // The buyer did not click to pay and closed the payment window. The SDK can be re-called with paymentSessionData within the validity period. If it has expired, paymentSessionData needs to be requested again.

    } else if ([eventCode isEqualToString:@"SDK_PAYMENT_ERROR"]) {
        // The payment status was abnormal. It is recommended that your server check the payment status or wait for the payment result notification.
    }
    NSLog(@"eventCode%@ eventResult%@", eventCode, eventResult);
}

#pragma AMSLogProtocol
- (void)logWithName:(NSString *)name parameter:(NSDictionary<NSString *,id> *)parameter
{
   NSLog(@"name%@ parameter%@", name, parameter);
}