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

Card payments (Web/WAP)

Antom SDK is a pre-built UI component designed to collect card information and manage 3D authentication processes for you. Integration of this component does not require you have a PCI qualification, making it ideal for those who prefer to entrust Antom to collect card information.

User experience

The following figures show the user journey of paying on a shopping website or mobile web app:

下载.png

Payment flow

The following process shows how to integrate Checkout Payment via Antom SDKs:

111卡.webp

  1. The user lands on the checkout page.
  2. Your server creates a payment session based on the payment method, amount, currency, and goods.
  3. Your client creates and invokes the component with the payment session.
  4. The component collects payment elements, displays code information, redirects, invokes, and guides the buyer to complete the payment based on the payment method's characteristics.
  5. Your server receives payment result notifications.

Quick start

Step 1: Create a payment session Server-side

When a buyer selects a payment method provided by Antom, you need to collect key information such as payment request ID, order amount, payment method, order description, payment redirect URL, and payment result notification URL, call the createPaymentSession API to create a payment session, and return the payment session to the client.

Antom provides server-side API libraries for multiple languages. The following codes use Java as an example. You need to install Java 6 or higher.

Install an API library

You can find the latest version on GitHub.

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

Initialize request instance

Create a singleton resource to make a request to Antom.

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

String merchantPrivateKey = "YOUR PRIVATE KEY";
String alipayPublicKey = "ALIPAY PUBLIC KEY"
AlipayClient defaultAlipayClient = new DefaultAlipayClient(EndPointConstants.SG,
                                                           merchantPrivateKey, alipayPublicKey);

Create a payment session

Creating a payment session includes the following parameters:

Parameter name

Required

Description

productCode

The value is fixed to CASHIER_PAYMENT.

paymentRequestId

The unique ID generated by the merchant, a new ID is required every time a payment is initiated.

paymentAmount

Payment amount, should be set according to the smallest unit of the order currency, e.g. CNY for cents, KRW for dollars.

paymentMethod

Payment method enumeration

paymentRedirectUrl

Merchant's payment result page, according to the server-side results, not a fixed success page.

order

Order information, including order amount, order ID, and order description on the merchant side.

paymentNotifyUrl

Payment result notification address, which can be passed in through the API or set as a fixed value through the portal.

settlementStrategy

Settlement currency of the payment, if the business has signed more than one settlement currency, you need to specify it in the API.

The above parameters are the basic parameters for creating a payment session, for full parameters and additional requirements for certain payment methods please refer to createPaymentSession (Checkout Payment).

The following sample code shows how to call the createPaymentSession API:

copy
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setClientId(CLIENT_ID);
alipayPaymentSessionRequest.setPath("/ams/sandbox/api/v1/payments/createPaymentSession");
alipayPaymentSessionRequest.setProductCode(ProductCodeType.CASHIER_PAYMENT);


// replace to your paymentRequestId
alipayPaymentSessionRequest.setPaymentRequestId("paymentRequestId01");

Amount amount = new Amount();
amount.setCurrency("SGD");
amount.setValue("4200");

alipayPaymentSessionRequest.setPaymentAmount(amount);

//set settlement currency
SettlementStrategy settlementStrategy = new SettlementStrategy();
settlementStrategy.setSettlementCurrency("SGD");
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);

// set paymentMethod
PaymentMethod paymentMethod = new PaymentMethod();
paymentMethod.setPaymentMethodType("CARD");
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);

// set paymentFactor
PaymentFactor paymentFactor = new PaymentFactor();
paymentFactor.setAuthorization(true);
alipayPaymentSessionRequest.setPaymentFactor(paymentFactor);

// set order Info
Order order = new Order();
order.setReferenceOrderId("referenceOrderId01");
order.setOrderDescription("antom sdk test order");
order.setOrderAmount(amount);
Buyer buyer = new Buyer();
buyer.setReferenceBuyerId("yourBuyerId");
order.setBuyer(buyer);
order.setOrderAmount(amount);
alipayPaymentSessionRequest.setOrder(order);

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

// replace to your redirect url
alipayPaymentSessionRequest.setPaymentRedirectUrl("https://www.yourMerchantWeb.com");
AlipayPaymentSessionResponse alipayPaymentSessionResponse = null;

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

The following code shows a sample of the request message:

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

The following code shows a sample of the response, which contains the following parameters:

  • paymentSessionData: the payment session to be returned to the frontend
  • paymentSessionExpiryTime: the expiration time of the payment session.
copy
{
  "paymentSessionData": "UNvjVWnWPXJA4BgW+vfjsQj7PbOraafHY19X+6EqMz6Kvvmsdk+akdLvoShW5avHX8e8J15P8uNVEf/PcCMyXg==&&SG&&111",
  "paymentSessionExpiryTime": "2023-04-06T03:28:49Z",
  "paymentSessionId": "UNvjVWnWPXJA4BgW+vfjsQj7PbOraafHY19X+6EqMz6Ikyj9FPVUOpv+DjiIZqMe",
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": "success.",
    "resultStatus": "S"
  }
}

FAQs

Can Chinese characters be used in the request?

 Do not use Chinese characters for the fields in the request including paymentRequestId, referenceOrderId, orderDescription, and goods to avoid incompatible payment methods, such as QRIS and Mastercard.

How to set the payment result notification address?

Antom will send the payment result through the notifyPayment, which you can specify in the createPaymentSession API via the paymentNotifyUrl parameter. If the address of each payment is the same, you can also configure it in the Antom Dashboard. If you have configured the address and set the parameter in the API, Antom will use the address set in the API.

Step 2: Create and invoke the SDK Client-side

The Antom SDK is a component used for handling payment processes. You initiate the SDK by creating a payment session to collect information and switch between apps based on the payment method specified in createPaymentSession API.

Install

Before beginning the integration, make sure that you have completed the following environment preparations:

  • Properly handle compatibility issues: Provide corresponding polyfills for Internet Explorer and other old browser versions. We recommend that you use babel-preset-env to address browser compatibility issues when you build a project.
  • Use the following recommended browser versions:
    • For mobile browsers:
      • iOS 11 and later.
      • Android 5.0 and later.
    • For computer browsers, use the following recommended versions:

imageEdge

Last 2 versions

imageFirefox

Last 2 versions

imageChrome

Last 2 versions

imageSafari

Last 2 versions

imageOpera

Last 2 versions

imageElectron

Last 2 versions

You can integrate the SDK resource package via CDN or npm.

copy
<script src="https://sdk.marmot-cloud.com/package/ams-checkout/1.11.1/dist/umd/ams-checkout.min.js"></script>
copy
npm install @alipay/ams-checkout

Instantiate the SDK

Create the SDK instance by using the AMSCashierPayment. Configuration objects includes the following parameters:

Parameter name

Required

Description

environment

Required string. It is used to pass in environmental information. Valid values are:

  • sandbox: Sandbox environment
  • prod: Production environment

locale

Optional. String type. It is used to pass in language information. Valid values are listed as follows. You can choose the value to pass based on the region of the payment method. If other values are passed, the local language is used by default:

  • en_US: English
  • pt_BR: Portuguese
  • ko_KR: Korean
  • es_ES: Spanish
  • ms_MY: Malay
  • in_ID: Indonesian
  • tl_PH: Tagalog
  • th_TH: Thai
  • vi_VN: Vietnamese
  • fr_FR: French
  • nl_NL: Dutch
  • it_IT: Italian
  • de_DE: German
  • zh_CN: Simplified Chinese
  • zh_HK: Traditional Chinese

analytics

Optional object. It is used to configure and analyze data. It contains a value below:

  • enabled: Optional Boolean. It defaults to true, which indicates that you allow the SDK to upload and analyze operational data to deliver a better service. If you do not allow the data to be uploaded and analyzed, specify it as false.

onLog

Optional. It is a callback method that is used to generate the error information about logs and API exceptions during the execution of the SDK.

onEventCallback

Optional. A callback function returns a specific event code when a payment event happens during SDK runtime, like payment result or a form submission error. For further information, please refer to the References.

The following sample code shows how to obtain the browser language:

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

The following sample code shows how to instantiate the SDK:

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

Invoke the SDK

After the buyer selects a payment method on the page, you need to create the SDK and initiate it with a payment session.

Use the createComponent or mountComponent function in the instance object to create a payment component:

Parameter name

Required

Description

sessionData

Create a configuration object by using the sessionData parameter: Pass the complete data in the paymentSessionData parameter obtained in the response through the createpaymentSession (Checkout Payment) API to the sessionData parameter.

appearance

Optional object for customized appearance theme configuration, and it contains the following child parameters:

  • showLoading: Optional. Boolean type. The default value is true, which shows the default loading animation. If you don't use the default loading animation, you need to specify this value as false.
  • showSubmitButton: Optional. Boolean type. The default value is false, which disables the button to render payment page.

notRedirectAfterComplete

notRedirectAfterComplete: Optional, Boolean type. The default value is false, which means it will jump back to your page after the payment is completed. The same applies when the value is empty. true value means there will be no jump after the payment is completed. You need to use the customer event code to control the card binding to complete the subsequent process. Please note that the payment result code returned by the client is only used as a reference for the jump operation of the client page. For transaction status's updates, please refer to the results returned by the server's notifyPayment or inquiryPayment API.

merchantAppointParam

Optional object used for setting custom features. It contains a value below:

  • storedCard: Optional object used for setting custom features of stored cards. It contains a value below:
    • needCVV: Optional Boolean. The default value is false, which indicates that the buyer do not need to input CVV number during the payment process. The same applies when the value is empty. true value means the buyer need to input CVV number during the payment process.

Embedded experience vs. Popup experience

There are different ways in which you can make the SDK display on a page through a pop-up window or embedded on a page.

Embedded experience

Popup experience

image.png

image.png

Popup experience

Popup experience offers the advantage of low impact on page style and relatively independent flow.

After the buyer selects a payment method on the page and clicks submit, you need to inevoke the SDK and pop up the window.

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,
  });
}

Embedded experience

The embedded experience embeds payment element within the designated view. You need to focus on styling adjustments for the payment list. The embedded content's width adjusts automatically to fit the parent container, while the height dynamically updates with view changes.

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');
}

Embedded Submit Payment

When using embedded experience and a custom submit button, remember to actively call the submit function to initiate the submission process.

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

Destroy the Component

Call the unmount method to free SDK component resources in the following situations:

  • When the buyer switches views to exit the checkout page, free the component resources created in the createPaymentSession.
  • When the buyer initiates multiple payments, free the component resources created in the previous createPaymentSession.
  • When the buyer completes the payment and sets notRedirectAfterComplete to true, free the component resources after obtaining specific payment result codes.
copy
// Free SDK component resources
checkoutApp.unmount();

FAQs

What can I do when I receive the SDK_CREATEPAYMENT_PARAMETER_ERROR?

When you receive this event code, please check if the sessionData passed in is correct and complete.

What can I do when I receive the SDK_PAYMENT_ERROR or Rendering View Error?

When you receive this event code, please check the network request. There may be an exception in the initialization interface, and you need to make sure that the environment of the payment session creation request is consistent with the environment parameters of the instantiated SDK. Check whether the payment session creation parameters are passed correctly. If the interface exception still exists, you can contact us for troubleshooting.

What can I do when I receive the SDK_FORM_VERIFICATION_FAILED?

The reason could be that the buyer did not fill in all the required elements. Upon submission, an error code indicating form verification failure may be returned. It is recommended to guide the buyer on enhancing the form content.

Display payment results

If you set notRedirectAfterComplete to false, the buyer will be redirected to the paymentRedirectUrl that you provided in createPaymentSession API after completing the payment. You can obtain the payment result by active query in that URL and show it to the buyer.

If notRedirectAfterComplete is true, the payment result will be given through the onEventCallback function. The payment result here is only for front-end display, and the final order status is subject to the server side.

You need to customize the processing flow you want for each payment result through the data in the result of onEventCallback.

The following are the possible event codes of the payment result returned by onEventCallback:

Event code

Message

Solution

SDK_PAYMENT_SUCCESSFUL

Payment was successful.

Suggest redirecting buyers to the payment result page.

SDK_PAYMENT_PROCESSING

Payment was being processed.

We suggest that you check the value of paymentResultCode in the onEventCallback result data for details. Guide buyers to retry the payment based on the provided information.

SDK_PAYMENT_FAIL

Payment failed.

We suggest that you check the value of paymentResultCode in the onEventCallback result data for details. Guide buyers to retry the payment based on the provided information.

SDK_PAYMENT_CANCEL

The buyer exits the payment page without submitting the order.

The SDK can be re-invoked with a paymentSessionData within the validity period; if it has expired, the paymentSessionData needs to be re-requested.

SDK_PAYMENT_ERROR

The payment status was abnormal.

We suggest that you check the value of paymentResultCode in the onEventCallback result data for details. Guide buyers to retry the payment based on the provided information.

The following sample code shows how to process the 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;
  }
}

Step 3: Obtain payment result Server-side

After the buyer completes the payment or the payment times out, Antom sends the corresponding payment results to the you through server interactions, you can obtain the payment result by one of the following methods:

  • Receive the asynchronous notification
  • Inquire about the result

Receive the asynchronous notification

When the payment reaches a final status of success or failure, Antom sends an asynchronous notification to the paymentNotifyUrl specified in the createPaymentSession API through the notifyPayment API. When you receive the notification from Antom, you are required to return a response as instructed in Requirements.

Antom allows you to specify the URL in the paymentNotifyUrl parameter within the createPaymentSession API. If the URL for each payment is the same, you can also configure it in the Antom Dashboard.

The following code shows a sample of the notification request:

copy
{
  "notifyType": "PAYMENT_RESULT",
  "result": {
    "resultCode": "SUCCESS",
    "resultStatus": "S",
    "resultMessage": "success"
  },
  "paymentRequestId": "2020010123456789XXXX",
  "paymentId": "2020010123456789XXXX",
  "paymentAmount": {
    "value": "4200",
    "currency": "SGD"
  },
  "paymentCreateTime": "2020-01-01T12:01:00+08:30",
  "paymentTime": "2020-01-01T12:01:01+08:30"
}

The following sample code shows how to verify the signature of the notification and make a response to the notification:

copy
@RequestMapping(path = "/payResult", method = RequestMethod.POST)
  public ResponseEntity<AlipayResponse> paymentNotifyProcessor(HttpServletRequest request,
                                                               @RequestBody String body) {

    // retrieve the required parameters from the request header.
    String requestTime = request.getHeader("request-time");
    String clientId = request.getHeader("client-id");
    String rawSignature = request.getHeader("signature");
    String signature = "";

    // get valid part from raw signature
    if(rawSignature==null||rawSignature.isEmpty()){
      throw new RuntimeException("empty notify signature");
    }else {
      String[] parts = rawSignature.split("signature=");
      if (parts.length > 1) {
        signature = parts[1];
      }
    }

    // verify payment result notify's signature
    boolean verifyResult = SignatureTool.verify(request.getMethod(), request.getRequestURI(),
                                                clientId, requestTime, body, signature,
                                                ALIPAY_PUBLIC_KEY);
    if (!verifyResult) {
      throw new RuntimeException("Invalid notify signature");
    }

    // update the record status with notify result

    // respond the server that we accept the notify
    Result result = new Result("SUCCESS", "success", ResultStatusType.S);
    AlipayResponse response = new AlipayResponse();
    response.setResult(result);
    return ResponseEntity.ok().body(response);
  }

FAQs

When will the notification be sent?

After the payment is completed, Antom will send asynchronous notification to you within 3~5s, some payment methods such as offline stores take a little longer;

If the payment is not completed, Antom will send asynchronous notification only after the order is closed, the time to close the order is different for different payment methods, generally the default is 14min, you can refer to the list of payment methods for special payment methods.

If the buyer does not submit the payment, in the scenario that the Component needs to collect the payment information (such as card information), if you do not enter any information and directly turn off the component, the notification will not be sent.

Will the asynchronous notification be re-sent?

If you receive an asynchronous notification from Antom, you are required to return the response in the Sample code format. If you do not respond to the asynchronous notification as required, or the asynchronous notification is not delivered due to network reasons, the notification will be automatically resent within 24 hours. The notification can be resent up to 8 times or until a correct response is received to terminate delivery. The sending intervals are as follows: 0 minutes, 2 minutes, 10 minutes, 10 minutes, 1 hour, 2 hours, 6 hours, and 15 hours.

Do I need to add a digital signature to the response?

If you receive an asynchronous notification from Antom, you are required to return the response in the Sample code format, but you do not need to add a digital signature to your response.

How do I understand the meaning of the following key fields?
  • result: the payment result of the order.
  • paymentRequestId: the payment request ID generated by the merchant used for querying, canceling, and reconciliation.
  • paymentId: the payment order ID generated by Antom used for refund and reconciliation.
  • paymentAmount: if there is a need for amount reconciliation, you can consume this field.

Inquire about the result

You can call the inquiryPayment API to initiate a query on the result of an order.

Parameter name

Required

Description

paymentRequestId

The payment request ID generated by the merchant.

The parameter is not a full set of parameters, please refer to the inquiryPayment API for full set of parameters and additional requirements for certain payment methods.

The following sample code shows how to call the inquiryPayment API:

copy

AlipayClient defaultAlipayClient = new DefaultAlipayClient(EndPointConstants.SG,
                                                           merchantPrivateKey, alipayPublicKey);

AlipayPayQueryRequest alipayPayQueryRequest = new AlipayPayQueryRequest();
alipayPayQueryRequest.setClientId(CLIENT_ID);
alipayPayQueryRequest.setPath("/ams/api/v1/payments/inquiryPayment");

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

The following code shows a sample of the request message:

copy
{
  "paymentRequestId": "2019060811401080010018882020035****"
}

The following code shows a sample of the response message:

copy
{
  "result": {
    "resultCode": "SUCCESS",
    "resultStatus": "S",
    "resultMessage": "Success"
  },
  "paymentStatus": "SUCCESS",
  "paymentRequestId": "pay_1089760038715669_10277574507XXXX",
  "paymentId": "2019060811401080010018882020035XXXX",
  "paymentAmount": {
    "value": "4200",
    "currency": "SGD"
  },
  "paymentCreateTime": "2019-06-01T12:01:01+08:30",
  "paymentTime": "2019-06-01T12:01:01+08:30",
  "transactions": null
}

FAQs

How do I understand the meaning of the following key fields?
  • result: the result of the API call. It only indicates the result of the inquiryPayment API call. The order result should be determined based on the paymentStatus. SUCCESS and FAIL indicate final results, while PROCESSING indicates that the transaction is still in progress.
  • paymentAmount: amount verification. If there is a need for amount verification, this field can be used.
How frequently should I initiate the query?

It is recommended to initiate a round-robin query at an interval of 2 seconds until either the final payment result is retrieved or an asynchronous payment notification is received.

Step 4: Obtain capture result Server-side

After the buyer completes the capture or the capture times out, Antom sends the corresponding capture results to you through server interactions, you can obtain the capture result by one of the following methods:

  • Receive the asynchronous notification
  • Inquire about the result

Receive the asynchronous notification

When the capture reaches a final status of success or failure, Antom sends an asynchronous notification to the paymentNotifyUrl specified in the createPaymentSession API through the notifyPayment API. When you receive the notification from Antom, you are required to return a response as instructed in Requirements.

Antom allows you to specify the URL in the paymentNotifyUrl parameter within the createPaymentSession API. If the URL for each payment is the same, you can also configure it in the Antom Dashboard.

The following code shows a sample of successful capture:

copy
"captureAmount": {
  "currency": "SGD",
  "value": "4200"
},
"notifyType": "CAPTURE_RESULT",
"captureId": "2022XXXXXXX",
"captureRequestId": "Merchant_Request_ID_XXXXXX",
"captureTime": "2022-11-10T00:34:52-08:00",
"paymentId": "2022XXXXXXX",
"result": {
  "resultCode": "SUCCESS",
  "resultMessage": "success.",
  "resultStatus": "S"
}
}

The following code shows a sample of failed capture:

copy
"captureAmount": {
  "currency": "SGD",
  "value": "4200"
},
"notifyType": "CAPTURE_RESULT",
"captureId": "2022XXXXXXX",
"captureRequestId": "Merchant_Request_ID_XXXXXX",
"captureTime": "2022-11-10T00:34:52-08:00",
"paymentId": "2022XXXXXXX",
"result": {
  "resultCode": "PROCESS_FAIL",
  "resultMessage": "fail.",
  "resultStatus": "F"
}
}

The following sample code shows how to verify the signature of the notification and make a response to the notification:

copy
@RequestMapping(path = "/captureResult", method = RequestMethod.POST)
public ResponseEntity<AlipayResponse> captureNotifyProcessor(HttpServletRequest request,
                                                             @RequestBody String body) {

    // retrieve the required parameters from the request header.
    String requestTime = request.getHeader("request-time");
    String clientId = request.getHeader("client-id");
    String rawSignature = request.getHeader("signature");
    String signature = "";

    // get valid part from raw signature
    if(rawSignature==null||rawSignature.isEmpty()){
        throw new RuntimeException("empty notify signature");
    }else {
        String[] parts = rawSignature.split("signature=");
        if (parts.length > 1) {
            signature = parts[1];
        }
    }

    // verify payment result notify's signature
    boolean verifyResult = SignatureTool.verify(request.getMethod(), request.getRequestURI(),
                                                clientId, requestTime, body, signature,
                                                ALIPAY_PUBLIC_KEY);
    if (!verifyResult) {
        throw new RuntimeException("Invalid notify signature");
    }

    // update the record status with notify result

    // respond the server that we accept the notify
    Result result = new Result("SUCCESS", "success", ResultStatusType.S);
    AlipayResponse response = new AlipayResponse();
    response.setResult(result);
    return ResponseEntity.ok().body(response);
}

FAQs

When will the notification be sent?

After the payment is completed, Antom will send asynchronous notification to you within 3~5s, some payment methods such as offline stores take a little longer;

If the payment is not completed, Antom will send asynchronous notification only after the order is closed, the time to close the order is different for different payment methods, generally the default is 14min, you can refer to the list of payment methods for special payment methods.

If the buyer does not submit the payment, in the scenario that the Component needs to collect the payment information (such as card information), if you do not enter any information and directly turn off the Component, the notification will not be sent.

Will the asynchronous notification be re-sent?

If you receive an asynchronous notification from Antom, you are required to return the response in the Sample code format. If you do not respond to the asynchronous notification as required, or the asynchronous notification is not delivered due to network reasons, the notification will be automatically resent within 24 hours. The notification can be resent up to 8 times or until a correct response is received to terminate delivery. The sending intervals are as follows: 0 minutes, 2 minutes, 10 minutes, 10 minutes, 1 hour, 2 hours, 6 hours, and 15 hours.

Do I need to add a digital signature to the response?

If you receive an asynchronous notification from Antom, you are required to return the response in the Sample code format, but you do not need to add a digital signature to your response.

How do I understand the meaning of the following key fields?
  • result: represents the capture result of the order.
  • notifyType: the value of notifyType is CAPTURE_RESULT.
  • paymentRequestId: the payment request number you generated, used for querying, canceling, and reconciliation.
  • paymentId: the payment order ID generated by Antom used for refund and reconciliation.
  • acquirerReferenceNo: merchants integrating with in-card payment services in Singapore and Hong Kong will receive specific acquirer numbers in the notification.

Inquire about the result

You can call the inquiryPayment API to initiate a query on the result of an order.

Parameter name

Required

Description

paymentRequestId

The payment request ID generated by the merchant.

The parameter is not a full set of parameters, please refer to the inquiryPayment API for full set of parameters and additional requirements for certain payment methods.

The following sample code shows how to call the inquiryPayment API:

copy
AlipayClient defaultAlipayClient = new DefaultAlipayClient(EndPointConstants.SG,
                                                           merchantPrivateKey, alipayPublicKey);

AlipayPayQueryRequest alipayPayQueryRequest = new AlipayPayQueryRequest();
alipayPayQueryRequest.setClientId(CLIENT_ID);
alipayPayQueryRequest.setPath("/ams/api/v1/payments/inquiryPayment");

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

The following code shows a sample of the request message:

copy
{
  "paymentRequestId": "2019060811401080010018882020035****"
}

The value of the transactions in the response of the API is the capture status:

Parameter name

Description

transactions.transationType

The value is CAPTURE, meaning the capture status.

transactions.transactionResult

Capture status.

The following code shows a sample of successful capture:

copy
{
  "transactions": [
    {
      "transactionType": "CAPTURE",
      "transactionStatus": "SUCCESS",
      "transactionRequestId": "test_test_test_XXXX",
      "transactionAmount": {
        "currency": "BRL",
        "value": "110"
      },
      "transactionId": "2022XXXXXXXX",
      "transactionResult": {
        "resultStatus": "S",
        "resultCode": "SUCCESS",
        "resultMessage": "success"
      }
    }
  ]
}

The following code shows a sample of failed capture:

copy
{
  "transactions": [
    {
      "transactionType": "CAPTURE",
      "transactionStatus": "FAIL",
      "transactionRequestId": "test_test_test_XXXX",
      "transactionAmount": {
        "currency": "BRL",
        "value": "110"
      },
      "transactionTime": "2022-09-29T07:13:50-07:00",
      "transactionId": "2022XXXXXXXX",
      "transactionResult": {
        "resultStatus": "F",
        "resultCode": "PROCESS_FAIL",
        "resultMessage": "General business failure. No retry."
      }
    }
  ]
}

The following code shows a sample of failed capture:

copy
{
  "transactions": [
    {
      "transactionType": "CAPTURE",
      "transactionStatus": "PROCESSING",
      "transactionRequestId": "test_test_test_XXXX",
      "transactionAmount": {
        "currency": "BRL",
        "value": "110"
      },
      "transactionId": "2022XXXXXXXX",
      "transactionResult": {
        "resultStatus": "U",
        "resultCode": "PAYMENT_IN_PROCESS",
        "resultMessage": "payment in process"
      }
    }
  ]
}

FAQs

How do I understand the meaning of the following key fields?
  • result: the result of the API call. It only indicates the result of the inquiryPayment API call. The order result should be determined based on the paymentStatus. SUCCESS and FAIL indicate final results, while PROCESSING indicates that the transaction is still in progress.
  • paymentAmount: amount verification. If there is a need for amount verification, this field can be used.
How frequently should I initiate the query?

It is recommended to initiate a round-robin query at an interval of 2 seconds until either the final payment result is retrieved or an asynchronous payment notification is received.

Sample codes

Full sample codes for front-end:

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.
    }, 
  });
}

Sample codes for customized loading animation:

The card payment scenario supports configuration of custom loading animations:

  1. Configure showLoading to false when rendering the component.
  2. Render a customized loading animation on the current page when the createComponent function is called.
  3. Listen to the onEventCallback event.
    1. Show your custom loading animation when you receive the SDK_START_OF_LOADING event code.
    2. End your custom loading animation when you receive the SDK_END_OF_LOADING event code.
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.
    }, 
  });
}

Sample codes for AVS authentication:

Pass in pre-collected billing address information for AVS authentication.

Parameter name

Required

Description

billingAddress

If you need to pass in pre-collected billing address information for AVS validation, you can configure the following parameters to be passed in via the submit method.

  • billingAddress: Optional Object. Billing address information is used to identify and locate the payer. It contains the following parameters:
    • region: Required. String (2). ISO 3166 compliant 2-digit country code.
    • state: Optional. String (8). The name of the state, country, or province.
    • city: Optional. String (32). Name of the city, region, suburb, town or village.
    • address1: Optional. String (256). Address line 1, e.g., street address, P.O. Box, and company name.
    • address2: Optional. String (256). Address line 2, e.g., apartment, suite, unit, and building information.
    • zipCode: Optional. String (32). Zip code.
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})=>{})

Event codes

The SDK provides the following status codes:

  • SDK_START_OF_LOADING: The loading animation starts to play during the payment component creation.
  • SDK_END_OF_LOADING: The loading animation ends during the payment component creation.

 

The SDK provides the following error codes:

  • SDK_INTERNAL_ERROR: The internal error of the SDK occurs. Contact Alipay Technical Support to resolve the issue.
  • SDK_CREATEPAYMENT_PARAMETER_ERROR: The parameters passed into the AMSCashierPayment method are incorrect. Ensure the parameters are passed correctly and send a new request.
  • SDK_INIT_PARAMETER_ERROR: The parameters passed into the createComponent method are incorrect. Ensure the parameters are passed correctly and send a new request.
  • SDK_CREATECOMPONENT_ERROR: An exception occurs when calling the createComponent method. Contact Alipay Technical Support to resolve the issue.
  • SDK_CALL_URL_ERROR: The payment method client failed to be revoked. Contact Alipay Technical Support to resolve the issue.