APM recurring payments

Subscription payment is an automatic recurring payment solution that helps you collect payments on a periodic basis. With a single authorization, the buyer can link their payment accounts to enjoy ongoing subscription services. It also supports dynamic adjustments to subscription settings such as modifying the billing cycle or amount, canceling renewals, or terminating services. The entire process is both convenient and secure.
This document focuses on API-based integration for APM. Different payment methods require different integration strategies, each with its own advantages and disadvantages that affect development costs and user experience. To make the best technical decision for your business, please refer to Choose your integration path for a detailed comparison of integration options and their applicable use cases.

User experience

First-time binding
Subsequent payments

Workflow

The following diagram illustrates the process of subscription cycle, creating subscription, and receiving payment notifications.
Subscription cycle
Create subscription
Receive payment notification

Integration preparations

Before you start integrating, read the Integration Guide and API Overview documents to understand the integration steps of the server-side API and the precautions for calling the API. Furthermore, ensure that the following prerequisites are met:
  • Obtain a client ID
  • Complete the key configuration
  • Complete the configuration of paymentNotifyUrl to receive the asynchronous notification
  • Integrate the server-side SDK package, install the server-side library, and initialize a request instance. For more details, refer to Server-side SDKs.

Integration steps

Start your integration by taking the following steps:
  1. Add a list of payment methods
  2. Create a subscription
  3. Redirect authorization binding link
  4. Receive asynchronous notification of subscription result
  5. Receive asynchronous notification of subscription renewal

Step 1: Add a list of payment methods
Client-side

In a subscription scenario, when the buyer enters the payment method selection page, the payment method identifiers and names to be integrated for this transaction should be displayed, allowing the buyer to choose according to their needs and preferences. Please contact Antom technical support to obtain the identifiers and names of each payment method.
Note: The payment method list page needs to be implemented by you.

Step 2: Create a subscription
Server-side

Call the create API, you need to collect the user’s payment method, subscription cycle, periodic amount, order information, and other details to submit the subscription creation request.
The subscription creation process includes the following key parameters:
The following code is an example of initiating a request by calling the create API:
public static void createSubscription() {
  AlipaySubscriptionCreateRequest alipaySubscriptionCreateRequest = new AlipaySubscriptionCreateRequest();

  // replace with your subscriptionRequestId.
  // You can save the relationship between the subscriptionRequestId and the user ID for later information retrieval.
  String subscriptionRequestId = UUID.randomUUID().toString();
  alipaySubscriptionCreateRequest.setSubscriptionRequestId(subscriptionRequestId);
  alipaySubscriptionCreateRequest.setSubscriptionDescription("Subscription Description");

  // set subscription start time and end time. you might want to consider time zones
  // If the start time is earlier than the authorization time, the subscription is successful.
  // If the start time is later than the authorization time, the payment is made after the successful authorization, which is the pre-sale.
  // For details, please refer to::<a href="https://docs.antom.com/ac/subscriptionpay/activation#uiqBb">Samples</a>
  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
  alipaySubscriptionCreateRequest.setSubscriptionStartTime(ZonedDateTime.now().format(formatter));
  alipaySubscriptionCreateRequest.setSubscriptionEndTime(ZonedDateTime.now().plusYears(3).format(formatter));

  // set periodRule
  PeriodRule periodRule = PeriodRule.builder().periodCount(1).periodType("MONTH").build();
  alipaySubscriptionCreateRequest.setPeriodRule(periodRule);

  // set paymentMethod
  PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType("ALIPAY_HK").build();
  alipaySubscriptionCreateRequest.setPaymentMethod(paymentMethod);

  // onvert 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>
  Amount amount = Amount.builder().currency("HKD").value("1688").build();

  // set payment amount
  alipaySubscriptionCreateRequest.setPaymentAmount(amount);

  // set order info
  OrderInfo orderInfo = OrderInfo.builder().orderAmount(amount).build();
  alipaySubscriptionCreateRequest.setOrderInfo(orderInfo);

  // set settlement strategy
  // replace with your existing settlement currency
  SettlementStrategy settlementStrategy = SettlementStrategy.builder().settlementCurrency("USD").build();
  alipaySubscriptionCreateRequest.setSettlementStrategy(settlementStrategy);

  // set env info
  Env env = Env.builder().terminalType(TerminalType.APP).build();
  env.setOsType(OsType.ANDROID);

  alipaySubscriptionCreateRequest.setEnv(env);

  // replace with your notify url
  // or configure your notify url here: <a href="https://dashboard.antom.com/global-payments/developers/iNotify">Notification URL</a>
  alipaySubscriptionCreateRequest.setPaymentNotificationUrl("http://www.yourNotifyUrl.com/subscriptions/receivePaymentNotify");
  alipaySubscriptionCreateRequest.setSubscriptionNotificationUrl("http://www.yourNotifyUrl.com/subscriptions/receiveSubscriptionNotify");

  // replace with your subscription redirect url
  alipaySubscriptionCreateRequest.setSubscriptionRedirectUrl("http://www.yourRedirectUrl.com?subscriptionRequestId=" + subscriptionRequestId);

  AlipaySubscriptionCreateResponse alipaySubscriptionCreateResponse;
      try {
          alipaySubscriptionCreateResponse = CLIENT.execute(alipaySubscriptionCreateRequest);
      } catch (AlipayApiException e) {
          String errorMsg = e.getMessage();
          // handle error condition
      }
  }
The following code shows a sample of the request message:
{
"env": {
  "osType": "ANDROID",
  "terminalType": "APP"
},
"orderInfo": {
  "orderAmount": {
    "currency": "HKD",
    "value": "1688"
  }
},
"paymentAmount": {
  "currency": "HKD",
  "value": "1688"
},
"paymentMethod": {
  "paymentMethodType": "ALIPAY_HK"
},
"paymentNotificationUrl": "http://www.yourNotifyUrl.com/subscriptions/receivePaymentNotify",
"periodRule": {
  "periodCount": 1,
  "periodType": "MONTH"
},
"settlementStrategy": {
  "settlementCurrency": "USD"
},
"subscriptionDescription": "Subscription Description",
"subscriptionEndTime": "2029-03-11T17:48:07+08:00",
"subscriptionNotificationUrl": "http://www.yourNotifyUrl.com/subscriptions/receiveSubscriptionNotify",
"subscriptionRedirectUrl": "http://www.yourRedirectUrl.com?subscriptionRequestId=5e5932ac-ed92-461a-9e3f-e1b4ac08fb0e",
"subscriptionRequestId": "5e5932ac-ed92-461a-9e3f-e1b4ac08fb0e",
"subscriptionStartTime": "2026-03-11T17:48:07+08:00"
}
The response code involves the following key parameters:
The following code shows a sample of the response message:
{
  "appIdentifier": "com.iap.linker_portal",
  "applinkUrl": "https://psp.ac.alipay.com/page/simulation-wallet/acwallet/signContract.html?scopes=AGREEMENT_PAY%2CUSER_LOGIN_ID&bizContent=%7B%22acquirerId%22%3A%22102218800000000000A%22%2C%22authClientDisplayName%22%3A%222188120314639523%40alitest.com%22%2C%22authClientId%22%3A%2221881200300645I9%22%2C%22authClientName%22%3A%222188120314639523%40alitest.com%22%2C%22authRedirectUrl%22%3A%22https%3A%2F%2Fg.alipayplus.com%2Fpage%2Fac-auth-payment%2Fresult%2Fmobile%2Findex.html%3FloadMode%3D2%26callbackType%3DCommon%26terminalType%3DAPP%26referenceAgreementId%3D2026031119214000100500031242021%26authRequestId%3D2026031119091305000370002050791%26pspId%3D102216000000000000A%26clientId%3DT_4GGO000000000001%22%2C%22authState%22%3A%22188bmljL2ZDWEZ4MnowK3dYVVdQVElPS0lpSFQ0b21xRkdSVWxkTStlaXAzOEh1VEVpaFRJS3M3Y290T0Zma0h6Ng%22%2C%22customerBelongsTo%22%3A%22ALIPAY_HK%22%2C%22osType%22%3A%22ANDROID%22%2C%22passThroughInfo%22%3A%22%7B%5C%22referenceMerchantId%5C%22%3A%5C%2221881200300645I9%5C%22%7D%22%2C%22pspId%22%3A%22102216000000000000A%22%2C%22referenceAgreementId%22%3A%222026031119214000100500031242021%22%2C%22referenceMerchantId%22%3A%2221881200300645I9%22%2C%22scopes%22%3A%5B%22AGREEMENT_PAY%22%2C%22USER_LOGIN_ID%22%5D%2C%22terminalType%22%3A%22APP%22%7D&source=AlipayConnect&needCallback=false",
  "normalUrl": "https://g.alipayplus.com/page/aplus-linker/acwallet/authorization.html?url=alipayconnect%3A%2F%2Fplatformapi%2Facwallet%2FsignContract&scopes=AGREEMENT_PAY%2CUSER_LOGIN_ID&bizContent=%7B%22acquirerId%22%3A%22102218800000000000A%22%2C%22authClientDisplayName%22%3A%222188120314639523%40alitest.com%22%2C%22authClientId%22%3A%2221881200300645I9%22%2C%22authClientName%22%3A%222188120314639523%40alitest.com%22%2C%22authRedirectUrl%22%3A%22https%3A%2F%2Fg.alipayplus.com%2Fpage%2Fac-auth-payment%2Fresult%2Fmobile%2Findex.html%3FloadMode%3D2%26callbackType%3DCommon%26terminalType%3DAPP%26referenceAgreementId%3D2026031119214000100500031242021%26authRequestId%3D2026031119091305000370002050791%26pspId%3D102216000000000000A%26clientId%3DT_4GGO000000000001%22%2C%22authState%22%3A%22188bmljL2ZDWEZ4MnowK3dYVVdQVElPS0lpSFQ0b21xRkdSVWxkTStlaXAzOEh1VEVpaFRJS3M3Y290T0Zma0h6Ng%22%2C%22customerBelongsTo%22%3A%22ALIPAY_HK%22%2C%22osType%22%3A%22ANDROID%22%2C%22passThroughInfo%22%3A%22%7B%5C%22referenceMerchantId%5C%22%3A%5C%2221881200300645I9%5C%22%7D%22%2C%22pspId%22%3A%22102216000000000000A%22%2C%22referenceAgreementId%22%3A%222026031119214000100500031242021%22%2C%22referenceMerchantId%22%3A%2221881200300645I9%22%2C%22scopes%22%3A%5B%22AGREEMENT_PAY%22%2C%22USER_LOGIN_ID%22%5D%2C%22terminalType%22%3A%22APP%22%7D&source=AlipayConnect&needCallback=false",
  "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. You can close the subscription or initiate a retry of the original order.

Common questions
Q: How can I determine which type of URL needs to be consumed in the response?
A: Depending on the payment method and terminal type, Antom may return one or more of the following URLs:
normalUrl, applinkUrl, and schemeUrl. The merchant server should pass these URLs to the merchant frontend, and any one of them can be selected for redirection.

Q: How do I set the terminalType?
A: Valid values for terminalType are as follows:
  • If the buyer initiates the transaction on a PC, set terminalType to
    WEB
    .
  • If the buyer initiates the transaction on a mobile browser, set terminalType to
    WAP
    . Specify the osType parameter and set the corresponding system based on the buyer's phone:
    ANDROID
    or
    IOS
    .
  • If the buyer initiates the transaction within an application, set terminalType to
    APP
    .

Step 3: Redirect to the authorization binding link
Client-side

After obtaining the authorization binding link returned by Antom, the merchant server passes the address to the frontend, which then redirects the buyer to the payment method page. The different types of payment progress links are shown in the table below:
The following is the sample codes for loading payment continuation URL on the merchant front end:
Web
WAP
iOS
Android
The following figure shows the effect of the payment method checkout page:
Screenshot of APM payment method checkout page shows the payment method interface for completing the binding
Different payment methods return different payment continuation URLs at different terminals. Antom returns different payment continuation URLs based on the paymentMethod and terminalType values you specified. The following table lists the types of returned payment continuation URLs and user experience on different terminals. Refer to URLs returned for payment methods for more details.
Common questions
Q: What should I pay attention to when passing the parameter paymentRedirectUrl?
A: It should be set to an HTTPS address by default, and special characters in the URL must not be encoded; otherwise, it may cause payment exceptions.

Q: How should the payment result page be displayed?
A: You need to specify the subscriptionRedirectUrl parameter in the create API to provide an HTTPS address. This address is used to display the payment result on the merchant side.
  • Both successful and failed authorizations may have an entry for returning from the payment method page to the merchant page. Therefore, do not hardcode subscriptionRedirectUrl as a success page; instead, display content based on the server-side result to avoid user misunderstanding.
  • If the transaction is initiated from a merchant application, subscriptionRedirectUrl must be set to the scheme address of the merchant app.

Q: Does returning to the merchant result page mean the subscription relationship has taken effect?
A: No, the redirect to the merchant page alone does not indicate successful authorization. There are three possible situations:
  • The buyer may have successfully authorized but failed to return to the merchant page due to network issues.
  • The buyer may return to the merchant page through a payment method entry even without completing authorization.
  • The buyer may complete authorization, but the subscription relationship might still fail to take effect if the initial payment is unsuccessful.

Step 4: Receive asynchronous notification of subscription result
Server-side

Antom will push asynchronous notifications based on the authorization result and payment result status of the APM transaction:
Subscription status notification
Current period payment result notification
  1. Respond to the notification result. When responding to the notification, you must follow the fixed format below regardless of whether the payment transaction succeeds or fails, and no signature processing is required.
{
"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 didn't make a response to the notification in the sample code format of Process the notification.
The notification can be resent up to 8 times or until a correct response is received to terminate delivery. The sending intervals are as follows: 0 minutes, 2 minutes, 10 minutes, 10 minutes, 1 hour, 2 hours, 6 hours, and 15 hours.

Q: When responding to an asynchronous notification, do I need to add a digital signature?
A: No. If you receive an asynchronous notification from Antom, you are required to return the response in the sample code format of Process the notification, but you do not need to countersign the response.

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 the merchant, indicating that the subscription activation has failed.

Q: What is the subscription timeout period?
A: For APM, the default timeout period is 80 minutes. You can also specify a custom timeout period using the
subscriptionExpiryTime parameter.

Q: If the subscription creation fails, will there be a first payment result notification?
There are two possible situations:
  • If the buyer authorization is successful but the first payment fails, both a subscription creation failure notification and a first payment failure notification will be sent.
  • If the buyer authorization fails, only a subscription creation failure notification will be sent.

Step 5: Receive asynchronous notification of subscription renewal
Server-side

After the subscription is successfully created and a valid relationship is established, the Antom system will automatically initiate renewal payments according to your configured subscription rules and send the corresponding payment result notification through the notifyPayment API, enabling periodic billing.
  • 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:
Asynchronous notifications are generally divided into the following scenarios:
Example of current period payment result notification:
{
"paymentAmount": {
	"currency": "PHP",
	"value": "100"
},
"notifyType": "PAYMENT_RESULT",
"paymentCreateTime": "2024-09-17T23:10:48-07:00",
"paymentId": "20240918194010****00188060246428030",
"paymentTime": "2024-09-17T23:10:50-07:00",
"periodEndTime": "2024-10-19T22:15:17-07:00",
"periodStartTime": "2024-09-19T22:15:17-07:00",
"phaseNo": "2",
"result": {
	"resultCode": "SUCCESS",
	"resultMessage": "success",
	"resultStatus": "S"
},
"subscriptionId": "2024091819000000****000050000010807",
"subscriptionRequestId": "SUBSCRIPTION_20244****yyy5oo0hhh1_AUTO"
}
Description of key parameters:
  • notifyType: Notification type; the value is
    PAYMENT_RESULT
    .
  • phaseNo: The sequence number of the current subscription period.
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 relationship 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: Yes, a failed deduction will trigger a payment failure notification. In the APM subscription payment scenario, Antom will perform multiple retry attempts.

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 period: 1.28, Second period: 2.28, Third period: 3.28, Fourth period: 4.28.
  • First period: 1.31, Second period: 2.28, Third period: 3.31, Fourth period: 4.30.
  • First period: 1.30, Second period: 2.28, Third period: 3.30, Fourth period: 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.

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:

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, please refer to the 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, please refer to the Subscription cancellation.

Cancel
Server-side

For orders with successful payments, if a buyer requests to cancel or refund on the same day, you can use Antom’s order cancellation capability to cancel or unfreeze the order status.
In addition, for orders that have not yet been paid, you can also cancel them directly. For detailed integration instructions, please 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 the Antom Dashboard.
  • Call refund API to initiate a refund. Refer to Refund to learn about Antom refund rules and operation process.

Best practices

Antom provides you with the following best practice solutions: