Accept payments with EasySafePay (SDK)
Antom EasySafePay is a minimalist payment solution focused on small-amount, high-frequency payment scenarios. With its innovative "bind payment method upon first payment" design and one-click payment feature, it significantly simplifies the payment process. Buyers can choose to pay directly or perform payment method binding during the first transaction, and subsequent payments can be processed instantly without repeated verification.
This solution leverages industry-leading intelligent risk control systems, dynamic polling technology, and payment failure recovery strategies to ensure transaction security while achieving top-tier payment success rates in the industry. It creates a win-win-win scenario for buyer payment experience, merchant conversion rates, and platform ecosystem value.
Web/WAP
User experience
Through simple browser integration, you can quickly enable digital wallet and online banking payment functionalities.
Different payment methods vary in their browser-side user experience. For specific interaction differences, refer to the table below:
Payment method category | Payment method | Terminal type | First-time payment | Subsequent payments |
Digital wallet | Web | Complete the payment within the payment method app. | Complete the payment on the merchant page. | |
Online banking | Web | Complete the payment on the payment method page. | Complete the payment on the payment method page. | |
Digital wallet | WAP | Complete the payment on the merchant page. | Complete the payment on the merchant page. | |
WAP | Redirect to the payment method app to complete payment. | Complete the payment on the merchant page. | ||
Online banking | WAP | Complete the payment on the merchant page. | Complete the payment on the merchant page. |
Digital wallet
In the digital wallet payment scenario, the system will guide the buyer to complete the transaction on the merchant's page or within the payment method app after the buyer confirms the payment. The first payment verification and subsequent simplified payment process are illustrated as follows:
First payment
The first payment requires security authentication. Once authorized, the buyer will be enabled for password-free payments on subsequent transactions.
Subsequent payments
Subsequent payments will be processed automatically upon order submission, without requiring password entry.
Online banking
The online banking process is illustrated as follows, including first payment authentication and subsequent simplified payment flows.
First payment
The first payment requires security authentication. Once authorized, the buyer will be enabled for password-free payments on subsequent transactions.
Subsequent payments
Subsequent payments will be processed automatically upon order submission, without requiring password entry.
Payment flow
First payment
The first payment flow chart:
- The buyer enters the checkout page.
- Create a payment session request.
After the buyer selects a payment method and submits the order, you can obtain the payment session by calling the createPaymentSession (EasySafePay) API. - Invoke the client SDK.
Invoke the SDK using a payment session and the SDK will automatically collect payment elements, render the payment interface, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics. For detailed interaction differences across payment methods, refer to the User experience table. - Obtain the authorization result.
When the authorization is successful, Antom sends you the asynchronous notification through the notifyAuthorization API. - Obtain the payment result.
Obtain the payment result using one of the following methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (EasySafePay) API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use notifyPayment to send asynchronous notifications to you.
- Synchronous inquiry: Call the inquiryPayment API to check the real-time payment status.
Subsequent payments
The subsequent payment flow chart:
- The buyer enters the checkout page.
- Create a payment session request.
After the buyer selects a payment method and submits the order, you can obtain the payment session by calling the createPaymentSession (EasySafePay) API. - Invoke the client SDK.
Invoke the SDK using a payment session and the SDK will automatically collect payment elements, render the payment interface, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics. For detailed interaction differences across payment methods, refer to the User experience table. - Obtain the payment result.
Obtain the payment result using one of the following methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (EasySafePay) API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use notifyPayment to send asynchronous notifications to you.
- Synchronous inquiry: Call the inquiryPayment API to check the real-time payment status.
Integration preparations
Before you start integrating, read the Integration Guide and API Overview documents to understand the integration steps of the server-side API and the precautions for calling the API. Furthermore, ensure that the following prerequisites are met:
- Obtain a client ID
- Complete the key configuration
- Complete the configuration of paymentNotifyUrl to receive the asynchronous notification
- Integrate the server-side SDK package, install the server-side library, and initialize a request instance. For more details, refer to Server-side SDKs.
- If you need to conduct joint debugging by connecting the sandbox with the production environment, please contact Antom technical support at least two business days in advance to request configuration. The sandbox environment and production environment require separate configuration.
Integration steps
Start your integration by taking the following steps:
- (Optional) Preload the SDK
- Create a payment session
- Invoke the SDK
- Obtain the authorization and payment result
(Optional) Step 1: Preload the SDK Client-side
Preloading the SDK during the checkout page initialization significantly improves the rendering performance with no negative impact. It is recommended to trigger preloading of the SDK when the buyer selects a payment method.
Follow the code example below to perform the preloading:
AMSEasyPay.preload();
Step 2: Create a payment session Server-side
When a buyer selects a payment method provided by Antom, you need to collect essential information including the payment request ID, order amount, payment method, order description, payment redirect page URL, and payment result notification URL.
Call the createPaymentSession (EasySafePay) API to create a payment session and initialize the Antom SDK using the paymentSessionData value returned in the response.
The table below lists the parameter specifications for calling the createPaymentSession (EasySafePay) API during the first and subsequent payments:
Note: For subsequent payments with Express Bank Transfer, simply keep the parameters consistent with the first payment. The buyer can open the Express Bank Transfer webpage and enter the phone number to proceed directly with the payment.
Parameter type | Parameter name | Required (First-time payment) | Required (Subsequent payments) | Description |
Base parameter | productCode | Yes | Yes | The value is fixed as AGREEMENT_PAYMENT in the EasySafePay scenario. |
productScene | Yes | Yes | The value is fixed as EASY_PAY in the EasySafePay scenario. | |
paymentRequestId | Yes | Yes | The unique ID assigned by a merchant to identify a payment request. | |
paymentMethod.paymentMethodType | Yes | Yes | ||
paymentMethod.paymentMethodId | No | Yes | The unique ID that is used to identify a payment method. The value of this parameter is that of accessToken from the notifyAuthorization API. | |
settlementStrategy | No | No | The settlement strategy for the payment request. If the merchant agreement supports multiple settlement currencies, they must be specified in the API request. | |
paymentAmount.value | Yes | Yes | The value of the amount as a positive integer in the smallest currency unit. | |
paymentAmount.currency | Yes | Yes | ||
paymentSessionExpiryTime | No | No | The specific date and time after which the payment session will expire. The default expiration time is 1 hour after the session creation. For example, if the session is created at 2023-7-27T12:00:01+08:30, the session expiration time is 2023-7-27T13:00:01+08:30. | |
paymentRedirectUrl | Yes | Yes | The merchant page URL that the user is redirected to after the payment is completed. The page display according to the server-side result and should not default to a fixed payment success page.
| |
paymentNotifyUrl | No | No | The URL that is used to receive the payment result notification. it must be an HTTPS URL. This field can be omitted if already configured via Antom Dashboard. | |
Authorization parameter | agreementInfo.authState | Yes | No | The unique ID generated by the merchant to initiate an EasySafePay authorization. |
Order parameter | order.orderAmount | Yes | Yes | The order amount of the merchant that directly provides services or goods to the customer |
order.referenceOrderId | Yes | Yes | The unique ID to identify the order on the merchant side. | |
order.orderDescription | Yes | Yes | Summary description of the order. | |
order.buyer.referenceBuyerId | No | No | Submit buyer information for risk assessment. Provide at least one of these fields: referenceBuyerId, buyerPhoneNo, or buyerEmail. | |
order.buyer.
| No | No | Buyer's account. Providing relevant payment account information can effectively improve the payment success rate and reduce the risk of buyer attrition. Please refer to the table below for specific format requirements. |
The parameter format for the buyer's payment account for each payment method is as follows:
Payment method | Parameter format |
It is recommended to prioritize using a mobile phone number:
| |
62-8569****7288. The phone number starts with 8 and is no more than 12 digits long, excluding the prefix. | |
TrueMoney | The buyer is authenticated on the payment method side, and no parameters need to be passed in.userloginId. |
During the first-time payment, passing the buyer's payment account will auto-fill the buyer's account on the payment page, eliminating manual input. Below is a comparison of the user experience with and without these fields:
With account parameter passed
Login account input is not required.
Without account parameter passed
Manual input of login account is required.
Below are code examples for first and subsequent payments.
First payment
@@PostMapping("/payment/createSession")
public ResponseEntity<ApiResponse> createPaymentSession(@RequestBody PaymentVO payment) {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// replace with paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// convert amount unit(in practice, amount should be calculated on your serverside)
// For details, please refer to: <a href="https://docs.antom.com/ac/ref/cc">Usage rules of the Amount object</a>
long amountMinorLong = Money.of(CurrencyUnit.of(payment.currency), new BigDecimal(payment.amountValue)).getAmountMinorLong();
// set amount
Amount amount = Amount.builder().currency(payment.currency).value(String.valueOf(amountMinorLong)).build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
// set settlement strategy
// replace with your existing settlement currency
SettlementStrategy settlementStrategy = SettlementStrategy.builder().settlementCurrency("USD").build();
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
User loginUser = users.get(payment.getUserId());
// set buyer info
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// set paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType(payment.paymentMethodType).build();
if (loginUser.getPaymentMethodTypeAccessToken().containsKey(payment.getPaymentMethodType())) {
// buyer has authorized
String accessToken = loginUser.getPaymentMethodTypeAccessToken().get(payment.getPaymentMethodType());
paymentMethod.setPaymentMethodId(accessToken);
} else {
// set agreementInfo
// replace with your authState
String authState = UUID.randomUUID().toString();
AgreementInfo agreementInfo = AgreementInfo.builder().authState(authState).build();
alipayPaymentSessionRequest.setAgreementInfo(agreementInfo);
// save the paymentMethodType corresponding to the authState
authStatePayment.put(authState, payment);
// The login ID that the user used to register in the payment method client. The login ID can be the user's email address or phone number.
// Specify this parameter to free users from manually entering their login IDs.
if(StringUtil.isNotBlank(loginUser.getPhoneNumber()){
buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
}
if(StringUtil.isNotBlank(loginUser.getEmail() && "ALIPAY_HK".equals(payment.getPaymentMethodType())){
buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
}
}
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// replace with your orderId
String orderId = UUID.randomUUID().toString();
// set order info
Order order = Order.builder().referenceOrderId(orderId)
.orderDescription("antom sdk testing order").orderAmount(amount).buyer(buyer).build();
alipayPaymentSessionRequest.setOrder(order);
// replace with your notify url
// or configure your notify url here: <a href="https://dashboard.antom.com/global-payments/developers/iNotify">Notification URL</a>
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com/payment/receivePaymentNotify");
// replace with your redirect URL
alipayPaymentSessionRequest.setPaymentRedirectUrl(
"http://localhost:8080/index.html?paymentRequestId=" + paymentRequestId);
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
long startTime = System.currentTimeMillis();
System.out.println("payment request: " + JSON.toJSONString(alipayPaymentSessionRequest));
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
System.out.println("payment response: " + JSON.toJSONString(alipayPaymentSessionResponse));
System.out.println("payment request cost time: " + (System.currentTimeMillis() - startTime) + "ms");
} catch (AlipayApiException e) {
return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), e));
}
return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), alipayPaymentSessionResponse));
}The following code shows a sample of the request message:
{
"agreementInfo": {
"authState": "authState001",
"userLoginId": "userLoginId001"
},
"order": {
"buyer": {
"referenceBuyerId": "referenceBuyerId001"
},
"orderAmount": {
"currency": "CNY",
"value": "100"
},
"orderDescription": "orderDescription001",
"referenceOrderId": "referenceOrderId001"
},
"paymentAmount": {
"currency": "CNY",
"value": "100"
},
"paymentMethod": {
"paymentMethodType": "ALIPAY_CN"
},
"paymentNotifyUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/record/notify?env=main_online&paymentMethodType=ALIPAY_CN",
"paymentRedirectUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/result",
"paymentRequestId": "paymentRequestId001",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}The following code shows a sample of the response message:
{
"paymentSessionData": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3cjK3CVpnMXY7BfQlIvwNqQWtXHEMUo0R5pQwnSyNtxTA==&&SG&&188&&eyJh***",
"paymentSessionExpiryTime": "2024-09-27T15:57:30+08:00",
"paymentSessionId": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3fI21eGbgq240lFVquZsLrM",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}Please take the next step according to the value of the result.resultStatus.
resultStatus | Message | Further actions |
S | The payment session is successfully created. | Return the obtained paymentSessionData to the merchant's frontend. For specific operational steps, refer to Step 4. |
F | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
U | The payment session creation failed due to unknown reasons. | Replace the paymentRequestId and authstate value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |
Note: If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new paymentRequestId and authstate value.
Subsequent payments
public static void createPaymentSession() {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// replace with your paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// set amount
// you should convert amount unit(in practice, amount should be calculated on your server side)
Amount amount = Amount.builder().currency("HKD").value("98080").build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
//set settlement currency
SettlementStrategy settlementStrategy = new SettlementStrategy();
settlementStrategy.setSettlementCurrency("USD");
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
// set paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder()
.paymentMethodType("ALIPAY_HK")
.paymentMethodId("28288803001319861727421828000Cv96OFlYoi17100****")
.build();
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// set buyer info
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// replace with your orderId
String orderId = UUID.randomUUID().toString();
// set order Info
Order order = Order.builder()
.referenceOrderId(orderId)
.orderDescription("antom api testing order")
.orderAmount(amount)
.buyer(buyer)
.build();
alipayPaymentSessionRequest.setOrder(order);
// replace with your notify url
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com");
// replace with your redirect url
alipayPaymentSessionRequest.setPaymentRedirectUrl("http://www.yourRedirectUrl.com");
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
} catch (AlipayApiException e) {
String errorMsg = e.getMessage();
// handle error condition
}
}
The following code shows a sample of the request message:
{
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "HKD",
"value": "98080"
},
"orderDescription": "antom api testing order",
"referenceOrderId": "5e445b58-49ad-4552-a36d-d38f311a090d"
},
"paymentAmount": {
"currency": "HKD",
"value": "98080"
},
"paymentMethod": {
"paymentMethodId": "28288803001319861727421828000Cv96OFlYoi17100****",
"paymentMethodType": "ALIPAY_HK"
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com",
"paymentRedirectUrl": "http://www.yourRedirectUrl.com",
"paymentRequestId": "5810a84e-3a3e-4e47-bbac-9dfe3f2dd2b3",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}The following code shows a sample of the response message:
{
"paymentSessionData": "paymentSessionData****",
"paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
"paymentSessionId": "paymentSessionId****",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}Please take the next step according to the value of the result.resultStatus.
resultStatus | Message | Further actions |
S | The payment session is successfully created. | Return the obtained paymentSessionData to the merchant's frontend. For specific operational steps, refer to Step 4. |
F | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
U | The payment session creation failed due to unknown reasons. | Replace the paymentRequestId value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |
Note: If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new paymentRequestId value.
Common questions
Q: Can I use Chinese characters in the value of the request parameters?
A: To avoid incompatibility of a certain payment method, do not use Chinese characters for parameters in the request.
Q: How to set the URL to receive the payment notification?
A: Specify paymentNotifyUrl in the createPaymentSession (EasySafePay) API to receive the asynchronous notification about the payment result (notifyPayment), or configure the receiving URL in Antom Dashboard. If the URL is specified in both the request and Antom Dashboard, the value specified in the request takes precedence.
Q: What is the difference between paymentAmount and orderAmount?
A: paymentAmount refers to the payment amount, while orderAmount refers to the order amount. The actual charged amount is determined by paymentAmount.
A: paymentAmount refers to the payment amount, while orderAmount refers to the order amount. The actual charged amount is determined by paymentAmount.
Q: What does paymentSessionExpiryTime specifically refer to in payment requests?
A: paymentSessionExpiryTime indicates the validity period from successful payment session creation until the buyer submits the payment. After submission, the payment processing timeout is 10 minutes. Therefore, the maximum total duration from session creation to payment completion is 1 hour and 10 minutes.
A: paymentSessionExpiryTime indicates the validity period from successful payment session creation until the buyer submits the payment. After submission, the payment processing timeout is 10 minutes. Therefore, the maximum total duration from session creation to payment completion is 1 hour and 10 minutes.
Q: Which parameters should be prioritized in the response message?
A: Pay attention to the following key parameters:
A: Pay attention to the following key parameters:
- result.resultStatus: Indicates the result of the API call.
- paymentSessionData: Encrypted payment session data, which is passed to the frontend for initializing the Antom SDK.
- paymentSessionExpiryTime: Expiration timestamp of the payment session.
Step 3: Invoke the SDK Client-side
After obtaining the paymentSessionData value on the merchant server side, the merchant client can invoke the SDK to redirect the checkout page to the payment method authorization page. When the buyer submits a payment request, the SDK will automatically handle encrypted communication, risk control verification, page redirection, and payment instruction execution, enabling an end-to-end payment authorization process.
1. Instantiate the SDK
- Use AMSEasyPayto create the SDK instance. The configuration object includes the following parameters:
Parameter name | Required | Description |
environment | Yes | Used to specify the environment information. Valid values are:
|
locale | No | Used to specify the language information. Select the appropriate value based on the region of the payment method. Valid values for this parameter are listed as follows.If a value not in the following list is used, the English is used instead.
|
onEventCallback | No | A callback function that returns a specific event code when a payment event occurs during SDK runtime. Note: After a successful payment, the payment result is not returned by this function by default; instead, the user is redirected to the payment success page you specified. However, when notRedirectAfterComplete is set to true and the payment process is completed within the SDK, the system will not perform a redirect after a successful payment but will instead provide an event callback. |
The following sample code shows how to instantiate the SDK using npm or CDN:
npm
import { AMSEasyPay } from "@alipay/ams-checkout"; // Manage the package
const checkoutApp = new AMSEasyPay({
environment: "sandbox",
locale: "en_US",
onEventCallback: ({ code, message }) => {},
});
CDN
const checkoutApp = new window.AMSEasyPay({
environment: "sandbox",
locale: "en_US",
onEventCallback: ({ code, message }) => {},
});
- Use createComponent in the instance object to create a payment component. The parameters involved are as follows:
Parameter name | Required | Description |
sessionData | Yes | Create a configuration object using the sessionData parameter: Use the complete data of the value of paymentSessionData obtained in the response of the createPaymentSession (EasySafePay) API as the value of this parameter. |
notRedirectAfterComplete | No | Boolean type. Valid values are:
Note:
|
The following sample code shows how to create the component:
async function create(sessionData) {
await checkoutApp.createComponent({
sessionData: sessionData,
notRedirectAfterComplete: false, // Set as false by default to indicate that it will redirect to your page after the payment is completed.
});
}The images below show the rendering effect when the SDK redirects the checkout page to the payment method authorization page:
Web
The image below shows the redirection from the merchant checkout page to the payment method page.
WAP
The image below shows the merchant checkout page launches a half-screen pop-up or redirects to the digital wallet app.
2. Handle SDK callback event codes
Below are the event codes returned by onEventCallback and handling recommendations:
Code | Description | Further action |
SDK_CALL_URL_SUCCESS | Successfully launched the payment method app or redirected to the merchant page. | No further action is needed. |
SDK_LAUNCH_PAYMENT_APP_ERROR | This event code indicates one of the following situations:
| Check whether the paymentRedirectUrl parameter is correctly passed when calling the createPaymentSession (EasySafePay) API. Web/WAP scenarios rarely experience redirection exceptions. However, in the event of any exceptions, it is recommended to verify the redirection link. For mobile app scenarios, if frequent redirection exceptions occur, contact Antom Technical Support to troubleshoot redirection or cross-application calling issues. |
SDK_PAYMENT_CANCEL | The buyer canceled the payment (the buyer exited the payment page without submitting the order). | You can re-invoke the SDK using paymentSessionData within its validity period; If it has expired, you need to initiate a new createPaymentSession (EasySafePay) request. |
SDK_PAYMENT_SUCCESSFUL | Indicates that the payment is successful on the wallet side. | Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. Suggest redirecting buyers to the payment result page. Note: This event code is returned only when the payment process is completed within the SDK. |
SDK_PAYMENT_FAIL | Indicates that the payment is unsuccessful on the wallet side. | Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. Suggest redirecting buyers to the payment result page. Note: This event code is returned only when the payment process is completed within the SDK. |
The following sample code shows how to handle the callback function:
// Step 2: Create onEventCallback handler.
function onEventCallback({ code }) {
switch (code) {
case "SDK_PAYMENT_CANCEL":
console.log(
"The buyer canceled the payment (the buyer exited the payment page without submitting the order). You can re-invoke the SDK using paymentSessionData within its validity period; If it has expired, you need to initiate a new createPaymentSession (EasySafePay) request.",
);
break;
case "SDK_CALL_URL_SUCCESS":
console.log(
"Successfully launched the payment method app or redirected to the merchant page.",
);
break;
case "SDK_LAUNCH_PAYMENT_APP_ERROR":
console.log(
"Failed to redirect to the checkout page of the payment method, or failed to redirect to the merchant page. Check whether the paymentRedirectUrl parameter is correctly passed when calling the createPaymentSession (EasySafePay) request. Web/WAP scenarios rarely experience redirection exceptions. However, in the event of any exceptions, it is recommended to verify the redirection link.",
);
break;
case "SDK_PAYMENT_SUCCESSFUL":
console.log(
"The wallet has successfully processed the payment. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. Suggest redirecting buyers to the payment result page.",
);
break;
case "SDK_PAYMENT_FAIL":
console.log(
"The wallet failed to process the payment. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. Suggest redirecting buyers to the payment result page.",
);
break;
default:
console.log(code);
}
}3. Free SDK component resources
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 (EasySafePay) API.
- When the buyer initiates multiple payments, free the component resources created in the previous createPaymentSession (EasySafePay) API.
- After obtaining the final payment result, free the component resources.
The following sample code shows how to free components:
// Free SDK component resources
checkoutApp.unmount();Common questions
Q: Can an AMSEasyPay instance execute createComponent multiple times?
A: No. If you need to initiate a new payment, you need to create a new AMSEasyPay instance.
A: No. If you need to initiate a new payment, you need to create a new AMSEasyPay instance.
Q: Are SDK calls required for both first and subsequent payments?
A: Yes.
A: Yes.
iOS
User experience
This iOS integration guide is designed to help you quickly integrate the digital wallet and online banking payment functions within the app and easily complete the payment interface rendering.
The user experience of each payment method on the iOS side varies; refer to the table below for specific interaction experiences:
Payment method category | Payment method | Terminal type | First-time payment | Subsequent payments |
Digital wallet | iOS | Complete the payment on the merchant page. | Complete the payment on the merchant page. | |
iOS | Redirect to the payment method app to complete payment. | Complete the payment on the merchant page. | ||
Online banking | iOS | Complete the payment on the merchant page. | Complete the payment on the merchant page. |
Digital wallet
Below is the user experience for first and subsequent payments using digital wallets.
First payment
Upon the first payment, the buyer can choose to pay immediately or complete the authorization process. After successful authorization, subsequent payments will be processed by the password-free feature.
Pay on the merchant page
Pay on the payment method app
Subsequent payments
Subsequent payments are processed without requiring a password upon order submission.
Online banking
Below is the user experience for first and subsequent payments using online banking payment methods.
First payment
Upon the first payment, the buyer can choose to pay immediately or complete the authorization process. After successful authorization, subsequent payments will be processed by the password-free feature.
Subsequent payments
Subsequent payments are processed without requiring a password upon order submission.
Payment flow
First payment
The first payment flow chart:
- The buyer enters the checkout page.
- Create a payment session request.
After the buyer selects a payment method and submits the order, you can obtain the payment session by calling the createPaymentSession (EasySafePay) API. - Invoke the client SDK.
Invoke the SDK using a payment session and the SDK will automatically collect payment elements, render the payment interface, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics. For detailed interaction differences across payment methods, refer to the User experience table. - Obtain the authorization result.
When the authorization is successful, Antom sends you the asynchronous notification through the notifyAuthorization API. - Obtain the payment result.
Obtain the payment result using one of the following methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (EasySafePay) API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use notifyPayment to send asynchronous notifications to you.
- Synchronous inquiry: Call the inquiryPayment API to check the real-time payment status.
Subsequent payments
The subsequent payment flow chart:
- The buyer enters the checkout page.
- Create a payment session request.
After the buyer selects a payment method and submits the order, you can obtain the payment session by calling the createPaymentSession (EasySafePay) API. - Invoke the client SDK.
Invoke the SDK using a payment session and the SDK will automatically collect payment elements, render the payment interface, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics. For detailed interaction differences across payment methods, refer to the User experience table. - Obtain the payment result.
Obtain the payment result using one of the following methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (EasySafePay) API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use notifyPayment to send asynchronous notifications to you.
- Synchronous inquiry: Call the inquiryPayment API to check the real-time payment status.
Integration preparations
Before you start integrating, read the Integration Guide and API Overview documents to understand the integration steps of the server-side API and the precautions for calling the API. Furthermore, ensure that the following prerequisites are met:
- Obtain a client ID
- Complete the key configuration
- Complete the configuration of paymentNotifyUrl to receive the asynchronous notification
- Integrate the server-side SDK package, install the server-side library, and initialize a request instance. For more details, refer to Server-side SDKs.
- If you need to conduct joint debugging by connecting the sandbox with the production environment, please contact Antom technical support at least two business days in advance to request configuration. The sandbox environment and production environment require separate configuration.
Integration steps
Start your integration by taking the following steps:
- (Optional) Preload the SDK
- Create a payment session
- Invoke the SDK
- Obtain the authorization and payment result
(Optional) Step 1: Preload the SDK Client-side
Preloading the SDK during the checkout page initialization significantly improves the rendering performance with no negative impact. It is recommended to trigger preloading of the SDK when the buyer selects a payment method.
Follow the code example below to perform the preloading:
[AMSEasyPay.shared preload];Step 2: Create a payment session Server-side
When a buyer selects a payment method provided by Antom, you need to collect essential information including the payment request ID, order amount, payment method, order description, payment redirect page URL, and payment result notification URL.
Call the createPaymentSession (EasySafePay) API to create a payment session and initialize the Antom SDK using the paymentSessionData value returned in the response.
The table below lists the parameter specifications for calling the createPaymentSession (EasySafePay) API during the first and subsequent payments:
Note: For subsequent payments with Express Bank Transfer, simply keep the parameters consistent with the first payment. The buyer can open the Express Bank Transfer webpage and enter the phone number to proceed directly with the payment.
Parameter type | Parameter name | Required (First-time payment) | Required (Subsequent payments) | Description |
Base parameter | productCode | Yes | Yes | The value is fixed as AGREEMENT_PAYMENT in the EasySafePay scenario. |
productScene | Yes | Yes | The value is fixed as EASY_PAY in the EasySafePay scenario. | |
paymentRequestId | Yes | Yes | The unique ID assigned by a merchant to identify a payment request. | |
paymentMethod.paymentMethodType | Yes | Yes | ||
paymentMethod.paymentMethodId | No | Yes | The unique ID that is used to identify a payment method. The value of this parameter is that of accessToken from the notifyAuthorization API. | |
settlementStrategy | No | No | The settlement strategy for the payment request. If the merchant agreement supports multiple settlement currencies, they must be specified in the API request. | |
paymentAmount.value | Yes | Yes | The value of the amount as a positive integer in the smallest currency unit. | |
paymentAmount.currency | Yes | Yes | ||
paymentSessionExpiryTime | No | No | The specific date and time after which the payment session will expire. The default expiration time is 1 hour after the session creation. For example, if the session is created at 2023-7-27T12:00:01+08:30, the session expiration time is 2023-7-27T13:00:01+08:30. | |
paymentRedirectUrl | Yes | Yes | The merchant page URL that the user is redirected to after the payment is completed. The page display according to the server-side result and should not default to a fixed payment success page.
| |
paymentNotifyUrl | No | No | The URL that is used to receive the payment result notification. it must be an HTTPS URL. This field can be omitted if already configured via Antom Dashboard. | |
Authorization parameter | agreementInfo.authState | Yes | No | The unique ID generated by the merchant to initiate an EasySafePay authorization. |
Order parameter | order.orderAmount | Yes | Yes | The order amount of the merchant that directly provides services or goods to the customer |
order.referenceOrderId | Yes | Yes | The unique ID to identify the order on the merchant side. | |
order.orderDescription | Yes | Yes | Summary description of the order. | |
order.buyer.referenceBuyerId | No | No | Submit buyer information for risk assessment. Provide at least one of these fields: referenceBuyerId, buyerPhoneNo, or buyerEmail. | |
order.buyer.
| No | No | Buyer's account. Providing relevant payment account information can effectively improve the payment success rate and reduce the risk of buyer attrition. Please refer to the table below for specific format requirements. |
The parameter format for the buyer's payment account for each payment method is as follows:
Payment method | Parameter format |
It is recommended to prioritize using a mobile phone number:
| |
62-8569****7288. The phone number starts with 8 and is no more than 12 digits long, excluding the prefix. | |
TrueMoney | The buyer is authenticated on the payment method side, and no parameters need to be passed in.userloginId. |
During the first-time payment, passing the buyer's payment account will auto-fill the buyer's account on the payment page, eliminating manual input. Below is a comparison of the user experience with and without these fields:
With account parameter passed
Login account input is not required.
Without account parameter passed
Manual input of login account is required.
Below are code examples for first and subsequent payments.
First payment
@PostMapping("/payment/createSession")
public ResponseEntity<ApiResponse> createPaymentSession(@RequestBody PaymentVO payment) {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// replace with your paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// convert amount unit(in practice, amount should be calculated on your server side)
// For details, refer to: <a href="https://docs.antom.com/ac/ref/cc">Usage rules of the Amount object</a>
long amountMinorLong = Money.of(CurrencyUnit.of(payment.currency), new BigDecimal(payment.amountValue)).getAmountMinorLong();
// set amount
Amount amount = Amount.builder().currency(payment.currency).value(String.valueOf(amountMinorLong)).build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
// set settlement strategy
// replace with your existing settlement currency
SettlementStrategy settlementStrategy = SettlementStrategy.builder().settlementCurrency("USD").build();
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
User loginUser = users.get(payment.getUserId());
// set paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType(payment.paymentMethodType).build();
if (loginUser.getPaymentMethodTypeAccessToken().containsKey(payment.getPaymentMethodType())) {
// buyer has authorized
String accessToken = loginUser.getPaymentMethodTypeAccessToken().get(payment.getPaymentMethodType());
paymentMethod.setPaymentMethodId(accessToken);
} else {
// set agreementInfo
// replace with your authState
String authState = UUID.randomUUID().toString();
// The login ID that the buyer used to register in the payment method client. The login ID can be the buyer's email address or phone number.
// Specify this parameter to free buyers from manually entering their login IDs.
String userLoginId = loginUser.getPhoneNumber();
AgreementInfo agreementInfo = AgreementInfo.builder().authState(authState).userLoginId(userLoginId).build();
alipayPaymentSessionRequest.setAgreementInfo(agreementInfo);
// save the paymentMethodType corresponding to the authState
authStatePayment.put(authState, payment);
}
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// set buyer info
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// replace with your orderId
String orderId = UUID.randomUUID().toString();
// set order Info
Order order = Order.builder().referenceOrderId(orderId)
.orderDescription("antom sdk testing order").orderAmount(amount).buyer(buyer).build();
alipayPaymentSessionRequest.setOrder(order);
// replace with your notify url
// or configure your notify url here: <a href="https://dashboard.antom.com/global-payments/developers/iNotify">Notification URL</a>
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com/payment/receivePaymentNotify");
// replace with your redirect url
alipayPaymentSessionRequest.setPaymentRedirectUrl(
"http://localhost:8080/index.html?paymentRequestId=" + paymentRequestId);
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
long startTime = System.currentTimeMillis();
System.out.println("payment request: " + JSON.toJSONString(alipayPaymentSessionRequest));
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
System.out.println("payment response: " + JSON.toJSONString(alipayPaymentSessionResponse));
System.out.println("payment request cost time: " + (System.currentTimeMillis() - startTime) + "ms
");
} catch (AlipayApiException e) {
return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), e));
}
return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), alipayPaymentSessionResponse));
}The following code shows a sample of the request message:
{
"agreementInfo": {
"authState": "authState001",
"userLoginId": "userLoginId001"
},
"order": {
"buyer": {
"referenceBuyerId": "referenceBuyerId001"
},
"orderAmount": {
"currency": "CNY",
"value": "100"
},
"orderDescription": "orderDescription001",
"referenceOrderId": "referenceOrderId001"
},
"paymentAmount": {
"currency": "CNY",
"value": "100"
},
"paymentMethod": {
"paymentMethodType": "ALIPAY_CN"
},
"paymentNotifyUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/record/notify?env=main_online&paymentMethodType=ALIPAY_CN",
"paymentRedirectUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/result",
"paymentRequestId": "paymentRequestId001",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}The following code shows a sample of the response message:
{
"paymentSessionData": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3cjK3CVpnMXY7BfQlIvwNqQWtXHEMUo0R5pQwnSyNtxTA==&&SG&&188&&eyJh***",
"paymentSessionExpiryTime": "2024-09-27T15:57:30+08:00",
"paymentSessionId": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3fI21eGbgq240lFVquZsLrM",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}Please take the next step according to the value of the result.resultStatus.
resultStatus | Message | Further actions |
S | The payment session is successfully created. | Return the obtained paymentSessionData to the merchant's frontend. For specific operational steps, refer to Step 4. |
F | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
U | The payment session creation failed due to unknown reasons. | Replace the paymentRequestId and authstate value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |
Note: If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new paymentRequestId and authstate value.
Subsequent payments
public static void createPaymentSession() {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// replace with your paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// set amount
// you should convert amount unit(in practice, amount should be calculated on your server side)
Amount amount = Amount.builder().currency("HKD").value("98080").build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
//set settlement currency
SettlementStrategy settlementStrategy = new SettlementStrategy();
settlementStrategy.setSettlementCurrency("USD");
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
// set paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder()
.paymentMethodType("ALIPAY_HK")
.paymentMethodId("28288803001319861727421828000Cv96OFlYoi17100****")
.build();
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// set buyer info
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// replace with your orderId
String orderId = UUID.randomUUID().toString();
// set order Info
Order order = Order.builder()
.referenceOrderId(orderId)
.orderDescription("antom api testing order")
.orderAmount(amount)
.buyer(buyer)
.build();
alipayPaymentSessionRequest.setOrder(order);
// replace with your notify url
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com");
// replace with your redirect url
alipayPaymentSessionRequest.setPaymentRedirectUrl("http://www.yourRedirectUrl.com");
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
} catch (AlipayApiException e) {
String errorMsg = e.getMessage();
// handle error condition
}
}
The following code shows a sample of the request message:
{
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "HKD",
"value": "98080"
},
"orderDescription": "antom api testing order",
"referenceOrderId": "5e445b58-49ad-4552-a36d-d38f311a090d"
},
"paymentAmount": {
"currency": "HKD",
"value": "98080"
},
"paymentMethod": {
"paymentMethodId": "28288803001319861727421828000Cv96OFlYoi17100****",
"paymentMethodType": "ALIPAY_HK"
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com",
"paymentRedirectUrl": "http://www.yourRedirectUrl.com",
"paymentRequestId": "5810a84e-3a3e-4e47-bbac-9dfe3f2dd2b3",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}The following code shows a sample of the response message:
{
"paymentSessionData": "paymentSessionData****",
"paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
"paymentSessionId": "paymentSessionId****",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}Please take the next step according to the value of the result.resultStatus.
resultStatus | Message | Further actions |
S | The payment session is successfully created. | Return the obtained paymentSessionData to the merchant's frontend. For specific operational steps, refer to Step 4. |
F | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
U | The payment session creation failed due to unknown reasons. | Replace the paymentRequestId value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |
Note: If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new paymentRequestId value.
Common questions
Q: Can I use Chinese characters in the value of the request parameters?
A: To avoid incompatibility of a certain payment method, do not use Chinese characters for parameters in the request.
Q: How to set the URL to receive the payment notification?
A: Specify paymentNotifyUrl in the createPaymentSession (EasySafePay) API to receive the asynchronous notification about the payment result (notifyPayment), or configure the receiving URL in Antom Dashboard. If the URL is specified in both the request and Antom Dashboard, the value specified in the request takes precedence.
Q: What is the difference between paymentAmount and orderAmount?
A: paymentAmount refers to the payment amount, while orderAmount refers to the order amount. The actual charged amount is determined by paymentAmount.
A: paymentAmount refers to the payment amount, while orderAmount refers to the order amount. The actual charged amount is determined by paymentAmount.
Q: What does paymentSessionExpiryTime specifically refer to in payment requests?
A: paymentSessionExpiryTime indicates the validity period from successful payment session creation until the buyer submits the payment. After submission, the payment processing timeout is 10 minutes. Therefore, the maximum total duration from session creation to payment completion is 1 hour and 10 minutes.
A: paymentSessionExpiryTime indicates the validity period from successful payment session creation until the buyer submits the payment. After submission, the payment processing timeout is 10 minutes. Therefore, the maximum total duration from session creation to payment completion is 1 hour and 10 minutes.
Q: Which parameters should be prioritized in the response message?
A: Pay attention to the following key parameters:
A: Pay attention to the following key parameters:
- result.resultStatus: Indicates the result of the API call.
- paymentSessionData: Encrypted payment session data, which is passed to the frontend for initializing the Antom SDK.
- paymentSessionExpiryTime: Expiration timestamp of the payment session.
Step 3: Invoke the SDK Client-side
After obtaining the paymentSessionData value on the merchant server side, the merchant client can invoke the SDK to redirect the checkout page to the payment method authorization page. When the buyer submits a payment request, the SDK will automatically handle encrypted communication, risk control verification, page redirection, and payment instruction execution, enabling an end-to-end payment authorization process.
1. Instantiate the SDK
- Use AMSEasyPayConfigurationto create the SDK instance. The configuration object includes the following parameters:
Parameter name | Required | Description |
locale | No | Used to specify the language information. Select the appropriate value based on the region of the payment method. Valid values for this parameter are listed as follows. If a value not in the following list is used, English is used instead.
|
options | No | Used to specify whether to use the sandbox environment. Valid values are:
Note:
|
fromScheme | No | In the Alipay scenario, when a buyer completes payment in the Alipay wallet, the system will redirect back to your merchant app according to the exampleForScheme configuration. Note: In the iOS Native environment, Alipay only supports redirecting to the app's launch page specified by componentConfig.fromScheme, rather than the paymentRedirectUrl specified in the createPaymentSession (EasySafePay) API. The specific redirect page needs to be controlled through the event code. |
- Create an instance of the AMSPaymentProtocol API to process the payment callback result, which includes the following method:
Method | Required | Description |
onEventCallback | No | A callback function that monitors payment events on the checkout page, returning eventCode and eventResult. The payment success result will not be returned by this callback function by default. A redirection to the payment success result page that you specified will take place instead. However, when notRedirectAfterComplete is set to true, the system will not perform redirection upon payment completion, instead it will provide event callback. Note: When integrating with Alipay, if you invoke processOrderWithPaymentResult, you will receive the payment event codes returned by onEventCallback. If you do not invoke processOrderWithPaymentResult, payment event codes will not be returned, but you can query the payment result by calling the inquiryPayment API on the server. |
The following sample code shows how to instantiate the SDK:
#import <AMSComponent/AMSComponent-Swift.h>
AMSEasyPayConfiguration *componentConfig = [AMSEasyPayConfiguration new];
// Alipay needs to add fromScheme. Note that this address refers to the corresponding APP startup page after the payment is completed.
componentConfig.fromScheme = @"exampleForScheme";
componentConfig.locale = @"en_US";
// Set the sandbox environment. If you leave it empty, the production environment is used by default.
NSDictionary *options = @{@"sandbox": @"true",
@"notRedirectAfterComplete": @"false"};
componentConfig.options = options;
[[AMSEasyPay shared] initConfiguration:componentConfig];
// Set the callback to monitor payment events on the checkout page.
[AMSEasyPay shared].paymentDelegate = self;
#pragma AMSPaymentProtocol
- (void)onEventCallback:(NSString *)eventCode eventResult:(AMSEventResult *)eventResult
{
NSLog(@"eventCode%@ eventResult%@", eventCode, eventResult);
}
The following image shows the rendering effect of the merchant checkout page invoking a half-screen pop-up or redirecting to the digital wallet app:
- Use the createComponent method in the instance object to create a payment component, which includes the following parameter:
Parameter name | Required | Description |
sessionData | Yes | Create a configuration object using the sessionData parameter: Use the complete data of the value of paymentSessionData obtained in the response of the createPaymentSession (EasySafePay) API as the value of this parameter. |
The sample code is as follows:
[[AMSEasyPay shared] createComponent:sessionData];2. Handle SDK callback event codes
Below are the event codes returned by onEventCallback and handling recommendations:
Type | Code | Description | Further action |
Status code | SDK_CALL_URL_SUCCESS | This event code indicates that redirect successfully for the paymentRedirectUrl. | Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. |
SDK_PAYMENT_CANCEL | The buyer canceled the payment (the buyer exited the payment page without submitting the order). | You can re-invoke the SDK using paymentSessionData within its validity period; If it has expired, you need to initiate a new createPaymentSession (EasySafePay) API. | |
SDK_PAYMENT_SUCCESSFUL | Indicates that the wallet has successfully processed the payment. | Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. Note: For payment solutions not integrated with Alipay, suggest redirecting users to the payment result page. | |
SDK_PAYMENT_FAIL | Indicates that the wallet failed to process the payment. | Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. Note: For payment solutions not integrated with Alipay, suggest redirecting users to the payment result page. | |
SDK_PAYMENT_PROCESSING (Returned when integrated with Alipay) | Indicates that the payment status of the Alipay walletis unknown. | Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. | |
SDK_PAYMENT_ERROR (Returned when integrated with Alipay) | Indicates that the payment processing of the Alipay wallet is abnormal. | Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. | |
Error code | SDK_CREATEPAYMENT_PARAMETER_ERROR | The parameters passed to the createComponent method are not correct. | Check if the parameters are correct and re-initialize the component. |
SDK_STATUS_ERROR | This event code indicates one of the following situations:
| Please check the result message, then match the errorsituations. | |
SDK_INTEGRATION_ERROR | This event code indicates thatsome dependencies of SDK is not exist. Currently there are two scenario:
| Please check whether target module has been integrated. | |
SDK_LAUNCH_PAYMENT_APP_ERROR | This event code indicates one of the following situations:
| Check whether the paymentRedirectUrl parameter is correctly passed when calling the createPaymentSession (EasySafePay) API. If frequent redirection exceptions occur, contact Antom Technical Support to troubleshoot redirection or cross-application calling issues. |
The following sample code shows how to handle the callback function:
-(void)onEventCallback:(NSString *)eventCode eventResult:(AMSEventResult *)eventResult {
if ([[_selectMethod title] isEqualToString:@"ALIPAY_CN"]) {
if ([eventCode isEqualToString:@"SDK_PAYMENT_CANCEL"]) {
NSLog(@"The buyer canceled the payment (the buyer exited the payment page without submitting the order). You can re-invoke the SDK using paymentSessionData within its validity period; If it has expired, you need to initiate a new createPaymentSession (EasySafePay) request.");
} else if ([eventCode isEqualToString:@"SDK_PAYMENT_SUCCESSFUL"]) {
NSLog(@"The Alipay wallet has successfully processed the payment. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result.");
} else if ([eventCode isEqualToString:@"SDK_PAYMENT_FAIL"]) {
NSLog(@"The Alipay wallet failed to process the payment. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result.");
} else if ([eventCode isEqualToString:@"SDK_PAYMENT_PROCESSING"]) {
NSLog(@"The payment status of the Alipay wallet is unknown. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result.");
} else if ([eventCode isEqualToString:@"SDK_PAYMENT_ERROR"]) {
NSLog(@"The payment processing of the Alipay wallet is abnormal. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result.");
} else {
NSLog(@"eventCode%@ eventResult%@", eventCode, eventResult);
}
} else {
// Please note that payment success will not be notified through this callback function, but will instead redirect to the success result page you specified.
if ([eventCode isEqualToString:@"SDK_PAYMENT_CANCEL"]) {
NSLog(@"The buyer canceled the payment (the buyer exited the payment page without submitting the order). You can re-invoke the SDK using paymentSessionData within its validity period; If it has expired, you need to initiate a new createPaymentSession (EasySafePay) request.");
} else if ([eventCode isEqualToString:@"SDK_CALL_URL_SUCCESS"]) {
NSLog(@"Open wallet app or redirect to the merchant page successfully.");
} else if ([eventCode isEqualToString:@"SDK_LAUNCH_PAYMENT_APP_ERROR"]) {
NSLog(@"Open wallet app or redirect to the merchant page failed");
} else if ([eventCode isEqualToString:@"SDK_CREATEPAYMENT_PARAMETER_ERROR"]) {
NSLog(@"The input parameter provided is invalid. Please check the value and try again.");
} else {
NSLog(@"eventCode%@ eventResult%@", eventCode, eventResult);
}
}
}
3. Free SDK component resources
Call the onDestroy method to free SDK component resources in the following situations:
- When the buyer exits the checkout page, completely free the component resources created in the createPaymentSession (EasySafePay) API.
- When the buyer initiates multiple payments, and the parameters in initConfiguration have changed, free the component resources created in the previous createPaymentSession (EasySafePay) API.
In the following scenario, you do not need to call onDestroy, and the SDK will automatically free partial resources (for iOS SDK AMSComponents 1.33.0 or above).
- When the buyer initiates multiple payments, and the parameters in initConfiguration have not changed. The SDK will automatically free partial resources after the payment is completed to reset to the state before createComponent was called.
The following sample code shows how to free components:
// Completely free SDK component resources
[[AMSEasyPay shared] onDestroy];Common questions
Q: Is it mandatory to handle SDK callback events?
A: For Alipay, you must process event codes to display payment results, but this payment method is optional. Callback events can also be used for logging.
A: For Alipay, you must process event codes to display payment results, but this payment method is optional. Callback events can also be used for logging.
Q: Can an AMSEasypay instance execute createComponent multiple times?
A: No. You need to create a freshAMSEasypay instance to initiate a new payment.
A: No. You need to create a freshAMSEasypay instance to initiate a new payment.
Q: Are SDK calls required for both first-time and subsequent payments?
A: Yes.
A: Yes.
4. Receive notification from callback function (When integrating Alipay)
When integrating with Alipay, the merchant-client can receive notifications from the callback function. After receiving the callback notification, use the openURL method in the AppDelegate file to handle the result returned by Alipay:
- Use canProcessOrderWithPaymentResult() to check whether the redirect URL, to redirect from the wallet to the merchant side, is valid.
- Use processOrderWithPaymentResult() to handle the redirection from the wallet to the merchant's side.
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
if ([url.scheme isEqualToString:@"exampleForScheme"]) {
if ([[AMSEasyPay shared] canProcessOrderWithPaymentResult:url]) {
[[AMSEasyPay shared] processOrderWithPaymentResult:url];
}
}
return YES;
}Android
User experience
This Android integration guide is designed to help you quickly integrate the digital wallet and online banking payment functions within the app and easily complete the payment interface rendering.
The user experience of each payment method on the Android side varies; refer to the table below for specific interaction experiences:
Payment method category | Payment method | Terminal type | First-time payment | Subsequent payments |
Digital wallet | Android | Complete the payment on the merchant page. | Complete the payment on the merchant page. | |
Android | Redirect to the payment method app to complete payment. | Complete the payment on the merchant page. | ||
Online banking | Android | Complete the payment on the merchant page. | Complete the payment on the merchant page. |
Digital wallet
Below is the user experience for first and subsequent payments using digital wallets.
First payment
Upon the first payment, the buyer can choose to pay immediately or complete the authorization process. After successful authorization, subsequent payments will be processed by the password-free feature.
Pay on the merchant page
Pay on the payment method app
Subsequent payments
Subsequent payments are processed without requiring a password upon order submission.
Online banking
Below is the user experience for first and subsequent payments using online banking payment methods.
First payment
Upon the first payment, the buyer can choose to pay immediately or complete the authorization process. After successful authorization, subsequent payments will be processed by the password-free feature.
Subsequent payments
Subsequent payments are processed without requiring a password upon order submission.
Payment flow
First payment
The first payment flow chart:
- The buyer enters the checkout page.
- Create a payment session request.
After the buyer selects a payment method and submits the order, you can obtain the payment session by calling the createPaymentSession (EasySafePay) API. - Invoke the client SDK.
Invoke the SDK using a payment session and the SDK will automatically collect payment elements, render the payment interface, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics. For detailed interaction differences across payment methods, refer to the User experience table. - Obtain the authorization result.
When the authorization is successful, Antom sends you the asynchronous notification through the notifyAuthorization API. - Obtain the payment result.
Obtain the payment result using one of the following methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (EasySafePay) API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use notifyPayment to send asynchronous notifications to you.
- Synchronous inquiry: Call the inquiryPayment API to check the real-time payment status.
Subsequent payments
The subsequent payment flow chart:
- The buyer enters the checkout page.
- Create a payment session request.
After the buyer selects a payment method and submits the order, you can obtain the payment session by calling the createPaymentSession (EasySafePay) API. - Invoke the client SDK.
Invoke the SDK using a payment session and the SDK will automatically collect payment elements, render the payment interface, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics. For detailed interaction differences across payment methods, refer to the User experience table. - Obtain the payment result.
Obtain the payment result using one of the following methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (EasySafePay) API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use notifyPayment to send asynchronous notifications to you.
- Synchronous inquiry: Call the inquiryPayment API to check the real-time payment status.
Integration preparations
Before you start integrating, read the Integration Guide and API Overview documents to understand the integration steps of the server-side API and the precautions for calling the API. Furthermore, ensure that the following prerequisites are met:
- Obtain a client ID
- Complete the key configuration
- Complete the configuration of paymentNotifyUrl to receive the asynchronous notification
- Integrate the server-side SDK package, install the server-side library, and initialize a request instance. For more details, refer to Server-side SDKs.
- If you need to conduct joint debugging by connecting the sandbox with the production environment, please contact Antom technical support at least two business days in advance to request configuration. The sandbox environment and production environment require separate configuration.
Integration steps
Start your integration by taking the following steps:
- (Optional) Preload the SDK
- Create a payment session
- Invoke the SDK
- Obtain the authorization and payment result
(Optional) Step 1: Preload the SDK Client-side
Preloading the SDK during the checkout page initialization significantly improves the rendering performance with no negative impact. It is recommended to trigger preloading of the SDK when the buyer selects a payment method.
Follow the code example below to perform the preloading:
AMSEasyPay.preload(getApplicationContext());Step 2: Create a payment session Server-side
When a buyer selects a payment method provided by Antom, you need to collect essential information including the payment request ID, order amount, payment method, order description, payment redirect page URL, and payment result notification URL.
Call the createPaymentSession (EasySafePay) API to create a payment session and initialize the Antom SDK using the paymentSessionData value returned in the response.
The table below lists the parameter specifications for calling the createPaymentSession (EasySafePay) API during the first and subsequent payments:
Note: For subsequent payments with Express Bank Transfer, simply keep the parameters consistent with the first payment. The buyer can open the Express Bank Transfer webpage and enter the phone number to proceed directly with the payment.
Parameter type | Parameter name | Required (First payment) | Required (Subsequent payments) | Description |
Base parameter | productCode | Yes | Yes | The value is fixed as AGREEMENT_PAYMENT in the EasySafePay scenario. |
productScene | Yes | Yes | The value is fixed as EASY_PAY in the EasySafePay scenario. | |
paymentRequestId | Yes | Yes | The unique ID assigned by a merchant to identify a payment request. | |
paymentMethod.paymentMethodType | Yes | Yes | ||
paymentMethod.paymentMethodId | No | Yes | The unique ID that is used to identify a payment method. The value of this parameter is that of accessToken from the notifyAuthorization API after the first payment. | |
settlementStrategy | No | No | The settlement strategy for the payment request. If the merchant agreement supports multiple settlement currencies, they must be specified in the API request. | |
paymentAmount.value | Yes | Yes | The value of the amount as a positive integer in the smallest currency unit. | |
paymentAmount.currency | Yes | Yes | ||
paymentSessionExpiryTime | No | No | The specific date and time after which the payment session will expire. The default expiration time is 1 hour after the session creation. The maximum expiration time cannot exceed 1 hour. For example, if the session is created at 2023-7-27T12:00:01+08:30, the session expiration time is 2023-7-27T13:00:01+08:30. | |
paymentRedirectUrl | Yes | Yes | The merchant page URL that the buyer is redirected to after the payment is completed. The page display according to the server-side result and should not default to a fixed payment success page. When the payment is initiated from an app, pass the scheme URL. | |
paymentNotifyUrl | No | No | The URL that is used to receive the payment result notification. it must be an HTTPS URL. This parameter can be omitted if already configured via Antom Dashboard. | |
Authorization parameter | agreementInfo.authState | Yes | No | The unique ID generated by the merchant to initiate an EasySafePay authorization. This parameter is only required during the first payment and is not required for subsequent payments. |
agreementInfo.userLoginId | No | No | The login ID that the buyer used to register in the payment method client. The login ID can be the buyer's email address or phone number. The specific format requirements are shown in the "Common userLoginId formats" table below. Providing this parameter can effectively increase payment success rates and reduce buyer drop-off risk. | |
Order parameter | order.orderAmount | Yes | Yes | The order amount of the merchant that directly provides services or goods to the buyer. |
order.referenceOrderId | Yes | Yes | The unique ID to identify the order on the merchant side. | |
order.orderDescription | Yes | Yes | Summary description of the order. | |
order.buyer
| Yes | Yes | Submit buyer information for risk assessment. Provide at least one of these parameters: referenceBuyerId, buyerPhoneNo, or buyerEmail. |
The parameter format for the buyer's payment account for each payment method is as follows:
Payment method | Parameter format |
It is recommended to prioritize using a mobile phone number:
| |
62-8569****7288. The phone number starts with 8 and is no more than 12 digits long, excluding the prefix. | |
TrueMoney | The buyer is authenticated on the payment method side, and no parameters need to be passed in.userloginId. |
During the first-time payment, passing the buyer's payment account will auto-fill the buyer's account on the payment page, eliminating manual input. Below is a comparison of the user experience with and without these fields:
With account parameter passed
Login account input is not required.
Without account parameter passed
Manual input of login account is required.
Below are code examples for first and subsequent payments.
First payment
@PostMapping("/payment/createSession")
public ResponseEntity<ApiResponse> createPaymentSession(@RequestBody PaymentVO payment) {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// replace with paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// convert amount unit(in practice, amount should be calculated on your serverside)
// For details, please refer to: <a href="https://docs.antom.com/ac/ref/cc">Usage rules of the Amount object</a>
long amountMinorLong = Money.of(CurrencyUnit.of(payment.currency), new BigDecimal(payment.amountValue)).getAmountMinorLong();
// set amount
Amount amount = Amount.builder().currency(payment.currency).value(String.valueOf(amountMinorLong)).build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
// set settlement strategy
// replace with your existing settlement currency
SettlementStrategy settlementStrategy = SettlementStrategy.builder().settlementCurrency("USD").build();
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
User loginUser = users.get(payment.getUserId());
// set buyer info
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// set paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType(payment.paymentMethodType).build();
if (loginUser.getPaymentMethodTypeAccessToken().containsKey(payment.getPaymentMethodType())) {
// buyer has authorized
String accessToken = loginUser.getPaymentMethodTypeAccessToken().get(payment.getPaymentMethodType());
paymentMethod.setPaymentMethodId(accessToken);
} else {
// set agreementInfo
// replace with your authState
String authState = UUID.randomUUID().toString();
AgreementInfo agreementInfo = AgreementInfo.builder().authState(authState).build();
alipayPaymentSessionRequest.setAgreementInfo(agreementInfo);
// save the paymentMethodType corresponding to the authState
authStatePayment.put(authState, payment);
// The login ID that the user used to register in the payment method client. The login ID can be the user's email address or phone number.
// Specify this parameter to free users from manually entering their login IDs.
if(StringUtil.isNotBlank(loginUser.getPhoneNumber()){
buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
}
if(StringUtil.isNotBlank(loginUser.getEmail() && "ALIPAY_HK".equals(payment.getPaymentMethodType())){
buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
}
}
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// replace with your orderId
String orderId = UUID.randomUUID().toString();
// set order info
Order order = Order.builder().referenceOrderId(orderId)
.orderDescription("antom sdk testing order").orderAmount(amount).buyer(buyer).build();
alipayPaymentSessionRequest.setOrder(order);
// replace with your notify url
// or configure your notify url here: <a href="https://dashboard.antom.com/global-payments/developers/iNotify">Notification URL</a>
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com/payment/receivePaymentNotify");
// replace with your redirect URL
alipayPaymentSessionRequest.setPaymentRedirectUrl(
"http://localhost:8080/index.html?paymentRequestId=" + paymentRequestId);
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
long startTime = System.currentTimeMillis();
System.out.println("payment request: " + JSON.toJSONString(alipayPaymentSessionRequest));
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
System.out.println("payment response: " + JSON.toJSONString(alipayPaymentSessionResponse));
System.out.println("payment request cost time: " + (System.currentTimeMillis() - startTime) + "ms");
} catch (AlipayApiException e) {
return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), e));
}
return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), alipayPaymentSessionResponse));
}The following code shows a sample of the request message:
{
"agreementInfo": {
"authState": "authState001",
"userLoginId": "userLoginId001"
},
"order": {
"buyer": {
"referenceBuyerId": "referenceBuyerId001"
},
"orderAmount": {
"currency": "CNY",
"value": "100"
},
"orderDescription": "orderDescription001",
"referenceOrderId": "referenceOrderId001"
},
"paymentAmount": {
"currency": "CNY",
"value": "100"
},
"paymentMethod": {
"paymentMethodType": "ALIPAY_CN"
},
"paymentNotifyUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/record/notify?env=main_online&paymentMethodType=ALIPAY_CN",
"paymentRedirectUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/result",
"paymentRequestId": "paymentRequestId001",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}The following code shows a sample of the response message:
{
"paymentSessionData": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3cjK3CVpnMXY7BfQlIvwNqQWtXHEMUo0R5pQwnSyNtxTA==&&SG&&188&&eyJh***",
"paymentSessionExpiryTime": "2024-09-27T15:57:30+08:00",
"paymentSessionId": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3fI21eGbgq240lFVquZsLrM",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}Please take the next step according to the value of the result.resultStatus.
resultStatus | Message | Further actions |
S | The payment session is successfully created. | Return the obtained paymentSessionData to the merchant's frontend. For specific operational steps, refer to Step 4. |
F | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
U | The payment session creation failed due to unknown reasons. | Replace the paymentRequestId and authstate value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |
Note: If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new paymentRequestId and authstate value.
Subsequent payments
public static void createPaymentSession() {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// replace with your paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// set amount
// you should convert amount unit(in practice, amount should be calculated on your server side)
Amount amount = Amount.builder().currency("HKD").value("98080").build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
//set settlement currency
SettlementStrategy settlementStrategy = new SettlementStrategy();
settlementStrategy.setSettlementCurrency("USD");
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
// set paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder()
.paymentMethodType("ALIPAY_HK")
.paymentMethodId("28288803001319861727421828000Cv96OFlYoi17100****")
.build();
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// set buyer info
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// replace with your orderId
String orderId = UUID.randomUUID().toString();
// set order Info
Order order = Order.builder()
.referenceOrderId(orderId)
.orderDescription("antom api testing order")
.orderAmount(amount)
.buyer(buyer)
.build();
alipayPaymentSessionRequest.setOrder(order);
// replace with your notify url
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com");
// replace with your redirect url
alipayPaymentSessionRequest.setPaymentRedirectUrl("http://www.yourRedirectUrl.com");
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
} catch (AlipayApiException e) {
String errorMsg = e.getMessage();
// handle error condition
}
}
The following code shows a sample of the request message:
{
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "HKD",
"value": "98080"
},
"orderDescription": "antom api testing order",
"referenceOrderId": "5e445b58-49ad-4552-a36d-d38f311a090d"
},
"paymentAmount": {
"currency": "HKD",
"value": "98080"
},
"paymentMethod": {
"paymentMethodId": "28288803001319861727421828000Cv96OFlYoi17100****",
"paymentMethodType": "ALIPAY_HK"
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com",
"paymentRedirectUrl": "http://www.yourRedirectUrl.com",
"paymentRequestId": "5810a84e-3a3e-4e47-bbac-9dfe3f2dd2b3",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}The following code shows a sample of the response message:
{
"paymentSessionData": "paymentSessionData****",
"paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
"paymentSessionId": "paymentSessionId****",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}Please take the next step according to the value of the result.resultStatus.
resultStatus | Message | Further actions |
S | The payment session is successfully created. | Return the obtained paymentSessionData to the merchant's frontend. For specific operational steps, refer to Step 4. |
F | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
U | The payment session creation failed due to unknown reasons. | Replace the paymentRequestId value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |
Note: If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new paymentRequestId value.
Common questions
Q: Can I use Chinese characters in the value of the request parameters?
A: To avoid incompatibility of a certain payment method, do not use Chinese characters for parameters in the request.
Q: How to set the URL to receive the payment notification?
A: Specify paymentNotifyUrl in the createPaymentSession (EasySafePay) API to receive the asynchronous notification about the payment result (notifyPayment), or configure the receiving URL in Antom Dashboard. If the URL is specified in both the request and Antom Dashboard, the value specified in the request takes precedence.
Q: What is the difference between paymentAmount and orderAmount?
A: paymentAmount refers to the payment amount, while orderAmount refers to the order amount. The actual charged amount is determined by paymentAmount.
A: paymentAmount refers to the payment amount, while orderAmount refers to the order amount. The actual charged amount is determined by paymentAmount.
Q: What does paymentSessionExpiryTime specifically refer to in payment requests?
A: paymentSessionExpiryTime indicates the validity period from successful payment session creation until the buyer submits the payment. After submission, the payment processing timeout is 10 minutes. Therefore, the maximum total duration from session creation to payment completion is 1 hour and 10 minutes.
A: paymentSessionExpiryTime indicates the validity period from successful payment session creation until the buyer submits the payment. After submission, the payment processing timeout is 10 minutes. Therefore, the maximum total duration from session creation to payment completion is 1 hour and 10 minutes.
Q: Which parameters should be prioritized in the response message?
A: Pay attention to the following key parameters:
A: Pay attention to the following key parameters:
- result.resultStatus: Indicates the result of the API call.
- paymentSessionData: Encrypted payment session data, which is passed to the frontend for initializing the Antom SDK.
- paymentSessionExpiryTime: Expiration timestamp of the payment session.
Step 3: Invoke the SDK Client-side
After obtaining the paymentSessionData value on the merchant server side, the merchant client can invoke the SDK to redirect the checkout page to the payment method authorization page. When the buyer submits a payment request, the SDK will automatically handle encrypted communication, risk control verification, page redirection, and payment instruction execution, enabling an end-to-end payment authorization process.
1. Instantiate the SDK
- Use AMSEasyPayConfigurationto create the SDK instance. The configuration object includes the following parameters:
Parameter name | Required | Description |
setLocale | No | Used to specify the language information. Select the appropriate value based on the region of the payment method. Valid values for this parameter are listed as follows.If a value not in the following list is used, the local language is used instead.
|
setOption | No | Used to specify whether to use the sandbox environment, the window alignment mode, and the redirection after the payment is complete. Valid values are:
Note:
|
- Create an instance of the setOnCheckoutListener API to handle corresponding events that occur in subsequent processes, which include the following method:
Method | Required | Description |
onEventCallback | No | A callback function that monitors payment events on the checkout page, returning eventCode and eventResult. The payment success result will not be returned by this callback function by default. A redirection to the payment success result page that you specified will take place instead. However, when notRedirectAfterComplete is set to true, the system will not perform redirection upon payment completion, instead it will provide event callback. Note: When integrating with Alipay, you will receive the payment event codes returned by onEventCallback. |
The following sample code shows how to instantiate the SDK:
// Step 1: Create the AMSEasyPayConfiguration type.
AMSEasyPayConfiguration configuration = new AMSEasyPayConfiguration();
configuration.setLocale(new Locale("en", "US"));
// Set the sandbox environment. If you leave it empty, the production environment is used by default.
configuration.setOption("sandbox", "true");
// Set as false by default
configuration.setOption("notRedirectAfterComplete", "false");
// Set the callback to monitor payment events on the checkout page.
configuration.setOnCheckoutListener(
new OnCheckoutListener() {
@Override
public void onEventCallback(String eventCode, AMSEventResult eventResult) {
// For eventCode, refer to the respective sample codes or event codes.
Toast.makeText(
activity,
"eventCode=" + eventCode + " message=" + message,
Toast.LENGTH_SHORT
).show();
}
}
);
// Instantiate AMSEasyPay.
AMSEasyPay checkout = new AMSEasyPay.Builder(activity, configuration).build();The following image shows the rendering effect of the merchant checkout page invoking a half-screen pop-up or redirecting to the digital wallet app:
- Use the createComponent method in the instance object to create a payment component, which includes the following parameter:
Parameter name | Required | Description |
sessionData | Yes | Create a configuration object using the sessionData parameter: Use the complete data of the value of paymentSessionData obtained in the response of the createPaymentSession (EasySafePay) API as the value of this parameter. |
The sample code is as follows:
checkout.createComponent(activity, sessionData);2. Handle SDK callback event codes
Below are the event codes returned by onEventCallback and handling recommendations:
Note: In the Android Native environment, Alipay only supports redirecting to the merchant app's launch page, rather than the paymentRedirectUrl specified in the createPaymentSession (EasySafePay) API. The specific redirect page needs to be controlled through the event code.
Type | Code | Description | Further action |
Status code | SDK_CALL_URL_SUCCESS | This event code indicates that redirect successfully for the paymentRedirectUrl. | Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. |
SDK_PAYMENT_CANCEL | The buyer canceled the payment (the buyer exited the payment page without submitting the order). | You can re-invoke the SDK usingpaymentSessionDatawithin its validity period; if it has expired, you need to initiate a new createPaymentSession (EasySafePay) API. | |
SDK_PAYMENT_SUCCESSFUL | Indicates that the wallet has successfully processed the payment. | Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. Note: For payment solutions not integrated with Alipay, suggest redirecting users to the payment result page. | |
SDK_PAYMENT_FAIL | Indicates that the wallet failed to process the payment. | Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. Note: For payment solutions not integrated with Alipay, suggest redirecting users to the payment result page. | |
SDK_PAYMENT_PROCESSING (Returned when integrated with Alipay) | Indicates that the payment status of theAlipay walletis unknown. | Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. | |
SDK_PAYMENT_ERROR (Returned when integrated with Alipay) | Indicates that the payment processing of the Alipay wallet is abnormal. | Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. | |
Error code | SDK_INTERNAL_ERROR | SDK internal error. | Contact Antom Technical Support. |
SDK_CREATEPAYMENT_PARAMETER_ERROR | The parameters passed to the createComponent method are not correct. | Check if the parameters are correct and re-initialize the component. | |
SDK_STATUS_ERROR | This event code indicates one of the following situations:
| Please check the result message, then match the error situations. | |
SDK_INTEGRATION_ERROR | This event code indicates that some dependencies of SDK is not exist. Currently there are two scenario:
| Please check whether target module has been integrated. | |
SDK_LAUNCH_PAYMENT_APP_ERROR | This event code indicates one of the following situations:
| Check whether the paymentRedirectUrl parameter is correctly passed when calling the createPaymentSession (EasySafePay) API. If frequent redirection exceptions occur, contact Antom Technical Support to troubleshoot redirection or cross-application calling issues. |
The following sample code shows how to handle the callback function:
configuration.setOnCheckoutListener(
new OnCheckoutListener() {
@Override
public void onEventCallback(String eventCode, AMSEventResult eventResult) {
if (selectPayment != null && selectPayment.getPaymentMethodCode().equals("ALIPAY_CN")) {
switch (eventCode) {
case "SDK_PAYMENT_CANCEL":
AlertUtils.showAlertWithMessage(
MainActivity.this,
"The buyer canceled the payment (the buyer exited the payment page without submitting the order). You can re-invoke the SDK using paymentSessionData within its validity period; If it has expired, you need to initiate a new createPaymentSession (EasySafePay) request."
);
break;
case "SDK_PAYMENT_SUCCESSFUL":
AlertUtils.showAlertWithMessage(
MainActivity.this,
"The Alipay wallet has successfully processed the payment. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result."
);
break;
case "SDK_PAYMENT_FAIL":
AlertUtils.showAlertWithMessage(
MainActivity.this,
"The Alipay wallet failed to process the payment. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result."
);
break;
case "SDK_PAYMENT_PROCESSING":
AlertUtils.showAlertWithMessage(
MainActivity.this,
"The payment status of the Alipay wallet is unknown. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result."
);
break;
case "SDK_PAYMENT_ERROR":
AlertUtils.showAlertWithMessage(
MainActivity.this,
"The payment processing of the Alipay wallet is abnormal. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result."
);
break;
default:
AlertUtils.showAlertWithMessage(
MainActivity.this,
"eventCode=" + eventCode + " message=" + eventResult.getMessage()
);
break;
}
} else {
// Please note that payment success will not be notified from this callback function, but rather the page will be redirected to the success result page you specified
switch (eventCode) {
case "SDK_PAYMENT_CANCEL":
AlertUtils.showAlertWithMessage(
MainActivity.this,
"The buyer canceled the payment (the buyer exited the payment page without submitting the order). You can re-invoke the SDK using paymentSessionData within its validity period; If it has expired, you need to initiate a new createPaymentSession (EasySafePay) request."
);
break;
case "SDK_CALL_URL_SUCCESS":
AlertUtils.showAlertWithMessage(
MainActivity.this,
"Open wallet app or redirect to the merchant page successfully."
);
break;
case "SDK_LAUNCH_PAYMENT_APP_ERROR":
AlertUtils.showAlertWithMessage(
MainActivity.this,
"Open wallet app or redirect to the merchant page failed"
);
break;
case "SDK_CREATEPAYMENT_PARAMETER_ERROR":
AlertUtils.showAlertWithMessage(
MainActivity.this,
"The input parameter provided is invalid. Please check the value and try again."
);
break;
default:
AlertUtils.showAlertWithMessage(
MainActivity.this,
"eventCode=" + eventCode + " message=" + eventResult.getMessage()
);
break;
}
}
}
}
);3. Free SDK component resources
Call the onDestroy method to free SDK component resources in the following situations:
- When the buyer exits the checkout page, completely free the component resources created in the createPaymentSession (EasySafePay) API.
- When the buyer initiates multiple payments, and the parameters in AMSEasyPayConfiguration have changed, free the component resources created in the previous createPaymentSession (EasySafePay) API.
In the following scenario, you do not need to call onDestroy, and the SDK will automatically free partial resources (for SDK 1.33.0 or above).
- When the buyer initiates multiple payments, and the parameters in AMSEasyPayConfiguration have not changed. The SDK will automatically free partial resources after the payment is completed to reset to the state before createComponent was called.
The following sample code shows how to free components:
// Completely free SDK component resources
checkout.onDestroy();Common questions
Q: Is it mandatory to handle SDK callback events?
A: For Alipay, you must process event codes to display payment results, but this payment method is optional. Callback events can also be used for logging.
A: For Alipay, you must process event codes to display payment results, but this payment method is optional. Callback events can also be used for logging.
Q: Can an AMSEasypay instance execute createComponent multiple times?
A: No. You need to create a freshAMSEasypay instance to initiate a new payment.
A: No. You need to create a freshAMSEasypay instance to initiate a new payment.
Q: Are SDK calls required for both first-time and subsequent payments?
A: Yes.
A: Yes.
WebView
User experience
The following screenshots show the user experience of wallet and bank transfer respectively:
Digital wallet
In the digital wallet payment scenario, the system will guide the buyer to complete the transaction on the merchant's page or within the payment method app after the buyer confirms the payment. The first payment verification and subsequent simplified payment process are illustrated as follows:
First payment
The first payment requires security authentication. Once authorized, the buyer will be enabled for password-free payments on subsequent transactions.
Pay on the merchant page
Pay on the payment method app
Subsequent payments
Subsequent payments are processed without requiring a password upon order submission.
Online banking
Below is the user experience for first and subsequent payments using online banking payment methods.
First payment
For the first payment, the buyer completes the payment authorization process to enable subsequent password-free payments.
Subsequent payments
Subsequent payments are processed without requiring a password upon order submission.
Payment flow
The following are flow chart for the first payment and subsequent payment:
First payment
- The buyer enters the checkout page.
- Preload the Antom SDK when the buyer chooses a payment method.
- Create a payment session request.
After the buyer submits the order, you can obtain the payment session by calling thecreatePaymentSession (EasySafePay) API. - Invoke the client SDK.
Invoke the SDK using a payment session on the client side and the SDK will automatically collect payment elements, Display the payment page, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics. - Obtain the authorization result.
When the authorization is successful, Antom sends you the asynchronous notification through thenotifyAuthorization API. - Obtain the payment result.
Obtain the payment result using one of the following methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (EasySafePay) API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use notifyPayment to send asynchronous notifications to you.
- Synchronous inquiry: Call the inquiryPayment API to check the real-time payment status.
Subsequent payments
- The buyer enters the checkout page.
- Preload the Antom SDK when the buyer chooses a payment method.
- Create a payment session request.
After the buyer submits the order, you can obtain the payment session by calling thecreatePaymentSession (EasySafePay) API. - Invoke the client SDK.
Invoke the SDK using a payment session on the client side and the SDK will automatically collect payment elements, Display the payment page, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics. - Obtain the payment result.
Obtain the payment result using one of the following methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (EasySafePay) API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use notifyPayment to send asynchronous notifications to you.
- Synchronous inquiry: Call the inquiryPayment API to check the real-time payment status.
Integration preparations
Before you start integrating, read the Integration Guide and API Overview documents to understand the integration steps of the server-side API and the precautions for calling the API. Furthermore, ensure that the following prerequisites are met:
- Obtain a client ID
- Complete the key configuration
- Complete the configuration of paymentNotifyUrl to receive the asynchronous notification
- Integrate the server-side SDK package, install the server-side library, and initialize a request instance. For more details, refer to Server-side SDKs.
- If you need to conduct joint debugging by connecting the sandbox with the production environment, please contact Antom technical support at least two business days in advance to request configuration. The sandbox environment and production environment require separate configuration.
Version Requirements
- iOS:
- Install Xcode 12 or later.
- Compatible with iOS 11 or later.
- Android:
- Compatible with Android 4.4 (API level 19) or later.
Note: Flutter and React Native (RN) development frameworks are not currently supported.
Integration steps
Start your integration by taking the following steps:
- (Optional) Preload the SDK
- Create a payment session
- Invoke the SDK
- Obtain the authorization and payment result
(Optional) Step 1: Preload the SDK Client-side
Preloading the SDK during the checkout page initialization significantly improves the rendering performance with no negative impact. It is recommended to trigger preloading of the SDK when the buyer selects a payment method.
Follow the code example below to perform the preloading:
AMSEasypay.preload();Step 2: Create a payment session Server-side
Call the createPaymentSession (EasySafePay) API to create a payment session and initialize the Antom SDK using the paymentSessionData value returned in the response.
The table below lists the parameter specifications for calling the createPaymentSession (EasySafePay) API during the first and subsequent payments:
Note: For subsequent payments with Express Bank Transfer, simply keep the parameters consistent with the first payment. The buyer can open the Express Bank Transfer webpage and enter the phone number to proceed directly with the payment.
Parameter type | Parameter name | Required (First-time payment) | Required (Subsequent payments) | Description |
Base parameter | productCode | Yes | Yes | The value is fixed as AGREEMENT_PAYMENT in the EasySafePay scenario. |
productScene | Yes | Yes | The value is fixed as EASY_PAY in the EasySafePay scenario. | |
paymentRequestId | Yes | Yes | The unique ID assigned by a merchant to identify a payment request. | |
paymentMethod.paymentMethodType | Yes | Yes | ||
paymentMethod.paymentMethodId | No | Yes | The unique ID that is used to identify a payment method. The value of this parameter is that of accessToken from the notifyAuthorization API. | |
settlementStrategy | No | No | The settlement strategy for the payment request. If the merchant agreement supports multiple settlement currencies, they must be specified in the API request. | |
paymentAmount.value | Yes | Yes | The value of the amount as a positive integer in the smallest currency unit. | |
paymentAmount.currency | Yes | Yes | ||
paymentSessionExpiryTime | No | No | The specific date and time after which the payment session will expire. The default expiration time is 1 hour after the session creation. For example, if the session is created at 2023-7-27T12:00:01+08:30, the session expiration time is 2023-7-27T13:00:01+08:30. | |
paymentRedirectUrl | Yes | Yes | The merchant page URL that the user is redirected to after the payment is completed. The page display according to the server-side result and should not default to a fixed payment success page.
| |
paymentNotifyUrl | No | No | The URL that is used to receive the payment result notification. it must be an HTTPS URL. This field can be omitted if already configured via Antom Dashboard. | |
Authorization parameter | agreementInfo.authState | Yes | No | The unique ID generated by the merchant to initiate an EasySafePay authorization. |
Order parameter | order.orderAmount | Yes | Yes | The order amount of the merchant that directly provides services or goods to the customer |
order.referenceOrderId | Yes | Yes | The unique ID to identify the order on the merchant side. | |
order.orderDescription | Yes | Yes | Summary description of the order. | |
order.buyer.referenceBuyerId | No | No | Submit buyer information for risk assessment. Provide at least one of these fields: referenceBuyerId, buyerPhoneNo, or buyerEmail. | |
order.buyer.
| No | No | Buyer's account. Providing relevant payment account information can effectively improve the payment success rate and reduce the risk of buyer attrition. Please refer to the table below for specific format requirements. |
The parameter format for the buyer's payment account for each payment method is as follows:
Payment method | Parameter format |
It is recommended to prioritize using a mobile phone number:
| |
62-8569****7288. The phone number starts with 8 and is no more than 12 digits long, excluding the prefix. | |
TrueMoney | The buyer is authenticated on the payment method side, and no parameters need to be passed in.userloginId. |
Below are code examples for first and subsequent payments.
First payment
@PostMapping("/payment/createSession")
public ResponseEntity<ApiResponse> createPaymentSession(@RequestBody PaymentVO payment) {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// replace with your paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// convert amount unit (in practice, amount should be calculated on your serverside)
// For details, please refer to: <a href="https://docs.antom.com/ac/ref/cc">Usage rules of the Amount object</a>
long amountMinorLong = Money.of(CurrencyUnit.of(payment.currency), new BigDecimal(payment.amountValue)).getAmountMinorLong();
// set amount
Amount amount = Amount.builder().currency(payment.currency).value(String.valueOf(amountMinorLong)).build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
// set settlement strategy
// replace with your existing settlement currency
SettlementStrategy settlementStrategy = SettlementStrategy.builder().settlementCurrency("USD").build();
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
User loginUser = users.get(payment.getUserId());
// set paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType(payment.paymentMethodType).build();
if(loginUser.getPaymentMethodTypeAccessToken().containsKey(payment.getPaymentMethodType())){
// user has authorized
String accessToken = loginUser.getPaymentMethodTypeAccessToken().get(payment.getPaymentMethodType());
paymentMethod.setPaymentMethodId(accessToken);
}else{
// set agreementInfo
// replace with your authState
String authState = UUID.randomUUID().toString();
// The login ID that the user used to register in the payment method client. The login ID can be the user's email address or phone number.
// Specify this parameter to free users from manually entering their login IDs
String userLoginId = loginUser.getPhoneNumber();
AgreementInfo agreementInfo = AgreementInfo.builder().authState(authState).userLoginId(userLoginId).build();
alipayPaymentSessionRequest.setAgreementInfo(agreementInfo);
// save the paymentMethodType corresponding to the authState
authStatePayment.put(authState, payment);
}
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// set buyer info
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// replace with your orderId
String orderId = UUID.randomUUID().toString();
// set order info
Order order = Order.builder().referenceOrderId(orderId).
orderDescription("antom sdk testing order").orderAmount(amount).buyer(buyer).build();
alipayPaymentSessionRequest.setOrder(order);
// replace with your notify url
// or configure your notify url here: <a href="https://dashboard.antom.com/global-payments/developers/iNotify">Notification URL</a>
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com/payment/receivePaymentNotify");
// replace with your redirect url
alipayPaymentSessionRequest.setPaymentRedirectUrl(
"http://localhost:8080/index.html?paymentRequestId=" + paymentRequestId);
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
long startTime = System.currentTimeMillis();
System.out.println("payment request: " + JSON.toJSONString(alipayPaymentSessionRequest));
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
System.out.println("payment response: " + JSON.toJSONString(alipayPaymentSessionResponse));
System.out.println("payment request cost time: " + (System.currentTimeMillis() - startTime) + "ms
");
} catch (AlipayApiException e) {
return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), e));
}
return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), alipayPaymentSessionResponse));
}The following code shows a sample of the request message:
{
"agreementInfo": {
"authState": "authState001",
"userLoginId": "userLoginId****"
},
"order": {
"buyer": {
"referenceBuyerId": "referenceBuyerId****"
},
"orderAmount": {
"currency": "CNY",
"value": "100"
},
"orderDescription": "orderDescription001",
"referenceOrderId": "referenceOrderId****"
},
"paymentAmount": {
"currency": "CNY",
"value": "100"
},
"paymentMethod": {
"paymentMethodType": "ALIPAY_CN"
},
"paymentNotifyUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/record/notify?env=main_online&paymentMethodType=ALIPAY_CN",
"paymentRedirectUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/result",
"paymentRequestId": "paymentRequestId****",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}The following code shows a sample of the response message, including the following key parameters:
- paymentSessionData: Encrypted payment session data. This data is passed to the frontend for invoking the Antom SDK.
- paymentSessionExpiryTime: Expiration time of the payment session.
{
"paymentSessionData": "paymentSessionData****",
"paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
"paymentSessionId": "paymentSessionId****",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}Please take the next step according to the value of the result.resultStatus.
resultStatus | Message | Further actions |
S | The payment session is successfully created. | Return the obtained paymentSessionData to the merchant's frontend. |
F | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
U | The payment session creation failed due to unknown reasons. | Replace the paymentRequestId and authstate value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |
Note: If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new paymentRequestId and authstate value.
Subsequent payments
public static void createPaymentSession() {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);
// replace with your paymentRequestId
String paymentRequestId = UUID.randomUUID().toString();
alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);
// set amount
// you should convert amount unit (in practice, amount should be calculated on your server side)
Amount amount = Amount.builder().currency("HKD").value("98080").build();
alipayPaymentSessionRequest.setPaymentAmount(amount);
// set settlement currency
SettlementStrategy settlementStrategy = new SettlementStrategy();
settlementStrategy.setSettlementCurrency("USD");
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
// set paymentMethod
PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType("ALIPAY_HK")
.paymentMethodId("28288803001319861727421828000Cv96OFlYoi17100****").build();
alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);
// set buyer info
Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();
// replace with your orderId
String orderId = UUID.randomUUID().toString();
// set order Info
Order order = Order.builder().referenceOrderId(orderId).
orderDescription("antom api testing order").orderAmount(amount).buyer(buyer).build();
alipayPaymentSessionRequest.setOrder(order);
// replace with your notify url
alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com");
// replace with your redirect url
alipayPaymentSessionRequest.setPaymentRedirectUrl("http://www.yourRedirectUrl.com");
AlipayPaymentSessionResponse alipayPaymentSessionResponse;
try {
alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
} catch (AlipayApiException e) {
String errorMsg = e.getMessage();
// handle error condition
}
}The following code shows a sample of the request message:
{
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "HKD",
"value": "98080"
},
"orderDescription": "antom api testing order",
"referenceOrderId": "5e445b58-49ad-4552-a36d-d38f311****"
},
"paymentAmount": {
"currency": "HKD",
"value": "98080"
},
"paymentMethod": {
"paymentMethodId": "28288803001319861727421828000Cv96OFlYoi17100****",
"paymentMethodType": "ALIPAY_HK"
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com",
"paymentRedirectUrl": "http://www.yourRedirectUrl.com",
"paymentRequestId": "5810a84e-3a3e-4e47-bbac-9dfe3f2d****",
"productCode": "AGREEMENT_PAYMENT",
"productScene": "EASY_PAY",
"settlementStrategy": {
"settlementCurrency": "USD"
}
}The following code shows a sample of the response message, including the following key parameters:
- paymentSessionData: Encrypted payment session data. This data is passed to the frontend for invoking the Antom SDK.
- paymentSessionExpiryTime: Expiration time of the payment session.
{
"paymentSessionData": "paymentSessionData****",
"paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
"paymentSessionId": "paymentSessionId****",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}Please take the next step according to the value of the result.resultStatus.
resultStatus | Message | Further actions |
S | The payment session is successfully created. | Return the obtained paymentSessionData to the merchant's frontend. |
F | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
U | The payment session creation failed due to unknown reasons. | Replace the paymentRequestId value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |
Note: If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new paymentRequestId value.
Common questions
Q: Can I use Chinese characters in the value of the request parameters?
A: To avoid incompatibility of a certain payment method, do not use Chinese characters for parameters in the request.
Q: How to set the URL to receive the payment notification?
A: Specify paymentNotifyUrl in the createPaymentSession (EasySafePay) API to receive the asynchronous notification about the payment result (notifyPayment), or configure the receiving URL in Antom Dashboard. If the URL is specified in both the request and Antom Dashboard, the value specified in the request takes precedence.
Q: What is the difference between paymentAmount and orderAmount?
A:paymentAmount refers to the payment amount, while orderAmount refers to the order amount. The actual charged amount is determined by paymentAmount.
A:paymentAmount refers to the payment amount, while orderAmount refers to the order amount. The actual charged amount is determined by paymentAmount.
Q: What does paymentSessionExpiryTime specifically refer to in payment requests?
A:paymentSessionExpiryTime indicates the validity period from successful payment session creation until the buyer submits the payment. After submission, the payment processing timeout is 10 minutes. Therefore, the maximum total duration from session creation to payment completion is 1 hour and 10 minutes.
A:paymentSessionExpiryTime indicates the validity period from successful payment session creation until the buyer submits the payment. After submission, the payment processing timeout is 10 minutes. Therefore, the maximum total duration from session creation to payment completion is 1 hour and 10 minutes.
Step 3: Invoke the SDK Server-side
After obtaining the paymentSessionData value on the merchant server side, the merchant client can invoke the SDK to redirect the checkout page to the payment method authorization page. When the buyer submits a payment request, the SDK will automatically handle encrypted communication, risk control verification, page redirection, and payment instruction execution, enabling an end-to-end payment authorization process.
1. Instantiate the SDK
- Use AMSEasyPay to create the SDK instance. The configuration object includes the following parameters:
Parameter name | Required | Description |
environment | Yes | Used to specify the environment information. Valid values are:
|
locale | No | Used to specify the language information. Select the appropriate value based on the region of the payment method. Valid values for this parameter are listed as follows.If a value not in the following list is used, the English is used instead.
|
onEventCallback | No | A callback function used to listen for payment events on the checkout page, returning eventCode and eventResult. During the payment process, set isNativeAppWebview to true and additionally monitor the following events:
After payment completion:
Note: Event codes should only be used for handling frontend navigation. Payment results must be determined based on the server-side payment status. |
The following sample code shows how to instantiate the SDK using npm or CDN:
npm
import { AMSEasyPay } from '@alipay/ams-checkout' // manage the package
const checkoutApp = new AMSEasyPay({
environment: "sandbox",
locale: "en_US",
onEventCallback: ({code, message})=>{},
});CDN
const checkoutApp = new window.AMSEasyPay({
environment: "sandbox",
locale: "en_US",
onEventCallback: ({code, message})=>{},
});- Use createComponent in the instance object to create a payment component. The parameters involved are as follows:
Parameter name | Required | Description |
sessionData | Yes | Create a configuration object using the sessionData parameter: Use the complete data of the value of paymentSessionData obtained in the response of the createPaymentSession (EasySafePay) API as the value of this parameter. |
isNativeAppWebview | No | Indicates whether it is an in-app webview. Valid values are:
|
notRedirectAfterComplete | No | Boolean type. Valid values are:
Note:
|
The following sample code shows how to create the component:
async function create(sessionData) {
await checkoutApp.createComponent({
sessionData: sessionData,
isNativeAppWebview: true, // Set as false by default to indicate that the merchant integrates the web SDK via an H5 webpage.
notRedirectAfterComplete: false // Set as false by default to indicate that it will redirect to your page after the payment is completed.
});
}- Listen for event code to handle redirection events.
By monitoring the SDK_REDIRECT event code, you can handle the subsequent process. An example code snippet is shown below:
import { AMSEasyPay } from '@alipay/ams-checkout' // Package management
const checkoutApp = new AMSEasyPay({
environment: "sandbox",
locale: "en_US",
onEventCallback: ({code, message, result}) => {
switch (code) {
case 'SDK_REDIRECT':
// Handle redirect logic
const redirectUrls = result?.redirectUrls || {};
const jsonString = JSON.stringify(redirectUrls);
// Check if the current environment's espJSBridge is available
if (window.espJSBridge) {
// Call the sdkRedirect method of espJSBridge, passing the redirect information.
// This approach is for reference; merchants can also use their own native communication methods for data transfer.
window.espJSBridge.sdkRedirect(jsonString)
// After data transfer is complete, perform component cleanup
checkoutApp.unmount();
}
break;
default:
console.log(code);
}
},
});- Handle redirection events using a WebView container.
Use a WebView container to manage in-app redirection events. The following are sample codes for iOS and Android respectively:
iOS
// Step 1: Create webview container
let url = "https://www.merchantWeb.com"
let webView = WKWebView()
webView.load(URLRequest(url: url))
webView.configuration.userContentController.addUserScript(
WKUserScript(
source: "window.espJSBridge = { sdkRedirect: function(message) { window.webkit.messageHandlers.espJSBridge.postMessage(message); } }",
injectionTime: .atDocumentStart,
forMainFrameOnly: true
)
)
webView.configuration.userContentController.add(self, name: "espJSBridge")
// Step 2: Handle redirect event
extension DemoViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
// Monitor redirect event
if message.name == "espJSBridge",
let bodyString = message.body as? String,
let bodyData = bodyString.data(using: .utf8),
let body = try? JSONSerialization.jsonObject(with: bodyData, options: []) as? [String: Any]
{
let applinkUrl = body["applinkUrl"] as? String
let schemeUrl = body["schemeUrl"] as? String
let normalUrl = body["normalUrl"] as? String
// Redirect to link
// Attempt to redirect to applinkUrl
tryRedirect(url: applinkUrl) { [weak self] success in
// If failed, attempt to redirect to schemeUrl
if !success {
self?.tryRedirect(url: schemeUrl) { [weak self] success in
// If failed, attempt to redirect to normalUrl
if !success {
self?.tryRedirect(url: normalUrl) { _ in }
}
}
}
}
}
}
}
func tryRedirect(url: String?, completion: @escaping (Bool) -> Void) {
guard let url = url, let url = URL(string: url) else {
completion(false)
return
}
UIApplication.shared.open(url) { success in
completion(success)
}
}Android
// Step 1: Create webview container
WebView webView;
webView = findViewById(R.id.webView);
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webView.addJavascriptInterface(new JSBridgeInterface(this), "espJSBridge");
webView.loadUrl(url);
// Step 2: Handle redirect event
public class JSBridgeInterface {
private Context mContext;
public JSBridgeInterface(Context context) {
mContext = context;
}
// Monitor redirect event
@JavascriptInterface
public void sdkRedirect(String redirectInfo) {
JSONObject jsonObject = JSONObject.parseObject(redirectInfo);
String schemeUrl = jsonObject.getString("schemeUrl");
String applinkUrl = jsonObject.getString("applinkUrl");
String normalUrl = jsonObject.getString("normalUrl");
// Attempt to redirect to schemeUrl
if (openRedirectionUrl(schemeUrl, true)) {
return;
}
// Attempt to redirect to applinkUrl
if (openRedirectionUrl(applinkUrl, false)) {
return;
}
// Attempt to redirect to normalUrl
if (openRedirectionUrl(normalUrl, false)) {
return;
}
showToast(mContext, "Failed to open URL");
}
private boolean openRedirectionUrl(String url, boolean isScheme) {
if (TextUtils.isEmpty(url)) {
return false;
}
try {
Intent intent = isScheme
? Intent.parseUri(url, Intent.URI_INTENT_SCHEME)
: new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(mContext, intent, null);
return true;
} catch (Exception exception) {
showToast(mContext, exception.getMessage()); // Display prompt message
return false;
}
}
private void showToast(Context context, String message) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
}2. Handle SDK callback event codes
Below are the event codes returned by onEventCallback and handling recommendations:
Code | Description | Further action |
SDK_REDIRECT | Triggered when redirection to a third-party payment page (such as Alipay, digital wallet applications, etc.) is required. The eventResult.redirectUrls object returned by this event contains redirect URLs for different environments. | Obtaining redirect URLs from redirectUrls:
|
SDK_CALL_URL_SUCCESS | Successfully launched the payment method app or redirected to the merchant page. | No further action is needed. |
SDK_LAUNCH_PAYMENT_APP_ERROR | This event code indicates one of the following situations:
| Check whether the paymentRedirectUrl parameter is correctly passed when calling the createPaymentSession (EasySafePay) API. Web/WAP scenarios rarely experience redirection exceptions. However, in the event of any exceptions, it is recommended to verify the redirection link. For mobile app scenarios, if frequent redirection exceptions occur, contact Antom Technical Support to troubleshoot redirection or cross-application calling issues. |
SDK_PAYMENT_CANCEL | The buyer canceled the payment (the buyer exited the payment page without submitting the order). | You can re-invoke the SDK using paymentSessionData within its validity period; If it has expired, you need to initiate a new createPaymentSession (EasySafePay) request. |
SDK_PAYMENT_SUCCESSFUL | Indicates that the payment is successful on the wallet side. | Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. Suggest redirecting buyers to the payment result page. Note: This event code is returned only when the payment process is completed within the SDK. |
SDK_PAYMENT_FAIL | Indicates that the payment is unsuccessful on the wallet side. | Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. Suggest redirecting buyers to the payment result page. Note: This event code is returned only when the payment process is completed within the SDK. |
The following sample code shows how to handle the callback function:
function onEventCallback({ code, result }) {
switch (code) {
case 'SDK_REDIRECT':
// Handle redirect logic
break;
case 'SDK_PAYMENT_CANCEL':
// Within the validity period, paymentSessionData can be used to reinvoke the SDK
break;
default:
break;
}
}3. Free SDK component resources
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 (EasySafePay) API.
- When the buyer initiates multiple payments, free the component resources created in the previous createPaymentSession (EasySafePay) API.
- After obtaining the final payment result, free the component resources.
The following sample code shows how to free components:
// Free SDK component resources
checkoutApp.unmount();Common questions
Q: Is it mandatory to handle SDK callback events?
A: Perform the following operations based on the value ofisNativeAppWebview:
A: Perform the following operations based on the value ofisNativeAppWebview:
- When isNativeAppWebview is true, you need to handle SDK callback events. They are generally categorized into two types:
- Key callbacks (e.g., payment redirect SDK_REDIRECT): Must be handled, otherwise the payment process will be interrupted.
- Other callbacks: Optional handling. You may use these callback events for logging or tracking purposes.
- When isNativeAppWebview is false, callback handling is optional. You may use the callback events for logging or tracking purposes.
Q: Can an AMSEasyPay instance execute createComponent multiple times?
A: No. If you need to initiate a new payment, you need to create a newAMSEasyPay instance.
A: No. If you need to initiate a new payment, you need to create a newAMSEasyPay instance.
Q: Are SDK calls required for both first and subsequent payments?
A: Yes.
A: Yes.
Step 4: Obtain authorization and payment result Client-side
For the first payment, you can obtain both the authorization and payment results, while for subsequent payments, only the payment result is available. Below are common scenarios:
Type | Common scenarios | Received asynchronous notification | Suggestions |
First payment | The buyer successfully authorized and paid. | Authorization succeeded, payment succeeded. |
|
The buyer authorized successfully but payment failed (e.g., due to insufficient balance). | Authorization succeeded, payment failed. | ||
The buyer authorization failed (or did not authorize) but payment succeeded. | No authorization asynchronous notification received, payment succeeded. | ||
The buyer authorization failed (or did not authorize) and payment failed (e.g., due to insufficient balance). | No authorization asynchronous notification received, payment failed. | ||
The buyer authorization failed (or did not authorize) and did not submit payment. | No asynchronous notifications received for both authorization and payment. | ||
Subsequent payments | The buyer successfully paid. | Payment succeeded. |
|
The buyer payment failed (e.g., due to insufficient balance). | Payment failed. |
Obtain the authorization result
Obtain the authorization result
When the authorization is successful during the first payment, Antom sends you the asynchronous notification through the notifyAuthorization API.
- Follow the steps below to set the notification webhook URL:
Log in to Antom Dashboard > Developer > Notification URL. Add the notification URL to alipay.ams.authorizations.notify. Refer to Notification URL for detailed steps.
The following code shows a sample of the asynchronous authorization notification request:
{
"accessToken": "28288803001319861727421828000Cv96OFlYoi17100****",
"accessTokenExpiryTime": 2145916817000,
"authState": "36a38e87-0453-495e-ad17-b46553b918da",
"authorizationNotifyType": "TOKEN_CREATED",
"userLoginId": "852-91****67",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}Based on the value of result.resultStatus in the authorization result notification request (onlySis returned), process as follows:
S: Indicates successful authorization, and the following parameters are returned:
Parameter name | Description |
accessToken | The access token that is used to access the corresponding scope of the user resource. |
accessTokenExpiryTime | The validity period of the accessToken. For the specific expiry time, refer to The table of validity period of accessToken. If the accessToken expires, you need to guide the buyer to authorize again. |
authState | A unique ID assigned for initiating authorization. This value is used to verify consistency with the authState specified in the createPaymentSession (EasySafePay) request. |
authorizationNotifyType | Only TOKEN_CREATED will be returned, indicating that the buyer successfully initiated a payment authorization on the merchant's client. |
userLoginId | The login ID used by the buyer when registering the payment method. This field has been desensitized. You may store this account for display in subsequent payments. Note: Not all payment methods return this information. |
The table below shows the token validity period for each payment method:
Payment method | Validity period of accessToken |
92 years | |
100 years | |
100 years | |
100 years | |
100 years | |
TrueMoney | 100 years |
No accesstoken is returned. The merchant side does not need to maintain an accessToken. |
- The result notification sent by Antom is signed by Antom, it is recommended that you verify the signature to confirm that the notification was sent by Antom. Refer to the following code example to verify the notification:
@PostMapping("/receiveAuthNotify")
@ResponseBody
public Result receiveAuthNotify(HttpServletRequest request, @RequestBody String notifyBody) {
// retrieve the required parameters from http request
String requestUri = request.getRequestURI();
String requestMethod = request.getMethod();
// retrieve the required parameters from request header
String requestTime = request.getHeader("request-time");
String clientId = request.getHeader("client-id");
String signature = request.getHeader("signature");
try {
// verify the signature of notification
boolean verifyResult = WebhookTool.checkSignature(
requestUri,
requestMethod,
clientId,
requestTime,
signature,
notifyBody,
ANTOM_PUBLIC_KEY
);
if (!verifyResult) {
throw new RuntimeException("Invalid notify signature");
}
// deserialize the notification body
AlipayAuthNotify authNotify = JSON.parseObject(notifyBody, AlipayAuthNotify.class);
if (
authNotify != null &&
"SUCCESS".equals(authNotify.getResult().getResultCode()) &&
"TOKEN_CREATED".equals(authNotify.getAuthorizationNotifyType())
) {
// save buyer's PaymentMethodType corresponding to accessToken
PaymentVO payment = authStatePayment.get(authNotify.getAuthState());
User user = users.get(payment.getUserId());
user
.getPaymentMethodTypeAccessToken()
.put(payment.getPaymentMethodType(), authNotify.getAccessToken());
return Result.builder()
.resultCode("SUCCESS")
.resultMessage("success.")
.resultStatus(ResultStatusType.S)
.build();
}
// other types of notifications
} 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();
}- After receiving the notification, whether the authorization is successful or not, you are not required to sign the response, but each notification request must be responded to in the format specified below. Otherwise, Antom will resend the asynchronous notification.
{
"result": {
"resultCode": "SUCCESS",
"resultStatus": "S",
"resultMessage": "success"
}
}Obtain the payment result
Obtain the payment result
After the first or subsequent payment is completed, you can obtain the payment result through one of the following methods:
- Receive the asynchronous notification: Receive the payment result delivered by the Antom server.
- Inquire about the result: Call inquiryPayment API to query payment status.
Receive the asynchronous notification
- Follow the steps below to set the notification webhook URL:
When the payment reaches a final status of success or failure, Antom sends an asynchronous notification to your configured webhook URL. You can choose one of the following two methods to set up the Webhook URL for receiving notifications:
- Order-level notification configuration: Specify an independent notification URL for each order through the paymentNotifyUrl parameter in the createPaymentSession (EasySafePay) API request.
- Merchant-level notification configuration: Log in to Antom Dashboard > Developer > Notification URL and add a notification URL for the alipay.ams.payments.payNotify API. For specific operations, refer to Notification URL.
Note: If you have configured notification URLs through both methods mentioned above, the API settings will take precedence.
The following code shows a sample of the notification request:
{
"actualPaymentAmount": {
"currency": "HKD",
"value": "98080"
},
"customsDeclarationAmount": {},
"notifyType": "PAYMENT_RESULT",
"paymentAmount": {
"currency": "HKD",
"value": "98080"
},
"paymentCreateTime": "2024-09-27T00:23:36-07:00",
"paymentId": "202409271940108001001881E0211235544",
"paymentRequestId": "bc93d19e-e1f6-4b68-b6b1-3d6ddc2a792a",
"paymentTime": "2024-09-27T00:23:46-07:00",
"pspCustomerInfo": {
"pspCustomerId": "20881221121****",
"pspName": "ALIPAY_HK"
},
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}The table below displays the possible values returned in the resultStatus parameter of the response. Please follow the corresponding instructions for handling:
result.resultStatus | Message | Suggestion |
S | Payment was successful. | The following fields can be obtained from:
|
F | Payment failed. | It is recommended to guide the buyer to place the order again. |
- The result notification sent by Antom is signed by Antom, it is recommended that you verify the signature to confirm that the notification was sent by Antom. Refer to the following code example to verify the notification:
/**
* receive notify
*
* @param request request
* @param notifyBody notify body
* @return Result
*/
@PostMapping("/receiveNotify")
@ResponseBody
public Result receiveNotify(HttpServletRequest request, @RequestBody String notifyBody) {
// retrieve the required parameters from http request
String requestUri = request.getRequestURI();
String requestMethod = request.getMethod();
// retrieve the required parameters from request header
String requestTime = request.getHeader("request-time");
String clientId = request.getHeader("client-id");
String signature = request.getHeader("signature");
try {
// verify the signature of notification
boolean verifyResult = WebhookTool.checkSignature(
requestUri,
requestMethod,
clientId,
requestTime,
signature,
notifyBody,
ANTOM_PUBLIC_KEY
);
if (!verifyResult) {
throw new RuntimeException("Invalid notify signature");
}
// deserialize the notification body
JSONObject jsonObject = JSON.parseObject(notifyBody);
String notifyType = (String) jsonObject.get("notifyType");
if ("PAYMENT_RESULT".equals(notifyType)) {
AlipayPayResultNotify paymentNotify = jsonObject.toJavaObject(AlipayPayResultNotify.class);
if (paymentNotify != null && "SUCCESS".equals(paymentNotify.getResult().getResultCode())) {
// handle your own business logic.
// e.g. The relationship between payment information and buyers is kept in the database.
System.out.println("receive payment notify: " + JSON.toJSONString(paymentNotify));
return Result.builder()
.resultCode("SUCCESS")
.resultMessage("success.")
.resultStatus(ResultStatusType.S)
.build();
}
}
// other types of notifications
} catch (Exception e) {
// handle error condition
return Result.builder()
.resultCode("FAIL")
.resultMessage("fail.")
.resultStatus(ResultStatusType.F)
.build();
}
return Result.builder()
.resultCode("SYSTEM_ERROR")
.resultMessage("system error.")
.resultStatus(ResultStatusType.F)
.build();
}- After receiving the notification, you are not required to sign the response, but must reply to every notification request in the following standardized format, regardless of whether the payment was successful or not.
{
"result": {
"resultCode": "SUCCESS",
"resultStatus": "S",
"resultMessage": "success"
}
}Inquire about the payment result
Call the inquiryPayment API to initiate a query on the payment result. The payment status can be checked via polling or scheduled tasks after the payment is initiated.
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
}
}The following code shows a sample of the request message:
{
"paymentRequestId": "bc93d19e-e1f6-4b68-b6b1-3d6ddc2a****"
}The following code shows a sample of the response message:
{
"actualPaymentAmount": {
"currency": "USD",
"value": "1"
},
"customsDeclarationAmount": {
"currency": "CNY",
"value": "7"
},
"paymentAmount": {
"currency": "USD",
"value": "1"
},
"paymentId": "20250305194010800100188690281017336",
"paymentMethodType": "ALIPAY_CN",
"paymentRedirectUrl": "https://checkout.antom.com/checkout-page/pages/payment/index.html?sessionData=%2BCUim8L0KviXagaygm9xBL5jZ%2F75w6gAX1nn8pcuFuGkIsMoHtD6U88YSyMrMJvorbwnBg5uQv8e6pyvIpjDQQ%3D%3D%26%26SG%26%26188%26%26eyJleHRlbmRJbmZvIjoie1wiT1BFTl9NVUxUSV9QQVlNRU5UX0FCSUxJVFlcIjpcInRydWVcIixcImxvY2FsZVwiOlwiZW5fVVNcIixcImRpc3BsYXlBbnRvbUxvZ29cIjpcInRydWVcIn0iLCJwYXltZW50U2Vzc2lvbkNvbmZpZyI6eyJwYXltZW50TWV0aG9kQ2F0ZWdvcnlUeXBlIjoiQUxMIiwicHJvZHVjdFNjZW5lIjoiQ0hFQ0tPVVRfUEFZTUVOVCIsInByb2R1Y3RTY2VuZVZlcnNpb24iOiIxLjAifSwic2VjdXJpdHlDb25maWciOnsiYXBwSWQiOiIiLCJhcHBOYW1lIjoiT25lQWNjb3VudCIsImJpelRva2VuIjoiNlRjZGJyMnJGM3JQWXg0aGtWckhxYnZqIiwiZ2F0ZXdheSI6Imh0dHBzOi8vaW1ncy1zZWEuYWxpcGF5LmNvbS9tZ3cuaHRtIiwiaDVnYXRld2F5IjoiaHR0cHM6Ly9vcGVuLXNlYS1nbG9iYWwuYWxpcGF5LmNvbS9hcGkvb3Blbi9yaXNrX2NsaWVudCIsIndvcmtTcGFjZUlkIjoiIn0sInNraXBSZW5kZXJQYXltZW50TWV0aG9kIjpmYWxzZX0%3D",
"paymentRequestId": "PAYMENT_20250305220039086_AUTO",
"paymentResultCode": "SUCCESS",
"paymentResultMessage": "success.",
"paymentStatus": "SUCCESS",
"paymentTime": "2025-03-05T06:02:34-08:00",
"pspCustomerInfo": {
"pspName": "ALIPAY_CN"
},
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}The table below displays the possible values returned in the paymentStatus parameter of the response. Please follow the corresponding instructions for handling:
paymentStatus | Message | Further actions |
SUCCESS | Payment was successful. | No further action is required. |
FAIL | Payment failed. | Guide the buyer to place a new order. |
PROCESSING | Payment is being processed. | |
CANCELLED | Payment is canceled. |
Common questions
Q: When is the payment notification sent?
A: It depends on whether the payment is completed: If the payment is successfully completed, Antom usually sends an asynchronous notification within 3 to 5 seconds.
Q: Is there an asynchronous notification sent for authorization failure?
A: No. An asynchronous notification will only be sent if the authorization is successful; there will be no notification returned for authorization failure.
Q: Will the asynchronous notification be re-sent?
A: Yes, the asynchronous notification will be re-sent automatically within 24 hours for the following cases:
- If you didn't receive the asynchronous notification due to network reasons.
- If you receive an asynchronous notification from Antom, but you didn't make a response to the notification in the sample code format of Process the notification.
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.
Q: Are the authorization notification and payment result notification sent separately, and will the authorization notification always be received before the payment result notification?
A: Due to the uncontrollable nature of network stability, it is possible for the authorization notification to arrive later than the payment result notification.
Q: Is authorization result inquiry supported?
A: Currently, calling an interface to query the authorization result is not supported.
Q: When responding to an asynchronous notification, do I need to add a digital signature?
A: No. If you receive an asynchronous notification from Antom, you are required to return the response in the sample code format of Process the notification, but you do not need to countersign the response.
After payments
Revoke authorization
After authorization is completed, the buyer can revoke the authorization from either the merchant side or the payment method side. Once revoked, the original authorization token immediately becomes invalid and cannot be used for payments again. For details, refer to Revoke.
Cancel
You can cancel orders through the cancel API within the time window (by D+1 day 00:15 GMT+8). For details, refer to Cancel.
Refund
Reconciliation
After a transaction is completed, use the provided Antom financial reports to perform reconciliation. For settlement rules and reconciliation operations, refer to Reconciliation.
Best practices
Antom provides you with the following best practice solutions. Refer to Best practices for more details.
- Intelligent risk control service
- Security expansion package
- Order query after redirecting to the merchant result page
- Merchant-initiated transaction cancellation
- Payment failure retry