Payment Element recurring payments
Subscription Payment is a payment solution that supports periodic automatic deductions, helping you easily achieve automated recurring revenue collection. Buyers only need to complete a one-time authorization and binding to continuously enjoy subscription services, while also supporting flexible adjustments to subscription configurations (such as modifying cycles/amounts, canceling renewals, or terminating services). The entire process is secure, reliable, and user-friendly, balancing efficiency with transaction security.
Antom Payment Element is a payment component integrated via SDK, designed to provide a seamless payment experience and help increase conversion rates. For different client types, Antom offers the following solutions:
- Web/WAP: Web Element for browser and mobile web environments
- App (Android & iOS): Mobile Element designed for merchants' native mobile applications
The capabilities supported by Payment Element on each platform are shown in the table below:
Web/WAP
iOS
Android
User experience
The following figures illustrates the user experience of integrating Payment Element for the first-time subscription and subsequent deductions:
First-time subscription
APM payments
Card payments
The figure below illustrates the buyer's user experience for APM payments:

The figure below illustrates the buyer's user experience for card payments:

Subsequent deductions
Antom server will automatically initiate subsequent periodic deductions. The merchant server will receive subscription renewal payment notifications to renew the subscription service for the buyer. This process involves no page interaction.
Order lifecycle
Learn about the lifecycle of different payment methods:
APM Payments
Card payments, Apple Pay, Google Pay
The following figure illustrates the subscription lifecycle for APM payments, including creating a subscription, signing and binding a payment method, completing the initial deduction, and initiating refunds when necessary. This process ensures the normal activation of subscriptions and secure, transparent handling of fees:

The following figure illustrates the subscription lifecycle for card payments, Google Pay, and Apple Pay, including creating a subscription, signing and binding a payment method, completing the initial deduction, and initiating refunds when necessary. This process ensures the normal activation of subscriptions and secure, transparent handling of fees:


Payment flow
The following flow illustrates how to integrate Subscription Payment using Payment Element:
APM Payments
Card payments, Apple Pay, Google Pay
First-time subscription
Subsequent deductions


First-time subscription
Subsequent deductions


First-time subscription
Subsequent deductions
- The buyer enters the subscription product page and initiates payment.
Merchant client collects relevant information about the buyer's subscription. - Create a payment session request.
Call the createPaymentSession (One-time Payments) API to obtain the payment session. You can specify one or multiple payment method types, or leave the payment method type unspecified, to submit the payment request. - Invoke Payment Element.
On the client side, invoke Payment Element using the payment session. You can choose to use the Payment Element-rendered payment method list, or render the payment methods by specifying them yourself. Payment Element will handle information processing, collect payment details, perform redirects, manage app invocations, display QR codes, and conduct validations based on the features of the selected payment method. After the payment is completed, depending on your configuration and the payment method features, you need to handle redirections based on the result returned by thesubmitPayment().then()method, or the system will automatically return to your result page. - Obtain the authorization or payment result.
You can obtain the payment or authorization results through one of the following two methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (One-time Payments) API or configure on Antom Dashboard 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 payment or authorization status.
Note: For card payments and certain APM payment methods (such as Google Pay, Apple Pay and Pay by Bank), these payment methods follow an authorized-capture mode. The steps above only complete the authorization phase, indicates that the buyer has completed the payment using their card, and the funds are in a frozen state. To transfer the buyer's frozen funds to your account, you must integrate the capture step. The successful capture result will serve as the basis for shipping goods.
- (Optional) Capture and obtain the capture result.
By default, Antom automatically handles fund capture on your behalf. You can also manually capture funds by calling the capture (One-time Payments) API. The capture result can be obtained through one of the following methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (One-time Payments) API or configure on Antom Dashboard to set the address for receiving asynchronous notifications. Upon capture completion, Antom will send you asynchronous notifications via the notifyCapture (One-time Payments) API.
- Synchronous inquiry: Call the inquiryPayment API to check the capture status.
- Obtain subscription notifications.
Once the subscription is activated, Antom will send initial subscription notifications and subscription renewal notifications to you.
- Antom server initiates a deduction from the payment method.
- Obtain the authorization or payment result.
You can obtain the payment or authorization results through one of the following two methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (One-time Payments) API or configure on Antom Dashboard 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 payment or authorization status.
Note: For card payments and certain APM payment methods (such as Google Pay, Apple Pay and Pay by Bank), these payment methods follow an authorized-capture mode. The steps above only complete the authorization phase, indicates that the buyer has completed the payment using their card, and the funds are in a frozen state. To transfer the buyer's frozen funds to your account, you must integrate the capture step. The successful capture result will serve as the basis for shipping goods.
- (Optional) Capture and obtain the capture result.
For subsequent deductions, Antom automatically handles fund capture on your behalf. You can obtain the capture result through one of the following methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (One-time Payments) API or configure on Antom Dashboard to set the address for receiving asynchronous notifications. Upon capture completion, Antom will send you asynchronous notifications via the notifyCapture (One-time Payments) API.
- Synchronous inquiry: Call the inquiryPayment API to check the capture status.
- Obtain subscription notifications.
After the deduction is successful or fails, Antom will send you a subscription deduction notification.
Integration preparations
Before you start integrating, read Integration guide and API overview to understand the integration steps of the server-side API and the precautions for calling the API. Furthermore, ensure the following prerequisites are met:
- Obtained your 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.
- Integrate the client-side SDK package by following the steps detailed in Integrate the SDK package for Web/WAP, and ensure to use the latest SDK version or no lower than 1.46.0.
Integration steps
Start your integration by taking the following steps:
- Create a payment session
- Invoke Payment Element
- Obtain the authorization or payment result
- (Optional) Capture
- Obtain subscription notifications
Step 1: Create a payment session Server-side
Call the createPaymentSession (One-time Payments) API with order information to create a payment session and obtain the paymentSessionData required to invoke Payment Element. You can choose to either render the payment methods by specifying them yourself or use the Payment Element-rendered payment method list. Pass the corresponding parameters when calling the createPaymentSession (One-time Payments) API:
- Render the payment methods by yourself: When rendering the payment method list yourself, you must pass the parameters for specifying payment methods listed in the table below. Note that for certain payment methods (e.g., card payments), you need to embed the payment details component rendered by Payment Element. The optimal timing for calling the createPaymentSession (One-time Payments) API when offering card payment options is as follows:
- If Payment Element needs to collect payment details: Call the createPaymentSession (One-time Payments) API after the buyer selects the payment method, and pass the card payment parameters listed in the table.
- If Payment Element does not need to collect payment details: Call the createPaymentSession (One-time Payments) API after the buyer selects the payment method and submits payment.
- When using the Payment Element-rendered payment method list, you only need to pass the basic parameters listed in the table below. Payment Element renders all supported payment methods on the checkout page by default, but you can specify payment methods to display only the options you need.
The above parameters are the basic parameters for creating a payment session, for full parameters and additional requirements for certain payment methods refer to createPaymentSession (One-time Payments).
public ResponseEntity<ApiResponse> createPaymentSession(@RequestBody PaymentVO payment) {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.CASHIER_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.ELEMENT_PAYMENT);
// 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("SGD").build();
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
// 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);
// set subscription info
PeriodRule periodRule = PeriodRule.builder().periodCount(1).
periodType("MONTH").build();
List trials = new ArrayList<Trial>();
Trial trial = Trial.builder().
trialAmount(amount).
trialStartPeriod(1).
trialEndPeriod(2).
build();
trials.add(trial);
SubscriptionInfo subscriptionInfo = SubscriptionInfo.builder().
subscriptionDescription("Subscription description").
subscriptionStartTime("2026-03-11T09:48:17+08:00").
subscriptionEndTime("2026-11-21T09:48:17+08:00").
periodRule(periodRule).
trials(trials).
subscriptionNotifyUrl("https://your.example.com/subscriptionNotify").
subscriptionExpiryTime("2026-03-12T09:48:17+08:00").
build();
alipayPaymentSessionRequest.setSubscriptionInfo(subscriptionInfo);
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));
}Merchant-rendered payment method list
Payment Element-rendered payment method list
If you render the payment method list yourself, you must integrate by specifying individual payment methods. The following code shows a sample of the request message:
{
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "USD",
"value": "2900"
},
"orderDescription": "antom sdk testing order",
"referenceOrderId": "4b085ec4-9999-4296-8f00-479e929edb2c"
},
"paymentAmount": {
"currency": "USD",
"value": "2900"
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com/payment/receivePaymentNotify",
"paymentRedirectUrl": "http://google.com.my",
"paymentRequestId": "PAYMENT_20260313102551842_AUTO",
"productCode": "CASHIER_PAYMENT",
"productScene": "ELEMENT_PAYMENT",
"settlementStrategy": {
"settlementCurrency": "USD"
},
"availablePaymentMethod": {
"paymentMethodTypeList": [
{
"paymentMethodType": "ALIPAY_CN" // Specify payment method
},
{
"paymentMethodType": "TNG"
}
]
},
"subscriptionInfo": {
"periodRule": {
"periodCount": 1,
"periodType": "MONTH"
},
"subscriptionDescription": "Subscription description",
"subscriptionNotifyUrl": "https://your.example.com/subscriptionNotify",
"subscriptionStartTime": "2026-03-11T09:48:17+08:00"
}
}If you use Payment Element-rendered payment method list, Payment Element will display all supported payment methods by default. The following code shows a sample of the request message:
{
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "SGD",
"value": "2900"
},
"orderDescription": "antom sdk testing order",
"referenceOrderId": "4b085ec4-9999-4296-8f00-479e929edb2c"
},
"paymentAmount": {
"currency": "SGD",
"value": "2900"
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com/payment/receivePaymentNotify",
"paymentRedirectUrl": "http://localhost:8080/index.html?paymentRequestId=7a6252b5-6d58-4033-882e-2eff7f262b35",
"paymentRequestId": "7a6252b5-6d58-4033-882e-2eff7f262b35",
"productCode": "CASHIER_PAYMENT",
"productScene": "ELEMENT_PAYMENT",
"settlementStrategy": {
"settlementCurrency": "SGD"
},
"subscriptionInfo": {
"periodRule": {
"periodCount": 1,
"periodType": "MONTH"
},
"subscriptionDescription": "Subscription description",
"subscriptionEndTime": "2026-11-21T09:48:17+08:00",
"subscriptionExpiryTime": "2026-03-12T09:48:17+08:00",
"subscriptionNotifyUrl": "https://your.example.com/subscriptionNotify",
"subscriptionStartTime": "2026-03-11T09:48:17+08:00",
"trials": [
{
"trialAmount": {
"$ref": "$.order.orderAmount"
},
"trialEndPeriod": 2,
"trialStartPeriod": 1
}
]
}
}The following code shows a sample of the response, which contains the following parameters:
- result.resultStatus: The result of the createPaymentSession (One-time Payments) API call.
- paymentSessionData: The payment session data to be returned to the client.
- paymentSessionExpiryTime: The expiration time of the payment session.
{
"paymentSessionData": "WNoudiUNUDjHjx0oXddzWn0QrRHv52lrHFNMKc8/5uKSqNDklmQ7Nh4JGBNITqi3jgIASZkbpq15gIEQleY13A==&&SG&&188&&eyJhY3Rpb24iOnsibmVlZFZlcmlmeUFuZFJlc3VtZSI6ZmFsc2UsInNpZ25CdXR0b25EaXNwbGF5IjpmYWxzZSwic2tpcFNka1F1ZXJ5IjpmYWxzZSwidXNlclNpZ25BZ3JlZW1lbnQiOmZhbHNlfSwiY2xpZW50SWQiOiJTQU5EQk9YXzVZRVYxRzJaVjQzSzA3MjE3IiwiY29ubmVjdEZhY3RvciI6eyJlbmFibGVDb25uZWN0IjpmYWxzZX0sImVsaWdpYmxlRWFzeVBheU1hcmtldGluZyI6ZmFsc2UsImV4dGVuZEluZm8iOiJ7XCJPUEVOX01VTFRJX1BBWU1FTlRfQUJJTElUWVwiOlwidHJ1ZVwiLFwiZXhwcmVzc0NoZWNrb3V0XCI6XCJmYWxzZVwiLFwidmVyc2lvbk1hcFwiOlwie1xcXCJ3ZWJcXFwiOntcXFwiMS4xLjBcXFwiOntcXFwidGFyZ2V0V2ViVmVyaXNvblxcXCI6XFxcIjEuMS4wXFxcIn0sXFxcIjEuMi4wXFxcIjp7XFxcInRhcmdldFdlYlZlcmlzb25cXFwiOlxcXCIxLjIuMFxcXCJ9fSxcXFwiaU9TXFxcIjp7XFxcIjEuMS4wXFxcIjp7XFxcInRhcmdldFdlYlZlcmlzb25cXFwiOlxcXCIxLjEuMFxcXCJ9LFxcXCIxLjIuMFxcXCI6e1xcXCJ0YXJnZXRXZWJWZXJpc29uXFxcIjpcXFwiMS4yLjBcXFwifX0sXFxcIkFuZHJvaWRcXFwiOntcXFwiMS4xLjBcXFwiOntcXFwidGFyZ2V0V2ViVmVyaXNvblxcXCI6XFxcIjEuMS4wXFxcIn0sXFxcIjEuMi4wXFxcIjp7XFxcInRhcmdldFdlYlZlcmlzb25cXFwiOlxcXCIxLjIuMFxcXCJ9fX1cIn0iLCJuZWVkQWNjb3VudENvbmZpcm1QYWdlIjpmYWxzZSwicGF5bWVudFNlc3Npb25Db25maWciOnsicGF5bWVudE1ldGhvZENhdGVnb3J5VHlwZSI6IkFMTCIsInByb2R1Y3RTY2VuZSI6IkVMRU1FTlRfUEFZTUVOVCIsInByb2R1Y3RTY2VuZVZlcnNpb24iOiIxLjAifSwic2tpcFJlbmRlclBheW1lbnRNZXRob2QiOmZhbHNlfQ==",
"paymentSessionExpiryTime": "2026-03-12T15:24:24+08:00",
"paymentSessionId": "WNoudiUNUDjHjx0oXddzWn0QrRHv52lrHFNMKc8/5uIsshVVNylGbBzLF2n6JmoT",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}The table below shows the possible values of result.resultStatus in the response. Please handle the result according to the guidance provided:
Note: If no response is received, it may indicate a network timeout. Please use a new paymentRequestId and call the API again. If the issue persists, contact Antom Technical Support.
Common questions
Q: Can I use Chinese characters in the value of the request parameters?
A: To avoid incompatibility of certain payment methods, do not use Chinese characters for fields in the request.
Q: How to set the address to receive payment notification?
A: Specify paymentNotifyUrl in the createPaymentSession (One-time Payments) 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: Does the returned paymentSessionData require processing before passing it to the client?
A: Do not process or modify paymentSessionData in any way, as this may cause the Payment Element invocation to fail.
Q: Is 3DS authentication mandatory for the first transaction?
A: The first transaction requires buyer participation and identity verification to ensure the security of subsequent recurring payments (where the buyer is not present). Specific requirements are as follows:
- Buyer uses card payment: Whether you or Antom collects card information, 3DS authentication must be completed. You can set is3DSAuthentication to truein the createPaymentSession (One-time Payments) request to enable Antom 3DS authentication.
- Buyer uses Google Pay and Antom decrypts the data: You need to set is3DSAuthentication to trueto initiate a 3DS transaction for identity verification. If the decrypted data is a DPAN (Device Primary Account Number), the system will automatically proceed with the authorization process without requiring additional buyer verification.
- Buyer uses Apple Pay and Antom decrypts the data: You can set is3DSAuthentication to falseor omit this parameter, as the buyer has already completed Apple's verification process.
Step 2: Invoke Payment Element Client-side
Use paymentSessionData to invoke Payment Element on your client. After the buyer clicks to submit payment, Payment Element will handle the entire flow based on the selected payment method, including displaying QR codes, redirecting to payment pages, performing 3DS authentication, and returning to the merchant’s result page.
Depending on the rendering method you chose in Step 1 (merchant-rendered or Payment Element-rendered payment method list), the following table compares how to invoke Payment Element in different scenarios:
- After obtaining paymentSessionData from the server, use the class to create a Payment Element instance. The following sample code how to instantiate the SDK using CDN or npm:
CDN
npm
// Get the browser language
let language = navigator.language || navigator.userLanguage;
language = language.replace("-", "_"); // Replace "-" with "_"
// Create Payment Element instance
const elementPayment = new window.AMSElement({
environment: "sandbox",
locale: "en_US",
sessionData:sessionData
})import { AMSElement, ThemeType, PaymentElementLayout } from '@alipay/ams-checkout' // Package management
// Get the browser language
let language = navigator.language || navigator.userLanguage;
language = language.replace("-", "_"); // Replace "-" with "_"
// Create Payment Element instance
const elementPayment = new AMSElement({
environment: "sandbox",
locale: "en_US",
sessionData:sessionData
})- Use the method from the instance object to create the payment component, and embed the component into the specified view if needed. Before calling the method, you may add a loading indicator and close it when handling the callback in the .then()method. If the callback result contains error information, determine the specific error type via error?.code, and refer to the callback function event codes for detailed error causes and handling suggestions. If no error information is present, the method rendering was successful.
Note:
- If you need to embed the payment details collection component (see Payment methods requiring embedding for details), it is recommended that the container for the payment element have a minimum width of 375 px and no height restriction, allowing the Payment Element to automatically expand the container height.
- The different configuration of notRedirectAfterComplete in the method handles the redirection of the merchant page differently. For details, refer to Redirect to the merchant page.
let loading = false;
// Customize appearance
const appearance = {
theme: "default",
layout: { type: "Accordion" },
variables: {},
};
// Set external container loading state before calling mount
loading = true;
// Embed into the document.querySelector("#payment-element") node
elementPayment.mount(
{
type: 'payment',
appearance: appearance,
notRedirectAfterComplete: false,
},
'#payment-element',
).then(({ error }) => {
// Manually turn off external container loading state
loading = false;
// Handle error information, process exceptions based on error.code
if (error && error?.code) {
// PARAM_INVALID: SDK parameter exception, recommend checking integration code
// UI_STATE_ERROR: mount call timing exception, recommend checking integration code
console.log(error.message);
if(error?.code === 'INITIALIZE_API_TIMEOUT') {
// Payment information query API timeout causing checkout rendering failure, recommend guiding user to retry
} else if(error?.code === 'INITIALIZE_WEB_TIMEOUT'){
// Checkout static resource loading timeout, recommend guiding user to retry
} ...
return;
}
// mount rendering successful, no handling needed
})- After the buyer clicks your custom payment button, call the method to submit payment.
Before calling the method, you may add a loading indicator and close it when handling the callback in the.then()method. It is recommended to display the loading state after the buyer clicks the payment button to prevent repeated submissions within a short period. After receiving the payment result returned by Payment Element, guide the buyer to either retry the payment or redirect to the payment result page based on the actual outcome.
- If the callback result contains error information, you can simplify integration based on the status value. Refer to the sample code below for specific operations. You may also refer to error?.code for specific exception handling and refer to callback function event codes for detailed error causes and handling suggestions.
- If no error information exists, proceed with subsequent operations based on the status value.
let loading = false;
loading = true;
// When the buyer clicks the payment button:
elementPayment.submitPayment().then(({ error, status, userCanceled3D }) => {
// Manually turn off the external container's loading state
loading = false;
if (error) { // Handle error information first
const { code, message } = error;
if (userCanceled3D) {
// Buyer actively closed the 3D popup, recommend polling results from the server
}
if (status === 'PROCESSING') {
// Status unknown due to network exception or channel instability. Recommend polling results from the server
} else {
// FAIL - Failure
// Form validation failed, Payment Element has prompted the buyer, recommend ignoring
if (code === 'FORM_INVALID') {
return;
}
toast(message);
// Or customize experience based on code granularity
if (code ){
// xxx
}
}
return;
}
if (status === 'SUCCESS') {
// SUCCESS - Success. In some scenarios Payment Element will show a toast prompt, recommend directly redirecting to the result page
} else if(status === 'CANCELLED'){
// Order has been cancelled, can be ignored if not applicable to this scenario
} else {
// You can add monitoring
}
})
Unmount Payment Element
elementPayment.destroy();Common questions
Q: Can I integrate the Web Element using Webview in PC or mobile applications?
A: Currently not supported.
Step 3: Obtain the authorization or payment result Server-side
In the payment processing flow, Antom will send you corresponding result notifications based on the type of payment method used.
- For card payments, Google Pay, and Apple Pay, Antom sends authorization result notifications to inform you whether the authorization was successful. Only after a successful authorization will the fund capture be triggered. Please use the capture result as the basis for shipping goods.
- For APM payments, when the payment succeeds or fails, Antom will send you payment result notifications.
You can obtain payment or authorization results by receiving asynchronous notifications from Antom or by proactively querying.
Receive asynchronous notifications
Inquire about the result
1. Configure the webhook URL to receive asynchronous notifications
When a payment succeeds or fails, Antom will send an asynchronous notification to the webhook URL you set. You can choose one of the following two methods to configure the webhook URL for receiving notifications (if both are set, the URL specified in the request takes precedence):
- If each of your orders has a unique notification URL, it is recommended to set the webhook URL in each request. You can pass the asynchronous notification receiving URL for the specific order through paymentNotifyUrl in the createPaymentSession (One-time Payments) API.
- If all your orders share a unified notification URL, you can set the webhook URL on Antom Dashboard through Developer > Notification URL. For detailed steps, refer to Notification URL.
The following code shows a sample of the asynchronous notification request:
Card payments, Apple Pay, Google Pay
APM payments
{
"actualPaymentAmount": {
"currency": "SGD",
"value": "4200"
},
"cardInfo": {
"avsResultRaw": "A",
"cardBrand": "MASTERCARD",
"cardNo": "****************",
"cardToken":"exxxxe",
"cvvResultRaw": "Y",
"funding": "DEBIT",
"issuingCountry": "US",
"networkTransactionId": "XXXXX",
"paymentMethodRegion": "GLOBAL",
"threeDSResult": {
"cavv": "",
"eci": ""
}
},
"notifyType": "PAYMENT_RESULT",
"paymentAmount": {
"currency": "SGD",
"value": "4200"
},
"paymentMethodType": "CARD",
"paymentCreateTime": "2024-01-01T00:00:00+08:00",
"paymentId": "20240101123456789XXXX",
"paymentRequestId": "paymentRequestId01",
"paymentResultInfo": {
"avsResultRaw": "A",
"cardBrand": "MASTERCARD",
"cardNo": "****************",
"cardToken":"exxxxe", // store cardToken for future card payments
"cvvResultRaw": "Y",
"funding": "DEBIT",
"issuingCountry": "US",
"networkTransactionId": "XXXXX",
"paymentMethodRegion": "GLOBAL",
"threeDSResult": {
"cavv": "",
"eci": ""
}
},
"paymentTime": "2024-01-01T00:01:00+08:00",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}The following table shows the possible values of result.resultStatus in the notification request of payment result. Please handle the result according to the guidance provided:
{
"actualPaymentAmount": {
"currency": "HKD",
"value": "100"
},
"notifyType": "PAYMENT_RESULT",
"paymentAmount": {
"currency": "HKD",
"value": "100"
},
"paymentCreateTime": "2025-02-04T22:11:19-08:00",
"paymentId": "20240101123456789XXXX",
"paymentMethodType": "ALIPAY_HK",
"paymentRequestId": "paymentRequestId01",
"paymentResultInfo": {
},
"paymentTime": "2025-02-04T22:14:25-08:00",
"pspCustomerInfo": {
"pspCustomerId": "216022003753XXXX",
"pspName": "ALIPAY_HK"
},
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}The following table shows the possible values of result.resultStatus in the notification request of payment result. Please handle the result according to the guidance provided:
2. Verify the asynchronous notification
When you receive an asynchronous notification from Antom, you are required to return the response in the Sample code format, but you do not need to countersign the response.
You need to verify the signature of the payment notification sent by Antom:
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.alipay.global.api.model.Result;
import com.alipay.global.api.model.ResultStatusType;
import com.alipay.global.api.response.AlipayResponse;
import com.alipay.global.api.tools.WebhookTool;
@RestController
public class PaymentNotifyHandleBySDK {
/**
* alipay public key, used to verify signature
*/
private static final String SERVER_PUBLIC_KEY = "";
/**
* payment result notify processor
* using <a href="https://spring.io">Spring Framework</a>
*
* @param request HttpServletRequest
* @param notifyBody notify body
* @return
*/
@PostMapping("/payNotify")
public Object payNotifyHandler(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");
Result result;
AlipayResponse response = new AlipayResponse();
try {
// verify the signature of notification
boolean verifyResult = WebhookTool.checkSignature(requestUri, requestMethod, clientId, requestTime, signature, notifyBody, SERVER_PUBLIC_KEY);
if (!verifyResult) {
throw new RuntimeException("Invalid notify signature");
}
// deserialize the notification body
// update the order status with notify result
// respond the server that the notification is received
result = new Result("SUCCESS", "success", ResultStatusType.S);
} catch (Exception e) {
String errorMsg = e.getMessage();
// handle error condition
result = new Result("ERROR", errorMsg, ResultStatusType.F);
}
response.setResult(result);
return ResponseEntity.ok().body(response);
}
}Whether the payment is successful or not, 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"
}
}Common questions
Q: When will the notification be sent?
A: It depends on whether the payment is completed:
- If the payment is successfully completed, Antom will send you an asynchronous notification within 3 to 5 seconds. For some payment methods like OTC, the notification might take a bit longer.
- If the payment is not completed, Antom needs to close the order first before sending an asynchronous notification. The time it takes for different payment methods to close the order varies, usually defaulting to 14 minutes.
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 did not respond to the notification in the Sample code format.
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: When responding to an asynchronous notification, do I need to add a digital signature?
A: If you receive an asynchronous notification from Antom, you are required to return the response in the Sample code format, but you do not need to countersign the response.
Q: What key parameters do I need to use in the notification?
A: Please note the following key parameters:
A: Please note the following key parameters:
- result: For APM payments, it represents the final payment result. For Apple Pay, Google Pay, and card payments, it only represents the authorization result, and further capture is required.
- paymentRequestId: The payment request ID used for inquiries, cancellations, and reconciliation.
- paymentId: The payment order ID generated by Antom, used for refunds and reconciliation.
- paymentAmount: The payment amount.
You can also inquire about the payment or authorization result by calling the inquiryPayment API using paymentRequestId from the payment request, regardless of whether it is an APM payment, card payment, Apple Pay, or Google Pay.
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 sample code shows a request message:
{
"paymentRequestId": "paymentRequestId01"
}The following sample code shows a 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"
}
}Please handle the result based on the value of the paymentStatus parameter in the response. For specific return values, refer to the API documentation.
Common questions
Q: What key parameters should I pay attention to when using the inquiryPayment API to check the payment or authorization status?
A: Please note the following key parameters:
- result: Only indicates the result of the API call. For APM payments, the final payment result should be determined based on paymentStatus (SUCCESS/FAIL/PROCESSING). For card payments, Apple Pay, and Google Pay, paymentStatus only represents the authorization result, and the decision to ship goods should rely on the capture result.
- paymentAmount: Used to verify the payment amount.
- paymentId: The payment order ID generated by Antom, used for refunds and reconciliation.
Q: How often should I call the inquiryPayment API?
A: Call the inquiryPayment API constantly with an interval of 2 seconds until the final payment result is obtained or an asynchronous payment result notification is received.
(Optional) Step 4: Capture Server-side
Note: Card payments and certain APM payment methods (such as Google Pay, Apple Pay and Pay by Bank) must undergo a capture process, and capture will only be triggered after a successful authorization.
After successful authorization, Antom will automatically initiate capture by default, but also supports you to initiate manual capture. Antom will send the capture result notification to you via the notifyCapture (One-time Payments) API, while you can also query the capture result. You need to decide whether to ship goods based on the capture result. For specific operations, refer to Capture.
Step 5: Obtain subscription notifications Server-side
User experience
The following figures illustrates the user experience of integrating Payment Element for the first-time subscription and subsequent deductions:
First-time subscription
APM payments
Card payments
The figure below illustrates the buyer's user experience for APM payments:

The figure below illustrates the buyer's user experience for card payments:

Subsequent deductions
Antom server will automatically initiate subsequent periodic deductions. The merchant server will receive subscription renewal payment notifications to renew the subscription service for the buyer. This process involves no page interaction.
Order lifecycle
Learn about the lifecycle of different payment methods:
APM Payments
Card payments, Apple Pay, Google Pay
The following figure illustrates the subscription lifecycle for APM payments, including creating a subscription, signing and binding a payment method, completing the initial deduction, and initiating refunds when necessary. This process ensures the normal activation of subscriptions and secure, transparent handling of fees:

The following figure illustrates the subscription lifecycle for card payments, Google Pay, and Apple Pay, including creating a subscription, signing and binding a payment method, completing the initial deduction, and initiating refunds when necessary. This process ensures the normal activation of subscriptions and secure, transparent handling of fees:



Payment flow
The following flow illustrates how to integrate Subscription Payment using Payment Element:
APM Payments
Card payments, Apple Pay, Google Pay
First-time subscription
Subsequent deductions


First-time subscription
Subsequent deductions


First-time subscription
Subsequent deductions
- The buyer enters the subscription product page and initiates payment.
Merchant client collects relevant information about the buyer's subscription. - Create a payment session request.
Call the createPaymentSession (One-time Payments) API to obtain the payment session. You can specify one or multiple payment method types, or leave the payment method type unspecified, to submit the payment request. - Invoke Payment Element.
On the client side, invoke Payment Element using the payment session. You can choose to use the Payment Element-rendered payment method list, or render the payment methods by specifying them yourself. Payment Element will handle information processing, collect payment details, perform redirects, manage app invocations, display QR codes, and conduct validations based on the features of the selected payment method. After the payment is completed, depending on your configuration and the payment method features, you need to handle redirections based on the result returned by theonSubmitPayCallback:method, or the system will automatically return to your result page. - Obtain the authorization or payment result.
You can obtain the payment or authorization results through one of the following two methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (One-time Payments) API or configure on Antom Dashboard 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 payment or authorization status.
Note: For card payments and certain APM payment methods (such as Google Pay, Apple Pay and Pay by Bank), these payment methods follow an authorized-capture mode. The steps above only complete the authorization phase, indicates that the buyer has completed the payment using their card, and the funds are in a frozen state. To transfer the buyer's frozen funds to your account, you must integrate the capture step. The successful capture result will serve as the basis for shipping goods.
- (Optional) Capture and obtain the capture result.
By default, Antom automatically handles fund capture on your behalf. You can also manually capture funds by calling the capture (One-time Payments) API. The capture result can be obtained through one of the following methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (One-time Payments) API or configure on Antom Dashboard to set the address for receiving asynchronous notifications. Upon capture completion, Antom will send you asynchronous notifications via the notifyCapture (One-time Payments) API.
- Synchronous inquiry: Call the inquiryPayment API to check the capture status.
- Obtain subscription notifications.
Once the subscription is activated, Antom will send initial subscription notifications and subscription renewal notifications to you.
- Antom server initiates a deduction from the payment method.
- Obtain the authorization or payment result.
You can obtain the payment or authorization results through one of the following two methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (One-time Payments) API or configure on Antom Dashboard 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 payment or authorization status.
Note: For card payments and certain APM payment methods (such as Google Pay, Apple Pay and Pay by Bank), these payment methods follow an authorized-capture mode. The steps above only complete the authorization phase, indicates that the buyer has completed the payment using their card, and the funds are in a frozen state. To transfer the buyer's frozen funds to your account, you must integrate the capture step. The successful capture result will serve as the basis for shipping goods.
- (Optional) Capture and obtain the capture result.
For subsequent deductions, Antom automatically handles fund capture on your behalf. You can obtain the capture result through one of the following methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (One-time Payments) API or configure on Antom Dashboard to set the address for receiving asynchronous notifications. Upon capture completion, Antom will send you asynchronous notifications via the notifyCapture (One-time Payments) API.
- Synchronous inquiry: Call the inquiryPayment API to check the capture status.
- Obtain subscription notifications.
After the deduction is successful or fails, Antom will send you a subscription deduction notification.
Integration preparations
Before you start integrating, read Integration guide and API overview to understand the integration steps of the server-side API and the precautions for calling the API. Furthermore, ensure the following prerequisites are met:
- Obtained your 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.
- Integrate the client-side SDK package by following the steps detailed in Integrate the SDK package for iOS, and ensure to use the latest SDK version or no lower than 1.46.0.
Integration steps
Start your integration by taking the following steps:
- (Optional) Preload the SDK
- Create a payment session
- Invoke Payment Element
- Obtain the authorization or payment result
- (Optional) Capture
- Obtain subscription notifications
(Optional) Step 1: Preload the SDK Client-side
Before creating a payment session, it is highly recommended that you preload the SDK to improve the rendering speed of the checkout page, reducing the waiting time for buyers during the payment. Follow the code example below to perform the preloading:
[AMSPaymentElement.shared preload];Step 2: Create a payment session Server-side
Call the createPaymentSession (One-time Payments) API with order information to create a payment session and obtain the paymentSessionData required to invoke Payment Element. You can choose to either render the payment methods by specifying them yourself or use the Payment Element-rendered payment method list.
It is recommended that you create a payment session after the buyer clicks the payment button. Depending on the method you selected for rendering the payment method list at the checkout page, pass the corresponding parameters when calling the createPaymentSession (One-time Payments) API.
- Render the payment methods by yourself: When rendering the payment method list yourself, you must pass the parameters for specifying payment methods listed in the table below. If Payment Element needs to collect payment details, pass the card payment parameters listed in the table below.
- When using the Payment Element-rendered payment method list, you only need to pass the basic parameters listed in the table below. Payment Element renders all supported payment methods on the checkout page by default, but you can specify payment methods to display only the options you need.
The above parameters are the basic parameters for creating a payment session, for full parameters and additional requirements for certain payment methods refer to createPaymentSession (One-time Payments).
public ResponseEntity<ApiResponse> createPaymentSession(@RequestBody PaymentVO payment) {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.CASHIER_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.ELEMENT_PAYMENT);
// 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("SGD").build();
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
// 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);
// set subscription info
PeriodRule periodRule = PeriodRule.builder().periodCount(1).
periodType("MONTH").build();
List trials = new ArrayList<Trial>();
Trial trial = Trial.builder().
trialAmount(amount).
trialStartPeriod(1).
trialEndPeriod(2).
build();
trials.add(trial);
SubscriptionInfo subscriptionInfo = SubscriptionInfo.builder().
subscriptionDescription("Subscription description").
subscriptionStartTime("2026-03-11T09:48:17+08:00").
subscriptionEndTime("2026-11-21T09:48:17+08:00").
periodRule(periodRule).
trials(trials).
subscriptionNotifyUrl("https://your.example.com/subscriptionNotify").
subscriptionExpiryTime("2026-03-12T09:48:17+08:00").
build();
alipayPaymentSessionRequest.setSubscriptionInfo(subscriptionInfo);
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));
}Merchant-rendered payment method list
Payment Element-rendered payment method list
If you render the payment method list yourself, you must integrate by specifying individual payment methods. The following code shows a sample of the request message:
{
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "USD",
"value": "2900"
},
"orderDescription": "antom sdk testing order",
"referenceOrderId": "4b085ec4-9999-4296-8f00-479e929edb2c"
},
"paymentAmount": {
"currency": "USD",
"value": "2900"
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com/payment/receivePaymentNotify",
"paymentRedirectUrl": "http://google.com.my",
"paymentRequestId": "PAYMENT_20260313102551842_AUTO",
"productCode": "CASHIER_PAYMENT",
"productScene": "ELEMENT_PAYMENT",
"settlementStrategy": {
"settlementCurrency": "USD"
},
"availablePaymentMethod": {
"paymentMethodTypeList": [
{
"paymentMethodType": "ALIPAY_CN" // Specify payment method
},
{
"paymentMethodType": "TNG"
}
]
},
"subscriptionInfo": {
"periodRule": {
"periodCount": 1,
"periodType": "MONTH"
},
"subscriptionDescription": "Subscription description",
"subscriptionNotifyUrl": "https://your.example.com/subscriptionNotify",
"subscriptionStartTime": "2026-03-11T09:48:17+08:00"
}
}If you use Payment Element-rendered payment method list, Payment Element will display all supported payment methods by default. The following code shows a sample of the request message:
{
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "SGD",
"value": "2900"
},
"orderDescription": "antom sdk testing order",
"referenceOrderId": "4b085ec4-9999-4296-8f00-479e929edb2c"
},
"paymentAmount": {
"currency": "SGD",
"value": "2900"
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com/payment/receivePaymentNotify",
"paymentRedirectUrl": "http://localhost:8080/index.html?paymentRequestId=7a6252b5-6d58-4033-882e-2eff7f262b35",
"paymentRequestId": "7a6252b5-6d58-4033-882e-2eff7f262b35",
"productCode": "CASHIER_PAYMENT",
"productScene": "ELEMENT_PAYMENT",
"settlementStrategy": {
"settlementCurrency": "SGD"
},
"subscriptionInfo": {
"periodRule": {
"periodCount": 1,
"periodType": "MONTH"
},
"subscriptionDescription": "Subscription description",
"subscriptionEndTime": "2026-11-21T09:48:17+08:00",
"subscriptionExpiryTime": "2026-03-12T09:48:17+08:00",
"subscriptionNotifyUrl": "https://your.example.com/subscriptionNotify",
"subscriptionStartTime": "2026-03-11T09:48:17+08:00",
"trials": [
{
"trialAmount": {
"$ref": "$.order.orderAmount"
},
"trialEndPeriod": 2,
"trialStartPeriod": 1
}
]
}
}The following code shows a sample of the response, which contains the following parameters:
- result.resultStatus: The result of the createPaymentSession (One-time Payments) API call.
- paymentSessionData: The payment session data to be returned to the client.
- paymentSessionExpiryTime: The expiration time of the payment session.
{
"paymentSessionData": "WNoudiUNUDjHjx0oXddzWn0QrRHv52lrHFNMKc8/5uKSqNDklmQ7Nh4JGBNITqi3jgIASZkbpq15gIEQleY13A==&&SG&&188&&eyJhY3Rpb24iOnsibmVlZFZlcmlmeUFuZFJlc3VtZSI6ZmFsc2UsInNpZ25CdXR0b25EaXNwbGF5IjpmYWxzZSwic2tpcFNka1F1ZXJ5IjpmYWxzZSwidXNlclNpZ25BZ3JlZW1lbnQiOmZhbHNlfSwiY2xpZW50SWQiOiJTQU5EQk9YXzVZRVYxRzJaVjQzSzA3MjE3IiwiY29ubmVjdEZhY3RvciI6eyJlbmFibGVDb25uZWN0IjpmYWxzZX0sImVsaWdpYmxlRWFzeVBheU1hcmtldGluZyI6ZmFsc2UsImV4dGVuZEluZm8iOiJ7XCJPUEVOX01VTFRJX1BBWU1FTlRfQUJJTElUWVwiOlwidHJ1ZVwiLFwiZXhwcmVzc0NoZWNrb3V0XCI6XCJmYWxzZVwiLFwidmVyc2lvbk1hcFwiOlwie1xcXCJ3ZWJcXFwiOntcXFwiMS4xLjBcXFwiOntcXFwidGFyZ2V0V2ViVmVyaXNvblxcXCI6XFxcIjEuMS4wXFxcIn0sXFxcIjEuMi4wXFxcIjp7XFxcInRhcmdldFdlYlZlcmlzb25cXFwiOlxcXCIxLjIuMFxcXCJ9fSxcXFwiaU9TXFxcIjp7XFxcIjEuMS4wXFxcIjp7XFxcInRhcmdldFdlYlZlcmlzb25cXFwiOlxcXCIxLjEuMFxcXCJ9LFxcXCIxLjIuMFxcXCI6e1xcXCJ0YXJnZXRXZWJWZXJpc29uXFxcIjpcXFwiMS4yLjBcXFwifX0sXFxcIkFuZHJvaWRcXFwiOntcXFwiMS4xLjBcXFwiOntcXFwidGFyZ2V0V2ViVmVyaXNvblxcXCI6XFxcIjEuMS4wXFxcIn0sXFxcIjEuMi4wXFxcIjp7XFxcInRhcmdldFdlYlZlcmlzb25cXFwiOlxcXCIxLjIuMFxcXCJ9fX1cIn0iLCJuZWVkQWNjb3VudENvbmZpcm1QYWdlIjpmYWxzZSwicGF5bWVudFNlc3Npb25Db25maWciOnsicGF5bWVudE1ldGhvZENhdGVnb3J5VHlwZSI6IkFMTCIsInByb2R1Y3RTY2VuZSI6IkVMRU1FTlRfUEFZTUVOVCIsInByb2R1Y3RTY2VuZVZlcnNpb24iOiIxLjAifSwic2tpcFJlbmRlclBheW1lbnRNZXRob2QiOmZhbHNlfQ==",
"paymentSessionExpiryTime": "2026-03-12T15:24:24+08:00",
"paymentSessionId": "WNoudiUNUDjHjx0oXddzWn0QrRHv52lrHFNMKc8/5uIsshVVNylGbBzLF2n6JmoT",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}The table below shows the possible values of result.resultStatus in the response. Please handle the result according to the guidance provided:
Note: If no response is received, it may indicate a network timeout. Please use a new paymentRequestId and call the API again. If the issue persists, contact Antom Technical Support.
Common questions
Q: Can I use Chinese characters in the value of the request parameters?
A: To avoid incompatibility of certain payment methods, do not use Chinese characters for fields in the request.
Q: How to set the address to receive payment notification?
A: Specify paymentNotifyUrl in the createPaymentSession (One-time Payments) 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: Does the returned paymentSessionData require processing before passing it to the client?
A: Do not process or modify paymentSessionData in any way, as this may cause the Payment Element invocation to fail.
Q: Is 3DS authentication mandatory for the first transaction?
A: The first transaction requires buyer participation and identity verification to ensure the security of subsequent recurring payments (where the buyer is not present). Specific requirements are as follows:
- Buyer uses card payment: Whether you or Antom collects card information, 3DS authentication must be completed. You can set is3DSAuthentication to truein the createPaymentSession (One-time Payments) request to enable Antom 3DS authentication.
- Buyer uses Google Pay and Antom decrypts the data: You need to set is3DSAuthentication to trueto initiate a 3DS transaction for identity verification. If the decrypted data is a DPAN (Device Primary Account Number), the system will automatically proceed with the authorization process without requiring additional buyer verification.
- Buyer uses Apple Pay and Antom decrypts the data: You can set is3DSAuthentication to falseor omit this parameter, as the buyer has already completed Apple's verification process.
Step 3: Invoke Payment Element Client-side
Use paymentSessionData to invoke Payment Element on your client. After the buyer clicks to submit payment, Payment Element will handle the entire flow based on the selected payment method, including displaying QR codes, redirecting to payment pages, performing 3DS authentication, and returning to the merchant’s result page.
- After obtaining paymentSessionData from the server, use the AMSPaymentElementclass to create a Payment Element instance.
- Creating the AMSPaymentElementConfigurationobject includes the following parameters:
- Implement AMSPaymentProtocolto handle corresponding events in subsequent processes. It includes the following methods:
The following shows a sample code for creating the Payment Element instance using
AMSPaymentElement
:#import <AMSComponent/AMSComponent-Swift.h>
// Create an AMSPaymentElementConfiguration object
AMSPaymentElementConfiguration *componentConfig = [AMSPaymentElementConfiguration new];
componentConfig.locale = @"en_US";
NSString *appearance = @"{\n \"theme\": \"night\",\n \"layout\": {\n \"type\": \"Tabs\"\n },\n \"variables\": {\n \"content-quaternary\": \"#FFFF00\"\n }\n}";
// Set sandbox environment. If left empty, the online production environment will be used by default
NSDictionary *options = @{@"showLoading": @"true",
@"sandbox": @"true",
@"appearance": appearance
};
componentConfig.options = options;
// initConfiguration usage
[[AMSPaymentElement shared] initConfiguration:componentConfig completion:^(AMSStatusResult * _Nonnull result) {
// Handle error events during the initConfiguration phase
if (result.error) {
// Handle failure
if ([result.error.code isEqualToString:@"UI_STATE_ERROR"]) {
NSLog(@"integration code error, please check the integration code");
} else {
NSLog(@"unknown error, please contact support");
}
} else {
// Handle success
}
}];
// Set callback to listen for payment events on the checkout page
[AMSPaymentElement shared].paymentDelegate = self;
// Server calls the Create Payment Session API to obtain paymentSessionData
#pragma AMSPaymentProtocol
// Handle submitPay phase event codes via callback
- (void)onSubmitPayCallback:(AMSStatusResult *)eventResult {
AMSStatusResultType statusType = eventResult.status;
AMSResultError *error = eventResult.error;
switch (statusType) {
case AMSStatusResultTypePROCESSING:
if (error && error.code) {
if ([@"PAYMENT_IN_PROCESS" isEqualToString:error.code]) {
NSLog(@"payment is in processing, please try polling the payment result from the server");
} else if ([@"USER_CANCELED" isEqualToString:error.code]) {
NSLog(@"user cancelled the payment process, please try invoke createComponent again");
} else if ([@"UNKNOWN_EXCEPTION" isEqualToString:error.code]) {
NSLog(@"unknown exception, please contact support");
} else if ([@"PAYMENT_RESULT_TIMEOUT" isEqualToString:error.code]) {
NSLog(@"get payment result timeout, please try polling the payment result from the server");
}
}
break;
case AMSStatusResultTypeCANCELLED:
// fall through
case AMSStatusResultTypeSUCCESS:
NSLog(@"payment cancelled or success, do nothing");
break;
case AMSStatusResultTypeFAIL:
if (error && error.code) {
if ([@"ORDER_IS_CANCELLED" isEqualToString:error.code]) {
NSLog(@"the merchant has proactively canceled the order, please check on your own.");
} else if ([@"ORDER_IS_CLOSED" isEqualToString:error.code]) {
NSLog(@"the order has timed out and is closed, please re-initiate payment using a new paymentRequestId.");
} else {
NSLog(@"unknown error, please contact support");
}
}
break;
default:
break;
}
}- Use the createComponentfunction from the instance object to invoke Payment Element:
// Callback event code method - createComponent usage
[[AMSPaymentElement shared] createComponent:paymentSessionData completion:^(AMSStatusResult * _Nonnull result) {
if (result.error) {
// Handle failure
if ([result.error.code isEqualToString:@"UI_STATE_ERROR"]) {
NSLog(@"integration code error, please check the integration code");
} else if ([result.error.code isEqualToString:@"PARAM_INVALID"]) {
NSLog(@"session data invalid, please check the session data");
} else if ([result.error.code isEqualToString:@"INITIALIZE_WEB_TIMEOUT"]) {
NSLog(@"web app timeout, please invoke component again");
} else {
NSLog(@"unknown error, please contact support");
}
} else {
// Handle success
}
}];
Unmount Payment Element
Call the
onDestroy
method to release SDK component resources in the following scenarios:- When the buyer navigates away from the checkout page, release the component resources created by the createPaymentSession (One-time Payments) API.
- When the buyer initiates multiple payments and the parameters in initConfigurationhad changed, release the component resources previously created by the createPaymentSession (One-time Payments) API.
// Release SDK component resources
[[AMSPaymentElement shared] onDestroy];You do not need to call
onDestroy
in the following scenarios, the SDK automatically releases resources:- When the buyer initiates multiple payments and the parameters in AMSPaymentElementConfigurationremain unchanged. The SDK will automatically reclaim some resources after payment concludes to reset to the state beforecreateComponent.
Redirect to the merchant page
The following scenarios describe how redirecting to the merchant page and returning payment results are handled. Please follow the guidelines below:
Note:
- If the payment requires redirecting to an external page (the payment method does not support payment within the SDK), the payment result will not be returned via onSubmitPayCallback:. After completing the payment on the external payment page, the payment method will determine whether to automatically redirect back to the paymentRedirectUrl you provided.
- The payment results returned by the onSubmitPayCallback:method are only for client-side page navigation and status display. For the final order status, please obtain it through Step 4: Obtain the authorization or payment result.
Common questions
Q: What should be noted when passing the paymentRedirectUrl parameter?
A: paymentRedirectUrl must be set to an HTTPS address. Additionally, do not encode special characters in the URL, as this may cause abnormalities in the payment process.
Q: How should the payment result page be displayed?
A: Follow these recommendations for display:
- You need to pass an HTTPS address via the paymentRedirectUrl parameter in the payment request to display the payment result on the merchant side.
- If notRedirectAfterComplete is set to truewhen creating the Payment Element instance, and the payment method supports completion within the SDK, the payment result will be returned viasubmitPayment().then(). Handle the redirection logic based on the{code, status}in the response.
- Whether the subscription creation succeeds or fails, the buyer may return to the merchant page from the payment method side. Do not set paymentRedirectUrl to a fixed "subscription payment success page." Instead, you should the display result page based on the actual results returned by the server to avoid misleading the buyer.
Q: Does returning to the merchant result page indicate that the subscription payment was created successfully?
A: You cannot determine whether the subscription was created successfully solely based on the redirection to the merchant page. Key reasons include:
- After the buyer successfully creates a subscription payment, they may fail to return to the merchant page due to network abnormalities or other reasons.
- Even if the buyer does not complete the subscription payment, they may still return to the merchant page via the payment method side.
- Even if the buyer completes the subscription payment authentication, the subscription will not take effect if the initial deduction fails.
Step 4: Obtain the authorization or payment result Server-side
In the payment processing flow, Antom will send you corresponding result notifications based on the type of payment method used.
- For card payments, Google Pay, and Apple Pay, Antom sends authorization result notifications to inform you whether the authorization was successful. Only after a successful authorization will the fund capture be triggered. Please use the capture result as the basis for shipping goods.
- For APM payments, when the payment succeeds or fails, Antom will send you payment result notifications.
You can obtain payment or authorization results by receiving asynchronous notifications from Antom or by proactively querying.
Receive asynchronous notifications
Inquire about the result
1. Configure the webhook URL to receive asynchronous notifications
When a payment succeeds or fails, Antom will send an asynchronous notification to the webhook URL you set. You can choose one of the following two methods to configure the webhook URL for receiving notifications (if both are set, the URL specified in the request takes precedence):
- If each of your orders has a unique notification URL, it is recommended to set the webhook URL in each request. You can pass the asynchronous notification receiving URL for the specific order through paymentNotifyUrl in the createPaymentSession (One-time Payments) API.
- If all your orders share a unified notification URL, you can set the webhook URL on Antom Dashboard through Developer > Notification URL. For detailed steps, refer to Notification URL.
The following code shows a sample of the asynchronous notification request:
Card payments, Apple Pay, Google Pay
APM payments
{
"actualPaymentAmount": {
"currency": "SGD",
"value": "4200"
},
"cardInfo": {
"avsResultRaw": "A",
"cardBrand": "MASTERCARD",
"cardNo": "****************",
"cardToken":"exxxxe",
"cvvResultRaw": "Y",
"funding": "DEBIT",
"issuingCountry": "US",
"networkTransactionId": "XXXXX",
"paymentMethodRegion": "GLOBAL",
"threeDSResult": {
"cavv": "",
"eci": ""
}
},
"notifyType": "PAYMENT_RESULT",
"paymentAmount": {
"currency": "SGD",
"value": "4200"
},
"paymentMethodType": "CARD",
"paymentCreateTime": "2024-01-01T00:00:00+08:00",
"paymentId": "20240101123456789XXXX",
"paymentRequestId": "paymentRequestId01",
"paymentResultInfo": {
"avsResultRaw": "A",
"cardBrand": "MASTERCARD",
"cardNo": "****************",
"cardToken":"exxxxe", // store cardToken for future card payments
"cvvResultRaw": "Y",
"funding": "DEBIT",
"issuingCountry": "US",
"networkTransactionId": "XXXXX",
"paymentMethodRegion": "GLOBAL",
"threeDSResult": {
"cavv": "",
"eci": ""
}
},
"paymentTime": "2024-01-01T00:01:00+08:00",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}The following table shows the possible values of result.resultStatus in the notification request of payment result. Please handle the result according to the guidance provided:
{
"actualPaymentAmount": {
"currency": "HKD",
"value": "100"
},
"notifyType": "PAYMENT_RESULT",
"paymentAmount": {
"currency": "HKD",
"value": "100"
},
"paymentCreateTime": "2025-02-04T22:11:19-08:00",
"paymentId": "20240101123456789XXXX",
"paymentMethodType": "ALIPAY_HK",
"paymentRequestId": "paymentRequestId01",
"paymentResultInfo": {
},
"paymentTime": "2025-02-04T22:14:25-08:00",
"pspCustomerInfo": {
"pspCustomerId": "216022003753XXXX",
"pspName": "ALIPAY_HK"
},
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}The following table shows the possible values of result.resultStatus in the notification request of payment result. Please handle the result according to the guidance provided:
2. Verify the asynchronous notification
When you receive an asynchronous notification from Antom, you are required to return the response in the Sample code format, but you do not need to countersign the response.
You need to verify the signature of the payment notification sent by Antom:
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.alipay.global.api.model.Result;
import com.alipay.global.api.model.ResultStatusType;
import com.alipay.global.api.response.AlipayResponse;
import com.alipay.global.api.tools.WebhookTool;
@RestController
public class PaymentNotifyHandleBySDK {
/**
* alipay public key, used to verify signature
*/
private static final String SERVER_PUBLIC_KEY = "";
/**
* payment result notify processor
* using <a href="https://spring.io">Spring Framework</a>
*
* @param request HttpServletRequest
* @param notifyBody notify body
* @return
*/
@PostMapping("/payNotify")
public Object payNotifyHandler(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");
Result result;
AlipayResponse response = new AlipayResponse();
try {
// verify the signature of notification
boolean verifyResult = WebhookTool.checkSignature(requestUri, requestMethod, clientId, requestTime, signature, notifyBody, SERVER_PUBLIC_KEY);
if (!verifyResult) {
throw new RuntimeException("Invalid notify signature");
}
// deserialize the notification body
// update the order status with notify result
// respond the server that the notification is received
result = new Result("SUCCESS", "success", ResultStatusType.S);
} catch (Exception e) {
String errorMsg = e.getMessage();
// handle error condition
result = new Result("ERROR", errorMsg, ResultStatusType.F);
}
response.setResult(result);
return ResponseEntity.ok().body(response);
}
}Whether the payment is successful or not, 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"
}
}Common questions
Q: When will the notification be sent?
A: It depends on whether the payment is completed:
- If the payment is successfully completed, Antom will send you an asynchronous notification within 3 to 5 seconds. For some payment methods like OTC, the notification might take a bit longer.
- If the payment is not completed, Antom needs to close the order first before sending an asynchronous notification. The time it takes for different payment methods to close the order varies, usually defaulting to 14 minutes.
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 did not respond to the notification in the Sample code format.
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: When responding to an asynchronous notification, do I need to add a digital signature?
A: If you receive an asynchronous notification from Antom, you are required to return the response in the Sample code format, but you do not need to countersign the response.
Q: What key parameters do I need to use in the notification?
A: Please note the following key parameters:
A: Please note the following key parameters:
- result: For APM payments, it represents the final payment result. For Apple Pay, Google Pay, and card payments, it only represents the authorization result, and further capture is required.
- paymentRequestId: The payment request ID used for inquiries, cancellations, and reconciliation.
- paymentId: The payment order ID generated by Antom, used for refunds and reconciliation.
- paymentAmount: The payment amount.
You can also inquire about the payment or authorization result by calling the inquiryPayment API using paymentRequestId from the payment request, regardless of whether it is an APM payment, card payment, Apple Pay, or Google Pay.
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 sample code shows a request message:
{
"paymentRequestId": "paymentRequestId01"
}The following sample code shows a 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"
}
}Please handle the result based on the value of the paymentStatus parameter in the response. For specific return values, refer to the API documentation.
Common questions
Q: What key parameters should I pay attention to when using the inquiryPayment API to check the payment or authorization status?
A: Please note the following key parameters:
- result: Only indicates the result of the API call. For APM payments, the final payment result should be determined based on paymentStatus (SUCCESS/FAIL/PROCESSING). For card payments, Apple Pay, and Google Pay, paymentStatus only represents the authorization result, and the decision to ship goods should rely on the capture result.
- paymentAmount: Used to verify the payment amount.
- paymentId: The payment order ID generated by Antom, used for refunds and reconciliation.
Q: How often should I call the inquiryPayment API?
A: Call the inquiryPayment API constantly with an interval of 2 seconds until the final payment result is obtained or an asynchronous payment result notification is received.
(Optional) Step 5: Capture Server-side
Note: Card payments and certain APM payment methods (such as Google Pay, Apple Pay and Pay by Bank) must undergo a capture process, and capture will only be triggered after a successful authorization.
After successful authorization, Antom will automatically initiate capture by default, but also supports you to initiate manual capture. Antom will send the capture result notification to you via the notifyCapture (One-time Payments) API, while you can also query the capture result. You need to decide whether to ship goods based on the capture result. For specific operations, refer to Capture.
Step 6: Obtain subscription notifications Server-side
User experience
The following figures illustrates the user experience of integrating Payment Element for the first-time subscription and subsequent deductions:
First-time subscription
APM payments
Card payments
The figure below illustrates the buyer's user experience for APM payments:

The figure below illustrates the buyer's user experience for card payments:

Subsequent deductions
Antom server will automatically initiate subsequent periodic deductions. The merchant server will receive subscription renewal payment notifications to renew the subscription service for the buyer. This process involves no page interaction.
Order lifecycle
Learn about the lifecycle of different payment methods:
APM Payments
Card payments, Apple Pay, Google Pay
The following figure illustrates the subscription lifecycle for APM payments, including creating a subscription, signing and binding a payment method, completing the initial deduction, and initiating refunds when necessary. This process ensures the normal activation of subscriptions and secure, transparent handling of fees:

The following figure illustrates the subscription lifecycle for card payments, Google Pay, and Apple Pay, including creating a subscription, signing and binding a payment method, completing the initial deduction, and initiating refunds when necessary. This process ensures the normal activation of subscriptions and secure, transparent handling of fees:


Payment flow
The following flow illustrates how to integrate Subscription Payment using Payment Element:
APM Payments
Card payments, Apple Pay, Google Pay
First-time subscription
Subsequent deductions


First-time subscription
Subsequent deductions


First-time subscription
Subsequent deductions
- The buyer enters the subscription product page and initiates payment.
Merchant client collects relevant information about the buyer's subscription. - Create a payment session request.
Call the createPaymentSession (One-time Payments) API to obtain the payment session. You can specify one or multiple payment method types, or leave the payment method type unspecified, to submit the payment request. - Invoke Payment Element.
On the client side, invoke Payment Element using the payment session. You can choose to use the Payment Element-rendered payment method list, or render the payment methods by specifying them yourself. Payment Element will handle information processing, collect payment details, perform redirects, manage app invocations, display QR codes, and conduct validations based on the features of the selected payment method. After the payment is completed, depending on your configuration and the payment method features, you need to handle redirections based on the result returned by theonSubmitPayCallbackmethod, or the system will automatically return to your result page. - Obtain the authorization or payment result.
You can obtain the payment or authorization results through one of the following two methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (One-time Payments) API or configure on Antom Dashboard 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 payment or authorization status.
Note: For card payments and certain APM payment methods (such as Google Pay, Apple Pay and Pay by Bank), these payment methods follow an authorized-capture mode. The steps above only complete the authorization phase, indicates that the buyer has completed the payment using their card, and the funds are in a frozen state. To transfer the buyer's frozen funds to your account, you must integrate the capture step. The successful capture result will serve as the basis for shipping goods.
- (Optional) Capture and obtain the capture result.
By default, Antom automatically handles fund capture on your behalf. You can also manually capture funds by calling the capture (One-time Payments) API. The capture result can be obtained through one of the following methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (One-time Payments) API or configure on Antom Dashboard to set the address for receiving asynchronous notifications. Upon capture completion, Antom will send you asynchronous notifications via the notifyCapture (One-time Payments) API.
- Synchronous inquiry: Call the inquiryPayment API to check the capture status.
- Obtain subscription notifications.
Once the subscription is activated, Antom will send initial subscription notifications and subscription renewal notifications to you.
- Antom server initiates a deduction from the payment method.
- Obtain the authorization or payment result.
You can obtain the payment or authorization results through one of the following two methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (One-time Payments) API or configure on Antom Dashboard 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 payment or authorization status.
Note: For card payments and certain APM payment methods (such as Google Pay, Apple Pay and Pay by Bank), these payment methods follow an authorized-capture mode. The steps above only complete the authorization phase, indicates that the buyer has completed the payment using their card, and the funds are in a frozen state. To transfer the buyer's frozen funds to your account, you must integrate the capture step. The successful capture result will serve as the basis for shipping goods.
- (Optional) Capture and obtain the capture result.
For subsequent deductions, Antom automatically handles fund capture on your behalf. You can obtain the capture result through one of the following methods:
- Asynchronous notification: Specify paymentNotifyUrl in the createPaymentSession (One-time Payments) API or configure on Antom Dashboard to set the address for receiving asynchronous notifications. Upon capture completion, Antom will send you asynchronous notifications via the notifyCapture (One-time Payments) API.
- Synchronous inquiry: Call the inquiryPayment API to check the capture status.
- Obtain subscription notifications.
After the deduction is successful or fails, Antom will send you a subscription deduction notification.
Integration preparations
Before you start integrating, read Integration guide and API overview to understand the integration steps of the server-side API and the precautions for calling the API. Furthermore, ensure the following prerequisites are met:
- Obtained your 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.
- Integrate the client-side SDK package by following the steps detailed in Integrate the SDK package for Android, and ensure to use the latest SDK version or no lower than 1.46.0.
Integration steps
Start your integration by taking the following steps:
- (Optional) Preload the SDK
- Create a payment session
- Invoke Payment Element
- Obtain the authorization or payment result
- (Optional) Capture
- Obtain subscription notifications
(Optional) Step 1: Preload the SDK Client-side
Before creating a payment session, it is highly recommended that you preload the SDK to improve the rendering speed of the checkout page, reducing the waiting time for buyers during the payment. Follow the code example below to perform the preloading:
AMSPaymentElement.preload(getApplicationContext());Step 2: Create a payment session Server-side
Call the createPaymentSession (One-time Payments) API with order information to create a payment session and obtain the paymentSessionData required to invoke Payment Element. You can choose to either render the payment methods by specifying them yourself or use the Payment Element-rendered payment method list.
It is recommended that you create a payment session after the buyer clicks the payment button. Depending on the method you selected for rendering the payment method list at the checkout page, pass the corresponding parameters when calling the createPaymentSession (One-time Payments) API.
- Render the payment methods by yourself: When rendering the payment method list yourself, you must pass the parameters for specifying payment methods listed in the table below. If Payment Element needs to collect payment details, pass the card payment parameters listed in the table below.
- When using the Payment Element-rendered payment method list, you only need to pass the basic parameters listed in the table below. Payment Element renders all supported payment methods on the checkout page by default, but you can specify payment methods to display only the options you need.
The above parameters are the basic parameters for creating a payment session, for full parameters and additional requirements for certain payment methods refer to createPaymentSession (One-time Payments).
public ResponseEntity<ApiResponse> createPaymentSession(@RequestBody PaymentVO payment) {
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setProductCode(ProductCodeType.CASHIER_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.ELEMENT_PAYMENT);
// 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("SGD").build();
alipayPaymentSessionRequest.setSettlementStrategy(settlementStrategy);
// 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);
// set subscription info
PeriodRule periodRule = PeriodRule.builder().periodCount(1).
periodType("MONTH").build();
List trials = new ArrayList<Trial>();
Trial trial = Trial.builder().
trialAmount(amount).
trialStartPeriod(1).
trialEndPeriod(2).
build();
trials.add(trial);
SubscriptionInfo subscriptionInfo = SubscriptionInfo.builder().
subscriptionDescription("Subscription description").
subscriptionStartTime("2026-03-11T09:48:17+08:00").
subscriptionEndTime("2026-11-21T09:48:17+08:00").
periodRule(periodRule).
trials(trials).
subscriptionNotifyUrl("https://your.example.com/subscriptionNotify").
subscriptionExpiryTime("2026-03-12T09:48:17+08:00").
build();
alipayPaymentSessionRequest.setSubscriptionInfo(subscriptionInfo);
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));
}Merchant-rendered payment method list
Payment Element-rendered payment method list
If you render the payment method list yourself, you must integrate by specifying individual payment methods. The following code shows a sample of the request message:
{
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "USD",
"value": "2900"
},
"orderDescription": "antom sdk testing order",
"referenceOrderId": "4b085ec4-9999-4296-8f00-479e929edb2c"
},
"paymentAmount": {
"currency": "USD",
"value": "2900"
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com/payment/receivePaymentNotify",
"paymentRedirectUrl": "http://google.com.my",
"paymentRequestId": "PAYMENT_20260313102551842_AUTO",
"productCode": "CASHIER_PAYMENT",
"productScene": "ELEMENT_PAYMENT",
"settlementStrategy": {
"settlementCurrency": "USD"
},
"availablePaymentMethod": {
"paymentMethodTypeList": [
{
"paymentMethodType": "ALIPAY_CN" // Specify payment method
},
{
"paymentMethodType": "TNG"
}
]
},
"subscriptionInfo": {
"periodRule": {
"periodCount": 1,
"periodType": "MONTH"
},
"subscriptionDescription": "Subscription description",
"subscriptionNotifyUrl": "https://your.example.com/subscriptionNotify",
"subscriptionStartTime": "2026-03-11T09:48:17+08:00"
}
}If you use Payment Element-rendered payment method list, Payment Element will display all supported payment methods by default. The following code shows a sample of the request message:
{
"order": {
"buyer": {
"referenceBuyerId": "yourBuyerId"
},
"orderAmount": {
"currency": "SGD",
"value": "2900"
},
"orderDescription": "antom sdk testing order",
"referenceOrderId": "4b085ec4-9999-4296-8f00-479e929edb2c"
},
"paymentAmount": {
"currency": "SGD",
"value": "2900"
},
"paymentNotifyUrl": "http://www.yourNotifyUrl.com/payment/receivePaymentNotify",
"paymentRedirectUrl": "http://localhost:8080/index.html?paymentRequestId=7a6252b5-6d58-4033-882e-2eff7f262b35",
"paymentRequestId": "7a6252b5-6d58-4033-882e-2eff7f262b35",
"productCode": "CASHIER_PAYMENT",
"productScene": "ELEMENT_PAYMENT",
"settlementStrategy": {
"settlementCurrency": "SGD"
},
"subscriptionInfo": {
"periodRule": {
"periodCount": 1,
"periodType": "MONTH"
},
"subscriptionDescription": "Subscription description",
"subscriptionEndTime": "2026-11-21T09:48:17+08:00",
"subscriptionExpiryTime": "2026-03-12T09:48:17+08:00",
"subscriptionNotifyUrl": "https://your.example.com/subscriptionNotify",
"subscriptionStartTime": "2026-03-11T09:48:17+08:00",
"trials": [
{
"trialAmount": {
"$ref": "$.order.orderAmount"
},
"trialEndPeriod": 2,
"trialStartPeriod": 1
}
]
}
}The following code shows a sample of the response, which contains the following parameters:
- result.resultStatus: The result of the createPaymentSession (One-time Payments) API call.
- paymentSessionData: The payment session data to be returned to the client.
- paymentSessionExpiryTime: The expiration time of the payment session.
{
"paymentSessionData": "WNoudiUNUDjHjx0oXddzWn0QrRHv52lrHFNMKc8/5uKSqNDklmQ7Nh4JGBNITqi3jgIASZkbpq15gIEQleY13A==&&SG&&188&&eyJhY3Rpb24iOnsibmVlZFZlcmlmeUFuZFJlc3VtZSI6ZmFsc2UsInNpZ25CdXR0b25EaXNwbGF5IjpmYWxzZSwic2tpcFNka1F1ZXJ5IjpmYWxzZSwidXNlclNpZ25BZ3JlZW1lbnQiOmZhbHNlfSwiY2xpZW50SWQiOiJTQU5EQk9YXzVZRVYxRzJaVjQzSzA3MjE3IiwiY29ubmVjdEZhY3RvciI6eyJlbmFibGVDb25uZWN0IjpmYWxzZX0sImVsaWdpYmxlRWFzeVBheU1hcmtldGluZyI6ZmFsc2UsImV4dGVuZEluZm8iOiJ7XCJPUEVOX01VTFRJX1BBWU1FTlRfQUJJTElUWVwiOlwidHJ1ZVwiLFwiZXhwcmVzc0NoZWNrb3V0XCI6XCJmYWxzZVwiLFwidmVyc2lvbk1hcFwiOlwie1xcXCJ3ZWJcXFwiOntcXFwiMS4xLjBcXFwiOntcXFwidGFyZ2V0V2ViVmVyaXNvblxcXCI6XFxcIjEuMS4wXFxcIn0sXFxcIjEuMi4wXFxcIjp7XFxcInRhcmdldFdlYlZlcmlzb25cXFwiOlxcXCIxLjIuMFxcXCJ9fSxcXFwiaU9TXFxcIjp7XFxcIjEuMS4wXFxcIjp7XFxcInRhcmdldFdlYlZlcmlzb25cXFwiOlxcXCIxLjEuMFxcXCJ9LFxcXCIxLjIuMFxcXCI6e1xcXCJ0YXJnZXRXZWJWZXJpc29uXFxcIjpcXFwiMS4yLjBcXFwifX0sXFxcIkFuZHJvaWRcXFwiOntcXFwiMS4xLjBcXFwiOntcXFwidGFyZ2V0V2ViVmVyaXNvblxcXCI6XFxcIjEuMS4wXFxcIn0sXFxcIjEuMi4wXFxcIjp7XFxcInRhcmdldFdlYlZlcmlzb25cXFwiOlxcXCIxLjIuMFxcXCJ9fX1cIn0iLCJuZWVkQWNjb3VudENvbmZpcm1QYWdlIjpmYWxzZSwicGF5bWVudFNlc3Npb25Db25maWciOnsicGF5bWVudE1ldGhvZENhdGVnb3J5VHlwZSI6IkFMTCIsInByb2R1Y3RTY2VuZSI6IkVMRU1FTlRfUEFZTUVOVCIsInByb2R1Y3RTY2VuZVZlcnNpb24iOiIxLjAifSwic2tpcFJlbmRlclBheW1lbnRNZXRob2QiOmZhbHNlfQ==",
"paymentSessionExpiryTime": "2026-03-12T15:24:24+08:00",
"paymentSessionId": "WNoudiUNUDjHjx0oXddzWn0QrRHv52lrHFNMKc8/5uIsshVVNylGbBzLF2n6JmoT",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}The table below shows the possible values of result.resultStatus in the response. Please handle the result according to the guidance provided:
Note: If no response is received, it may indicate a network timeout. Please use a new paymentRequestId and call the API again. If the issue persists, contact Antom Technical Support.
Common questions
Q: Can I use Chinese characters in the value of the request parameters?
A: To avoid incompatibility of certain payment methods, do not use Chinese characters for fields in the request.
Q: How to set the address to receive payment notification?
A: Specify paymentNotifyUrl in the createPaymentSession (One-time Payments) 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: Does the returned paymentSessionData require processing before passing it to the client?
A: Do not process or modify paymentSessionData in any way, as this may cause the Payment Element invocation to fail.
Q: Is 3DS authentication mandatory for the first transaction?
A: The first transaction requires buyer participation and identity verification to ensure the security of subsequent recurring payments (where the buyer is not present). Specific requirements are as follows:
- Buyer uses card payment: Whether you or Antom collects card information, 3DS authentication must be completed. You can set is3DSAuthentication to truein the createPaymentSession (One-time Payments) request to enable Antom 3DS authentication.
- Buyer uses Google Pay and Antom decrypts the data: You need to set is3DSAuthentication to trueto initiate a 3DS transaction for identity verification. If the decrypted data is a DPAN (Device Primary Account Number), the system will automatically proceed with the authorization process without requiring additional buyer verification.
- Buyer uses Apple Pay and Antom decrypts the data: You can set is3DSAuthentication to falseor omit this parameter, as the buyer has already completed Apple's verification process.
Step 3: Invoke Payment Element Client-side
Use paymentSessionData to invoke Payment Element on your client. After the buyer clicks to submit payment, Payment Element will handle the entire flow based on the selected payment method, including displaying QR codes, redirecting to payment pages, performing 3DS authentication, and returning to the merchant’s result page.
- After obtaining paymentSessionData from the server, use the AMSPaymentElementclass to create SDK instance.
- Creating the AMSPaymentElementConfigurationobject includes the following parameters:
- Implement OnCreateComponentListenerto handle events in the process of invoking the payment component and launching the payment page. It includes the following methods:
- Implement OnSubmitPayListenerto handle events related to the payment initiation process. It includes the following methods:
The following shows a sample code for creating the SDK instance using
AMSPaymentElement
:AMSPaymentElementConfiguration configuration = new AMSPaymentElementConfiguration();
configuration.setLocale(new Locale("en", "US"));
configuration.setOption("showLoading", "true");
configuration.setOption("sandbox", "true");
configuration.setOption("notRedirectAfterComplete", "false");
String appearance = "{\"theme\":\"night\",\"layout\":{\"type\":\"accordion\"},\"variables\":{\"content-primary\":\"#ff5b4d\"}}";
configuration.setOption("appearance", appearance);
configuration.setOnCreateComponentListener(new OnCreateComponentListener() {
@Override
public void onCreateComponentCallback(AMSStatusResult statusResult) {
if (statusResult.getError() != null) {
switch (statusResult.getError().getCode()) {
case "UI_STATE_ERROR":
System.out.println("integration code error, please check the integration code");
break;
case "PARAM_INVALID":
System.out.println("session data invalid, please check the session data");
break;
case "INITIALIZE_WEB_TIMEOUT":
System.out.println("web app timeout, please invoke component again");
break;
default:
System.out.println("unknown error, please contact support");
break;
}
}
}
});
configuration.setOnSubmitPayListener(new OnSubmitPayListener() {
@Override
public void onSubmitPayCallback(AMSStatusResult statusResult) {
AMSStatus status = statusResult.getStatus();
AMSResultError error = statusResult.getError();
if (status == AMSStatus.PROCESSING) {
if (error != null && error.getCode() != null) {
if ("PAYMENT_IN_PROCESS".equals(error.getCode())) {
System.out.println("payment is in processing, please try polling the payment result from the server");
} else if ("USER_CANCELED".equals(error.getCode())){
System.out.println("user cancelled the payment process, please try invoke createComponent again");
} else if ("UNKNOWN_EXCEPTION".equals(error.getCode())) {
System.out.println("unknown exception, please contact support");
} else if ("PAYMENT_RESULT_TIMEOUT".equals(error.getCode())){
System.out.println("get payment result timeout, please try polling the payment result from the server");
}
}
} else if (status == AMSStatus.CANCELLED || status == AMSStatus.SUCCESS) {
System.out.println("payment cancelled or success, do nothing");
} else if (status == AMSStatus.FAIL) {
if (error != null && error.getCode() != null) {
if ("ORDER_IS_CANCELLED".equals(error.getCode())) {
System.out.println("the merchant has proactively canceled the order, please check on your own.");
} else if ("ORDER_IS_CLOSED".equals(error.getCode()) || "INQUIRY_PAYMENT_SESSION_FAILED".equals(error.getCode())){
System.out.println("the order has timed out and is closed, please re-initiate payment using a new paymentRequestId.");
} else {
System.out.println("unknown error, please contact support");
}
}
}
}
});
AMSPaymentElement amsPaymentElement = new AMSPaymentElement.Builder(this, (AMSPaymentElementConfiguration) configuration).build();
- Use the createComponentfunction from the instance object to invoke Payment Element:
// paymentSessionData obtained when creating a payment session
String paymentSessionData = "exxxxe";
amsPaymentElement.createComponent(this, paymentSessionData);Unmount Payment Element
Call the
onDestory
method to release SDK component resources in the following scenarios:- When the buyer navigates away from the checkout page, release the component resources created by the createPaymentSession (One-time Payments) API.
- When the buyer initiates multiple payments and the parameters in AMSPaymentElementConfigurationhad changed, release the component resources previously created by the createPaymentSession (One-time Payments) API.
// release SDK component resources
amsPaymentElement.onDestroy();You do not need to call
onDestroy
in the following scenarios, the SDK automatically releases resources (requires Android SDK version 1.33.0 or higher):- When the buyer initiates multiple payments and the parameters in AMSPaymentElementConfigurationremain unchanged, the SDK will automatically reclaim some resources after payment concludes to reset to the state beforecreateComponent.
Redirect to the merchant page
The following scenarios describe how redirecting to the merchant page and returning payment results are handled. Please follow the guidelines below:
Note:
- If the payment requires redirecting to an external page (the payment method does not support payment within the SDK), the payment result will not be returned via onSubmitPayCallback. After completing the payment on the external payment page, the payment method will determine whether to automatically redirect back to the paymentRedirectUrlyou provided.
- The payment results returned by the onSubmitPayCallbackmethod are only for client-side page navigation and status display. For the final order status, please obtain it through Step 4: Obtain the authorization or payment result.
Common questions
Q: What should be noted when passing the paymentRedirectUrl parameter?
A: paymentRedirectUrl must be set to an HTTPS address. Additionally, do not encode special characters in the URL, as this may cause abnormalities in the payment process.
Q: How should the payment result page be displayed?
A: Follow these recommendations for display:
- You need to pass an HTTPS address via the paymentRedirectUrl parameter in the payment request to display the payment result on the merchant side.
- If notRedirectAfterComplete is set to truewhen creating the Payment Element instance, and the payment method supports completion within the SDK, the payment result will be returned viasubmitPayment().then(). Handle the redirection logic based on the{code, status}in the response.
- Whether the subscription creation succeeds or fails, the buyer may return to the merchant page from the payment method side. Do not set paymentRedirectUrl to a fixed "subscription payment success page." Instead, you should the display result page based on the actual results returned by the server to avoid misleading the buyer.
Q: Does returning to the merchant result page indicate that the subscription payment was created successfully?
A: You cannot determine whether the subscription was created successfully solely based on the redirection to the merchant page. Key reasons include:
- After the buyer successfully creates a subscription payment, they may fail to return to the merchant page due to network abnormalities or other reasons.
- Even if the buyer does not complete the subscription payment, they may still return to the merchant page via the payment method side.
- Even if the buyer completes the subscription payment authentication, the subscription will not take effect if the initial deduction fails.
Step 4: Obtain the authorization or payment result Server-side
In the payment processing flow, Antom will send you corresponding result notifications based on the type of payment method used.
- For card payments, Google Pay, and Apple Pay, Antom sends authorization result notifications to inform you whether the authorization was successful. Only after a successful authorization will the fund capture be triggered. Please use the capture result as the basis for shipping goods.
- For APM payments, when the payment succeeds or fails, Antom will send you payment result notifications.
You can obtain payment or authorization results by receiving asynchronous notifications from Antom or by proactively querying.
Receive asynchronous notifications
Inquire about the result
1. Configure the webhook URL to receive asynchronous notifications
When a payment succeeds or fails, Antom will send an asynchronous notification to the webhook URL you set. You can choose one of the following two methods to configure the webhook URL for receiving notifications (if both are set, the URL specified in the request takes precedence):
- If each of your orders has a unique notification URL, it is recommended to set the webhook URL in each request. You can pass the asynchronous notification receiving URL for the specific order through paymentNotifyUrl in the createPaymentSession (One-time Payments) API.
- If all your orders share a unified notification URL, you can set the webhook URL on Antom Dashboard through Developer > Notification URL. For detailed steps, refer to Notification URL.
The following code shows a sample of the asynchronous notification request:
Card payments, Apple Pay, Google Pay
APM payments
{
"actualPaymentAmount": {
"currency": "SGD",
"value": "4200"
},
"cardInfo": {
"avsResultRaw": "A",
"cardBrand": "MASTERCARD",
"cardNo": "****************",
"cardToken":"exxxxe",
"cvvResultRaw": "Y",
"funding": "DEBIT",
"issuingCountry": "US",
"networkTransactionId": "XXXXX",
"paymentMethodRegion": "GLOBAL",
"threeDSResult": {
"cavv": "",
"eci": ""
}
},
"notifyType": "PAYMENT_RESULT",
"paymentAmount": {
"currency": "SGD",
"value": "4200"
},
"paymentMethodType": "CARD",
"paymentCreateTime": "2024-01-01T00:00:00+08:00",
"paymentId": "20240101123456789XXXX",
"paymentRequestId": "paymentRequestId01",
"paymentResultInfo": {
"avsResultRaw": "A",
"cardBrand": "MASTERCARD",
"cardNo": "****************",
"cardToken":"exxxxe", // store cardToken for future card payments
"cvvResultRaw": "Y",
"funding": "DEBIT",
"issuingCountry": "US",
"networkTransactionId": "XXXXX",
"paymentMethodRegion": "GLOBAL",
"threeDSResult": {
"cavv": "",
"eci": ""
}
},
"paymentTime": "2024-01-01T00:01:00+08:00",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}The following table shows the possible values of result.resultStatus in the notification request of payment result. Please handle the result according to the guidance provided:
{
"actualPaymentAmount": {
"currency": "HKD",
"value": "100"
},
"notifyType": "PAYMENT_RESULT",
"paymentAmount": {
"currency": "HKD",
"value": "100"
},
"paymentCreateTime": "2025-02-04T22:11:19-08:00",
"paymentId": "20240101123456789XXXX",
"paymentMethodType": "ALIPAY_HK",
"paymentRequestId": "paymentRequestId01",
"paymentResultInfo": {
},
"paymentTime": "2025-02-04T22:14:25-08:00",
"pspCustomerInfo": {
"pspCustomerId": "216022003753XXXX",
"pspName": "ALIPAY_HK"
},
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}The following table shows the possible values of result.resultStatus in the notification request of payment result. Please handle the result according to the guidance provided:
2. Verify the asynchronous notification
When you receive an asynchronous notification from Antom, you are required to return the response in the Sample code format, but you do not need to countersign the response.
You need to verify the signature of the payment notification sent by Antom:
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.alipay.global.api.model.Result;
import com.alipay.global.api.model.ResultStatusType;
import com.alipay.global.api.response.AlipayResponse;
import com.alipay.global.api.tools.WebhookTool;
@RestController
public class PaymentNotifyHandleBySDK {
/**
* alipay public key, used to verify signature
*/
private static final String SERVER_PUBLIC_KEY = "";
/**
* payment result notify processor
* using <a href="https://spring.io">Spring Framework</a>
*
* @param request HttpServletRequest
* @param notifyBody notify body
* @return
*/
@PostMapping("/payNotify")
public Object payNotifyHandler(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");
Result result;
AlipayResponse response = new AlipayResponse();
try {
// verify the signature of notification
boolean verifyResult = WebhookTool.checkSignature(requestUri, requestMethod, clientId, requestTime, signature, notifyBody, SERVER_PUBLIC_KEY);
if (!verifyResult) {
throw new RuntimeException("Invalid notify signature");
}
// deserialize the notification body
// update the order status with notify result
// respond the server that the notification is received
result = new Result("SUCCESS", "success", ResultStatusType.S);
} catch (Exception e) {
String errorMsg = e.getMessage();
// handle error condition
result = new Result("ERROR", errorMsg, ResultStatusType.F);
}
response.setResult(result);
return ResponseEntity.ok().body(response);
}
}Whether the payment is successful or not, 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"
}
}Common questions
Q: When will the notification be sent?
A: It depends on whether the payment is completed:
- If the payment is successfully completed, Antom will send you an asynchronous notification within 3 to 5 seconds. For some payment methods like OTC, the notification might take a bit longer.
- If the payment is not completed, Antom needs to close the order first before sending an asynchronous notification. The time it takes for different payment methods to close the order varies, usually defaulting to 14 minutes.
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 did not respond to the notification in the Sample code format.
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: When responding to an asynchronous notification, do I need to add a digital signature?
A: If you receive an asynchronous notification from Antom, you are required to return the response in the Sample code format, but you do not need to countersign the response.
Q: What key parameters do I need to use in the notification?
A: Please note the following key parameters:
A: Please note the following key parameters:
- result: For APM payments, it represents the final payment result. For Apple Pay, Google Pay, and card payments, it only represents the authorization result, and further capture is required.
- paymentRequestId: The payment request ID used for inquiries, cancellations, and reconciliation.
- paymentId: The payment order ID generated by Antom, used for refunds and reconciliation.
- paymentAmount: The payment amount.
You can also inquire about the payment or authorization result by calling the inquiryPayment API using paymentRequestId from the payment request, regardless of whether it is an APM payment, card payment, Apple Pay, or Google Pay.
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 sample code shows a request message:
{
"paymentRequestId": "paymentRequestId01"
}The following sample code shows a 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"
}
}Please handle the result based on the value of the paymentStatus parameter in the response. For specific return values, refer to the API documentation.
Common questions
Q: What key parameters should I pay attention to when using the inquiryPayment API to check the payment or authorization status?
A: Please note the following key parameters:
- result: Only indicates the result of the API call. For APM payments, the final payment result should be determined based on paymentStatus (SUCCESS/FAIL/PROCESSING). For card payments, Apple Pay, and Google Pay, paymentStatus only represents the authorization result, and the decision to ship goods should rely on the capture result.
- paymentAmount: Used to verify the payment amount.
- paymentId: The payment order ID generated by Antom, used for refunds and reconciliation.
Q: How often should I call the inquiryPayment API?
A: Call the inquiryPayment API constantly with an interval of 2 seconds until the final payment result is obtained or an asynchronous payment result notification is received.
(Optional) Step 5: Capture Server-side
Note: Card payments and certain APM payment methods (such as Google Pay, Apple Pay and Pay by Bank) must undergo a capture process, and capture will only be triggered after a successful authorization.
After successful authorization, Antom will automatically initiate capture by default, but also supports you to initiate manual capture. Antom will send the capture result notification to you via the notifyCapture (One-time Payments) API, while you can also query the capture result. You need to decide whether to ship goods based on the capture result. For specific operations, refer to Capture.
Step 6: Obtain subscription notifications Sever-side
After the subscription takes effect, Antom will send you the following notifications:
First-time subscription notification
Antom will send the following event notifications via HTTPS to the webhook configured in the API or Antom Dashboard:
Subscription status notification
Current deduction result notification
Follow the steps below to obtain subscription status notifications:
- Set the webhook URL for receiving notifications: Configure the subscriptionInfo.subscriptionNotifyUrl parameter in the createPaymentSession (One-time Payments) API. Below are examples of two types of subscription status notifications:
- When the value of subscriptionNotificationType is CREATE, determine the subscription status based on the value of subscriptionStatus :
- ACTIVE: Indicates the subscription is active.
- TERMINATED: Indicates the subscription is terminated.
{
"periodRule": {
"periodCount": 1,
"periodType": "MONTH"
},
"subscriptionEndTime": "2074-02-20T01:16:17-08:00",
"subscriptionId": "20240914190000000000000050000010226",
"subscriptionNotificationType": "CREATE",
"subscriptionRequestId": "SUBSCRIPTION_202444091410165oo009851_AUTO",
"subscriptionStartTime": "2024-09-13T19:30:17-07:00",
"subscriptionStatus": "ACTIVE"
}- When the value of subscriptionNotificationType is TERMINATE, the subscription is terminated.
{
"periodRule": {
"periodCount": 1,
"periodType": "WEEK"
},
"subscriptionId": "2025102619******00000160000671943",
"subscriptionLastUpdateTime": "2025-10-26T09:51:13-07:00",
"subscriptionNotificationType": "TERMINATE",
"subscriptionRequestId": "PR_en_****176",
"subscriptionStartTime": "2025-10-26T10:01:13-07:00",
"subscriptionStatus": "TERMINATED"
}- Verify the asynchronous notification
When you receive an asynchronous notification from Antom, you are required to return the response in the Sample code format, but you do not need to countersign the response.
You need to verify the signature of the payment notification sent by Antom:
/**
* Receive subscription notification
*
* @param request request
* @param notifyBody notify body
* @return Result
*/
@PostMapping("/receiveSubscriptionNotify")
@ResponseBody
public Result receiveSubscriptionNotify(HttpServletRequest request, @RequestBody String notifyBody) {
// Get required parameters from HTTP request
String requestUri = request.getRequestURI();
String requestMethod = request.getMethod();
// Get necessary parameters from request headers
String requestTime = request.getHeader("request-time");
String clientId = request.getHeader("client-id");
String signature = request.getHeader("signature");
try {
// Verify the validity of the notification signature
boolean verifyResult = WebhookTool.checkSignature(requestUri, requestMethod, clientId,
requestTime, signature, notifyBody, ANTOM_PUBLIC_KEY);
if (!verifyResult) {
throw new RuntimeException("Invalid notify signature");
}
// Deserialize the notification message body
AlipaySubscriptionNotify subscriptionNotify = JSON.parseObject(notifyBody, AlipaySubscriptionNotify.class);
if (subscriptionNotify != null && SubscriptionNotificationType.CREATE.equals(subscriptionNotify.getSubscriptionNotificationType())) {
// Process your business logic
// For example: Save user subscription information through the relationship between subscriptionRequestId and user ID
System.out.println("receive subscription notify: " + JSON.toJSONString(subscriptionNotify));
return Result.builder().resultCode("SUCCESS").resultMessage("success.").resultStatus(ResultStatusType.S).build();
}
} catch (Exception e) {
return Result.builder().resultCode("FAIL").resultMessage("fail.").resultStatus(ResultStatusType.F).build();
}
return Result.builder().resultCode("SYSTEM_ERROR").resultMessage("system error.").resultStatus(ResultStatusType.F).build();
}- Whether the payment is successful or not, 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 current deduction result notification by following the steps below:
- Set the webhook URL to receive notifications: Configure through the paymentNotifyUrl parameter in the createPaymentSession (One-time Payments) API or configure the webhook URL in Antom Dashboard.
The following is an example of a payment result notification:
{
"paymentAmount": {
"currency": "USD",
"value": "1"
},
"notifyType": "PAYMENT_RESULT",
"paymentCreateTime": "2025-10-08T19:10:51-07:00",
"paymentId": "202510091940108001001889B0255128143",
"paymentTime": "2025-10-08T19:11:40-07:00",
"periodEndTime": "2025-08-02T19:15:29-07:00",
"periodStartTime": "2025-07-26T19:15:29-07:00",
"phaseNo": "1",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success",
"resultStatus": "S"
},
"subscriptionId": "202510091900000000000000E0000032897",
"subscriptionRequestId": "PAYMENT_20251009101050687_AUTO"
}Description of key parameters:
- notifyType: Notification type; the value is PAYMENT_RESULT.
- phaseNo: The sequence number of the current subscription cycle.
- periodStartTime: The start time of the current subscription cycle.
- periodEndTime: The end time of the current subscription cycle.
- paymentAmount: The charged amount for each subscription cycle.
- Verify the asynchronous notification
When you receive an asynchronous notification from Antom, you are required to return the response in the Sample code format, but you do not need to countersign the response.
You need to verify the signature of the payment notification sent by Antom:
/**
* receive payment notify
*
* @param request request
* @param notifyBody notify body
* @return Result
*/
@PostMapping("/receivePaymentNotify")
@ResponseBody
public Result receivePaymentNotify(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("通知签名无效");
}
// deserialize the notification body
AlipaySubscriptionPayNotify paymentNotify = JSON.parseObject(notifyBody, AlipaySubscriptionPayNotify.class);
if (paymentNotify != null && "SUCCESS".equals(paymentNotify.getResult().getResultCode())) {
// handle your own business logic.
// e.g. The payment information of the user is saved through the relationship between the subscriptionRequestId and the user ID.
System.out.println("接收到支付通知: " + JSON.toJSONString(paymentNotify));
return Result.builder().resultCode("SUCCESS").resultMessage("success.").resultStatus(ResultStatusType.S).build();
}
} catch (Exception e) {
return Result.builder().resultCode("FAIL").resultMessage("fail.").resultStatus(ResultStatusType.F).build();
}
return Result.builder().resultCode("SYSTEM_ERROR").resultMessage("system error.").resultStatus(ResultStatusType.F).build();
}- Whether the payment is successful or not, 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"
}
}Common questions
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 did not respond to the notification in the Sample code format.
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: Do I need to verify the signature after receiving the payment result notification?
A: Yes. To ensure that the callback request is indeed sent by Antom, verification is required during signature verification. When assembling messages to be verified, you are required to process in the following standard order:
<http-method> <http-uri> <client-id>.<request-time>.<request-body>
. Note that <request-body>
should be assembled directly from the original value, rather than parsed into JSON and then assembled.
Q: If the first payment fails, will the subscription take effect?
A: When the first deduction during subscription activation fails, the subscription will not take effect. Antom will push a webhook notification with subscriptionStatus=
TERMINATED
to you, indicating that the subscription activation has failed.Q: What is the subscription timeout period?
For APM payment types, the default timeout period is 30 minutes. For card payment types, the default timeout period is 7 days.
Subscription renewal notification
After the subscription is successfully created and has taken effect, the Antom system will automatically initiate renewal deductions based on the subscription rules you have configured, and send the corresponding payment result notifications through webhook to achieve periodic deductions. The timing and rules for triggering renewal deductions are as follows:
- Trigger timing: The renewal deduction will be automatically triggered 24 hours before the start date of the next subscription cycle. You can determine the initiation time of the next cycle’s payment by subtracting 24 hours from the periodEndTime parameter in the previous cycle’s payment result notification.
- Cycle rule: The renewal period and deduction frequency will follow the periodRule defined during subscription creation, for example, daily, monthly, quarterly, or yearly billing. The explanation is as follows:
Card payments, Apple Pay, Google Pay
APM payments
For card payments, Google Pay, and Apple Pay payment scenarios, asynchronous notifications are typically divided into the following scenarios:
The following are sample codes for asynchronous notifications in each scenario:
Authorized payment result notification
Capture notification
Subscription status notification
Current deduction result notification
The following code shows a sample of the authorized payment result notification:
{
"actualPaymentAmount": {
"currency": "USD",
"value": "1"
},
"cardInfo": {
"avsResultRaw": "U",
"cardBrand": "VISA",
"cardCategory": "CONSUMER",
"cardNo": "************0550",
"credentialTypeUsed": "PAN",
"cvvResultRaw": "M",
"funding": "PREPAID",
"issuingCountry": "MY",
"networkTransactionId": "202510090310009b937936376",
"paymentMethodRegion": "GLOBAL",
"threeDSResult": {
"cavv": "mockCavv",
"challengeCancel": "",
"challenged": true,
"dsTransactionId": "cce18b6e-b55e-40ff-814c-619b45987636",
"eci": "02",
"threeDSOffered": true,
"threeDSVersion": "2.1.0",
"threeDStransactionStatusReason": ""
}
},
"notifyType": "PAYMENT_RESULT",
"paymentAmount": {
"currency": "USD",
"value": "1"
},
"paymentCreateTime": "2025-10-08T19:11:20-07:00",
"paymentId": "202510091940108001001889B0255128143",
"paymentMethodType": "GOOGLEPAY",
"paymentRequestId": "PAYMENT_20251009101050687_AUTO",
"paymentResultInfo": {
"avsResultRaw": "U",
"cardBrand": "VISA",
"cardCategory": "CONSUMER",
"cardNo": "************0550",
"credentialTypeUsed": "PAN",
"cvvResultRaw": "M",
"funding": "PREPAID",
"issuingCountry": "MY",
"networkTransactionId": "202510090310009b937936376",
"paymentMethodRegion": "GLOBAL",
"threeDSResult": {
"cavv": "mockCavv",
"challengeCancel": "",
"challenged": true,
"dsTransactionId": "cce18b6e-b55e-40ff-814c-619b45987636",
"eci": "02",
"threeDSOffered": true,
"threeDSVersion": "2.1.0",
"threeDStransactionStatusReason": ""
}
},
"paymentTime": "2025-10-08T19:11:38-07:00",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}The following code shows a sample of the capture notification:
{
"captureAmount": {
"currency": "USD",
"value": "1"
},
"captureId": "202510091940108070001889B0280060023",
"captureRequestId": "PAYMENT_20251009101050687_AUTO",
"captureTime": "2025-10-08T19:11:40-07:00",
"notifyType": "CAPTURE_RESULT",
"paymentId": "202510091940108001001889B0255128143",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success.",
"resultStatus": "S"
}
}No notification.
The following code shows a sample of the current deduction result notification:
{
"paymentAmount": {
"currency": "USD",
"value": "1"
},
"notifyType": "PAYMENT_RESULT",
"paymentCreateTime": "2025-10-08T19:10:51-07:00",
"paymentId": "202510091940108001001889B0255128143",
"paymentTime": "2025-10-08T19:11:40-07:00",
"periodEndTime": "2025-08-02T19:15:29-07:00",
"periodStartTime": "2025-07-26T19:15:29-07:00",
"phaseNo": "1",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success",
"resultStatus": "S"
},
"subscriptionId": "202510091900000000000000E0000032897",
"subscriptionRequestId": "PAYMENT_20251009101050687_AUTO"
}Description of key parameters:
- notifyType: Notification type; the value is PAYMENT_RESULT.
- phaseNo: The sequence number of the current subscription cycle.
- periodStartTime: The start time of the current subscription cycle.
- periodEndTime: The end time of the current subscription cycle.
- paymentAmount: The charged amount for each subscription cycle.
In APM payment scenarios, asynchronous notifications are typically categorized into the following cases:
The following are sample codes for asynchronous notifications in each scenario:
Payment result notification
Subscription status notification
Current deduction result notification
No notification.
No notification.
The following code shows a sample of the current deduction result notification:
{
"paymentAmount": {
"currency": "USD",
"value": "1"
},
"notifyType": "PAYMENT_RESULT",
"paymentCreateTime": "2025-10-08T19:10:51-07:00",
"paymentId": "202510091940108001001889B0255128143",
"paymentTime": "2025-10-08T19:11:40-07:00",
"periodEndTime": "2025-08-02T19:15:29-07:00",
"periodStartTime": "2025-07-26T19:15:29-07:00",
"phaseNo": "1",
"result": {
"resultCode": "SUCCESS",
"resultMessage": "success",
"resultStatus": "S"
},
"subscriptionId": "202510091900000000000000E0000032897",
"subscriptionRequestId": "PAYMENT_20251009101050687_AUTO"
}Description of key parameters:
- notifyType: Notification type; the value is PAYMENT_RESULT.
- phaseNo: The sequence number of the current subscription cycle.
- periodStartTime: The start time of the current subscription cycle.
- periodEndTime: The end time of the current subscription cycle.
- paymentAmount: The charged amount for each subscription cycle.
Common questions
Q: If a payment deduction fails, will it cause the subscription to become invalid?
A: If the first deduction when creating a subscription fails, the subscription will not take effect. However, if the subscription has already taken effect and subsequent cycle deductions fail (for example, due to insufficient balance), the subscription will remain valid. If the subscription is not actively canceled, Antom will retry the deduction in the next billing cycle.
Q: Will a payment failure trigger a deduction notification, and will it be retried?
A: A deduction failure notification will be sent when the deduction fails. In card subscription payment scenarios, Antom will not initiate a retry. If you need to initiate a retry, please contact Antom technical support to confirm the solution.
Q: If the first deduction occurs on dates such as February 28, March 31, or April 30 (the end of the month), how is the next deduction date determined?
A: The subscription cycle logic is based on the selected date. If the next cycle does not have that same date, the deduction will occur one day earlier. For example:
- First cycle: 1.28, Second cycle: 2.28, Third cycle: 3.28, Fourth cycle: 4.28.
- First cycle: 1.31, Second cycle: 2.28, Third cycle: 3.31, Fourth cycle: 4.30.
- First cycle: 1.30, Second cycle: 2.28, Third cycle: 3.30, Fourth cycle: 4.30.
Q: How are subsequent recurring deductions associated with the initial subscription contract?
A: For recurring deduction notifications, the association can be made using the subscriptionRequestId or subscriptionId included in the notification request to link back to the initial contract. For recurring deductions in card payment scenarios, Antom will additionally send authorization result notifications and capture result notifications. These two notifications can be linked to the recurring deduction notification through paymentId, and ultimately associated with the initial contract’s subscriptionId.
After subscription
After completing the subscription, you can perform the following actions:
Inquire subscription information Server-side
After your subscription is confirmed, you can query the following subscription information:
- Query subscription list: You can query a list of subscriptions that match specific filter conditions through the inquireSubscriptionList API.
- Query subscription details: You can call the inquireSubscription API with subscriptionId to get the details information of each subscription.
- Query subscription transactions: You can call the inquireSubscriptionPayment API with subscriptionId to retrieve a list of payments for a subscription.
Subscription trial Server-side
Antom provides a subscription trial feature that allows buyers to experience a product or service for a limited time at no cost or at a discounted rate before officially purchasing a subscription plan. For more details, refer to Subscription trial.
Subscription cancellation Server-side
The subscription cancellation feature allows buyers to cancel their current subscription at any time when they no longer need to use the associated service. For more details, refer to Subscription cancellation.
Cancellation Server-side
For successful payments, if the buyer requests cancellation or a refund on the same day, you can use Antom’s cancellation capability to cancel the order or release funds. Orders not yet completed can also be cancelled directly. For details, refer to Cancel.
Refund Server-side
For successfully paid orders, if you need to issue a refund to the buyer, Antom provides two methods:
- Your operations staff can manually process refunds directly through Antom Dashboard.
- Call the refund API to initiate a refund.
Antom’s refund capabilities are as follows:
- Supports full refunds.
- Supports multiple partial refunds, with the total refunded amount not exceeding the captured amount.
Dispute Server-side
Antom provides dispute resolution services for contested transactions. For more information, refer to Dispute Guidance.
Reconciliation Server-side
After the transaction is completed, use the financial reports provided by Antom for reconciliation. For more information on how to reconcile and the settlement rules of Antom, please refer to Reconciliation.
Payment method features
This section explains differences in supported features across payment methods.
Default timeout
The default order closing time varies for different payment methods. For specific information, refer to Payment method default timeout.
Note: Since Payment Element orders have a default validity period of 1 hour, the actual timeout period is extended by 1 hour beyond the payment method’s default timeout. For example, if a payment method’s default timeout is 14 minutes, the actual timeout period for a Payment Element order will be 1 hour and 14 minutes.
Integration key points
Refer to Integration key considerations to learn about the integration key points and recommended solutions for different payment methods.
Card payment features
Payment Element supports the following card payment features. Click to get detailed information and usage instructions:
Additional content
Antom also offers the following customization options:
- Appearance customization: Antom provides extensive styling options, including theme, layout, and CSS customization.
- Google Pay: Buyers can pay using credit or debit cards stored in their Google account. With Payment Element, no additional Google Pay SDK integration is needed—it loads Google Pay automatically.
- Apple Pay: Buyers can pay using credit or debit cards stored in their Apple account. With Payment Element, no additional Apple Pay SDK integration is needed—it loads Apple Pay automatically.
Specify a payment method
You can pass the parameters in the createPaymentSession (One-time Payments) API to specify the display of payment methods on Payment Element, the order of the payment method list, and the display of quick payments. This feature offers you the following benefits:
- Filter local payment methods based on your business region.
- Sort your preferred payment methods.
- Display the mainstream quick payments, such as Alipay, Apple Pay, and Google Pay.
Payment methods requiring embedding
The following payment methods require you to embed the payment details collection component: