Hosted 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.

This topic describes how to integrate card payment methods through the hosted mode. By adopting this mode, you delegate the payment information collection process to Antom. Since sensitive cardholder data does not pass through your servers, this approach helps you eliminate the compliance burden of PCI-DSS. You are not required to build a PCI-DSS compliant payment environment nor obtain PCI compliance certification.

User experience

The following figures illustrates the user experience of the first-time subscription and subsequent deductions:

Note: When subscribing to payment services that require card binding, the first transaction requires the buyer completing the 3DS authentication process.

PC:

首次支付用户体验图.png

Mobile:

首次支付用户体验-mobile.png

Order lifecycle

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

The following diagram illustrates the entire subscription cycle, including subscription creation, payment method binding, completion of the first payment, and refund processing when necessary. The process ensures the valid activation of subscriptions and the security and transparency of all payment transactions.

1.png 2.png

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 recurring payment request
  3. Redirect to Antom card information collection page (normalUrl)
  4. Obtain the authorization result
  5. Capture and obtain the capture result
  6. Obtain the subscription notifications

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

When the buyer enters the payment method selection page, the card brand identifiers and names to be integrated for this transaction should be displayed, allowing the buyer to choose according to their needs and preferences.

Note: The payment method list page needs to be implemented by you.

Step 2: Create an authorized recurring payment Server-side

You can redirect to Antom card information collection page to collect the buyer‘s payment information (for example, card number and exporation date), subscription information (for example, the deduction amount and cycle), order information, device information, and payment amount. Call the pay (One-time Payments) API, and submit an authorization subscription request for payment.

The subscription creation process includes the following key parameters:

Type

Parameter

Required

Description

Basic parameters

paymentRequestId

Yes

The request ID of the authorized payment, which must be unique each time.

paymentAmount.currency

Yes

The currency of the payment amount.

paymentAmount.value

Yes

The payment amount. 

settlementStrategy.settlementCurrency

Yes

The currency of the settlement strategy for the payment request.

paymentMethod.paymentMethodType

Yes

Enumeration values for payment methods. In card payment scenario, the value is fixed as CARD.

paymentFactor.isAuthorization

Yes

Payment mode. For card payment scenarios, the value is fixed as true, indicating the authorization-capture mode.

paymentFactor.captureMode

No

The capture mode. By default, Antom completes the capture for the merchant. If the initial subscription creation payment needs to be captured manually, you can set this field to MANUAL, and after authorization is successful, call the capture (One-time Payments) API.

productCode

Yes

Product code. In this scenario, the value is fixed as CASHIER_PAYMENT.

paymentRedirectUrl

Yes

The merchant page URL that the buyer is redirected to after the payment is completed. This URL must be an HTTPS address and should render content corresponding to the payment result.

paymentNotifyUrl

No

The URL that is used to receive the authorized payment result notification. This URL must be an HTTPS address and if the address is configured on Antom Dashboard, this parameter can be omitted.

Device parameters

env.terminalType

Yes

Terminal type of which the merchant service applies to. Valid values are:

  • WEB: The client-side terminal type is a website, which is opened via a PC browser.
  • WAP: The client-side terminal type is an H5 page, which is opened via a mobile browser.
  • APP: The client-side terminal type is a mobile application.

env.clientIp

Yes

The IP address of the client device.

Order parameters

order.orderAmount

Yes

The order amount of the merchant side.

order.referenceOrderId

Yes

The unique ID to identify the order on the merchant side.

order.orderDescription

Yes

The summary description of the order on the merchant side.

order.buyer

Yes

Buyer information. At least one of the following must be provided:

  • order.buyer.referenceBuyerId
  • order.buyer.buyerPhoneNo
  • order.buyer.buyerEmail

Subscription parameters

subscriptionInfo.subscriptionDescription

Yes

The description of the subscription.

subscriptionInfo.subscriptionStartTime

Yes

The date and time when the subscription becomes active.

subscriptionInfo.subscriptionNotifyUrl

Yes

The URL that is used to receive the subscription result notification. HTTPS address must be provided.

subscriptionInfo.trials

No

The list of trial information for the subscription. If your subscription service includes a trial or discount offer, you can specify this parameter.

subscriptionInfo.periodRule

Yes

The subscription period type, supporting four types of cycles: YEARMONTHWEEK and DAY.

Card payment parameters

paymentMethod.paymentMethodMetaData.

is3DSAuthentication

Yes

Determine whether to set the transaction authentication type to 3DS based on risk and dispute history. Valid values are:

  • true: indicates that the transaction authentication type is3DS authentication.
  • falseindicates that the transaction authentication type is Non-3DS authentication. Default if empty or not provided.

Note: In card payment scenarios, this parameter must be set as true to perform a 3D authentication, ensuring that the buyer’s identity is verified during the first card payment.

The above parameters are the basic parameters for creating a subscription payment session, for full parameters and additional requirements for certain payment methods refer to pay (One-time Payments).

The following sample code shows how to call the pay (One-time Payments) API:

copy
public static void pay() {
    AlipayPayRequest alipayPayRequest = new AlipayPayRequest();

    // Set subscription information
    SubscriptionInfo subscriptionInfo = new SubscriptionInfo();
    subscriptionInfo.setSubscriptionDescription("TEST_SUBSCRIPTION");
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
    subscriptionInfo.setSubscriptionStartTime(ZonedDateTime.now().format(formatter));
    subscriptionInfo.setSubscriptionEndTime(ZonedDateTime.now().plusYears(1).format(formatter));
    subscriptionInfo.setSubscriptionNotifyUrl("https://your.example.com/subscriptionNotify");

    // Set subscription period rule
    PeriodRule periodRule = new PeriodRule();
    periodRule.setPeriodType("YEAR");
    periodRule.setPeriodCount(1);
    subscriptionInfo.setPeriodRule(periodRule);
    alipayPayRequest.setSubscriptionInfo(subscriptionInfo);

    // Set order information
    String rng = UUID.randomUUID().toString();
    Amount amount = Amount.builder().currency("SGD").value("5200").build();

    Order order = new Order();
    order.setOrderAmount(amount);
    order.setOrderDescription("TEST_ORDER_" + rng);
    order.setReferenceOrderId("ORDER_" + rng);
    Buyer buyer = new Buyer();

    // Set order description
    order.setOrderDescription("Sample subscription order");

    // Replace with your orderId
    order.setReferenceOrderId("ORDER_" + rng);

    // Set buyer information
    buyer.setBuyerEmail("buyer@example.com");
    buyer.setBuyerPhoneNo("123456789");
    buyer.setReferenceBuyerId("BUYER_" + rng);
    order.setBuyer(buyer);

    alipayPayRequest.setOrder(order);

    // Set environment information
    Env env = new Env();
    env.setTerminalType(TerminalType.WEB);
    env.setClientIp("112.80.248.78");
    alipayPayRequest.setEnv(env);

    alipayPayRequest.setPaymentAmount(amount);

    // Set payment method
    PaymentMethod paymentMethod = new PaymentMethod();
    paymentMethod.setPaymentMethodType("CARD");

    // Set payment method metadata
    Map<String, Object> metaData = new HashMap<>();
    metaData.put("is3DSAuthentication", "true");
    paymentMethod.setPaymentMethodMetaData(metaData);
    alipayPayRequest.setPaymentMethod(paymentMethod);

    // Set settlement currency
    SettlementStrategy settlementStrategy = new SettlementStrategy();
    settlementStrategy.setSettlementCurrency("SGD");
    alipayPayRequest.setSettlementStrategy(settlementStrategy);

    // Set authorization capture mode
    PaymentFactor paymentFactor = new PaymentFactor();
    paymentFactor.setIsAuthorization(true);
    alipayPayRequest.setPaymentFactor(paymentFactor);

    // Replace with your notification URL
    alipayPayRequest.setPaymentNotifyUrl("https://www.your-notify.example.com/payments/notify");

    // Replace with your redirect URL
    alipayPayRequest.setPaymentRedirectUrl("https://www.your-merchant.example.com/redirect");

    // Replace with your paymentRequestId
    alipayPayRequest.setPaymentRequestId("PAY_XXXXXX" + rng);

    // Set product code
    alipayPayRequest.setProductCode(ProductCodeType.CASHIER_PAYMENT);

    // Set request path
    alipayPayRequest.setPath(PAY_PATH);

    // Do payment
    AlipayPayResponse alipayPayResponse = null;
    try {
        alipayPayResponse = CLIENT.execute(alipayPayRequest);
    } catch (AlipayApiException e) {
        String error = e.getMessage();
        // Handle error message
    }
}

The following code shows a sample of the request message:

copy
{
    "env": {
        "clientIp": "112.*.*.*",
        "terminalType": "WEB"
    },
    "order": {
        "buyer": {
            "buyerEmail": "buy***@example.com",
            "buyerPhoneNo": "123456789",
            "referenceBuyerId": "BUYER_eeae1497-8f54-4359-977e-3b5e858335af"
        },
        "orderAmount": {
            "currency": "SGD",
            "value": "5200"
        },
        "orderDescription": "Sample subscription order",
        "referenceOrderId": "ORDER_eeae1497-8f54-4359-977e-3b5e858335af"
    },
    "paymentAmount": {
        "currency": "SGD",
        "value": "5200"
    },
    "paymentFactor": {
        "isAuthorization": true
    },
    "paymentMethod": {
        "paymentMethodMetaData": {
            "is3DSAuthentication": "true"
        },
        "paymentMethodType": "CARD"
    },
    "paymentNotifyUrl": "https://www.your-notify.example.com/payments/notify",
    "paymentRedirectUrl": "https://www.your-merchant.example.com/redirect",
    "paymentRequestId": "PAY_XXXXXXeeae1497-8f54-4359-977e-3b5e858335af",
    "productCode": "CASHIER_PAYMENT",
    "settlementStrategy": {
        "settlementCurrency": "SGD"
    },
    "subscriptionInfo": {
        "periodRule": {
            "periodCount": 1,
            "periodType": "YEAR"
        },
        "subscriptionDescription": "TEST_SUBSCRIPTION",
        "subscriptionEndTime": "2027-03-12T09:59:38+08:00",
        "subscriptionNotifyUrl": "http://localhost:8443/payment/receiveSubscriptionNotify",
        "subscriptionStartTime": "2026-03-12T09:59:38+08:00"
    }
}

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

  • result.resultStatus: The status of the authorized payment.
  • normalUrl: The URL used to redirect to Antom card information collection page.
copy
{
  "normalUrl": "https://sandbox.example.com/checkout/page?sessionData=SESSION_SAMPLE_ABC123",
  "paymentActionForm": "{\"method\":\"GET\",\"paymentActionFormType\":\"RedirectActionForm\",\"redirectUrl\":\"https://sandbox.example.com/checkout/page?sessionData=SESSION_SAMPLE_ABC123\"}",
    "paymentAmount": {
        "currency": "SGD",
        "value": "5200"
    },
    "paymentCreateTime": "2026-03-11T18:59:40-07:00",
    "paymentId": "202603121940109000001888F0284122695",
    "paymentRequestId": "PAY_XXXXXXeeae1497-8f54-4359-977e-3b5e858335af",
    "paymentResultInfo": {},
    "redirectActionForm": {
        "method": "GET",
        "redirectUrl": "https://sandbox.example.com/checkout/page?sessionData=SESSION_SAMPLE_ABC123"
    },
    "result": {
        "resultCode": "PAYMENT_IN_PROCESS",
        "resultMessage": "payment in process",
        "resultStatus": "U"
    }
}

The table below shows the possible values of result.resultStatus in the response. Please handle the result according to the guidance provided:

result.resultStatus

Message

Further action

F

The authorization failed. Please close the current transaction or retry with a new paymentRequestId.

U

The authorization is being processed.
  • If normalUrl is returned, redirect from your merchant server to this Antom intermediate page to collect the buyer’s card information. And you need to store the paymentId for subsequent capture or refund operations.
  • If normalUrl is not returned, it indicates that the transaction is abnormal. You may close the current transaction or retry with a different paymentRequestId.

Note: If no response is received, it may indicate a network timeout. You may close the current transaction or retry with a different paymentRequestId.

Common questions

Q: Is 3D authentication mandatory for the first transaction?

A: The first transaction is a buyer-initiated transaction that requires identity verification to ensure the security of subsequent periodic deductions when the buyer is not present. Therefore, the following requirements apply to identity verification for the first transaction:

  • Complete 3D authentication through Antom: When the buyer selects card payment and paymentMethodType is set to CARD, the 3DS authentication must be completed to verify the buyer’s identity. You can set the is3DSAuthentication parameter to true in the pay (One-time Payments) API request to complete the authentication through Antom 3DS.

Step 3: Redirect to Antom card information collection page (normalUrl) Client-side

After the merchant server obtains normalUrl from Antom and passes it to the frontend, it will redirect from the merchant frontend to the Antom card information collection page. 

The following is sample codes for the merchant front end to load normalUrl.

copy
if (serverResponse.normalUrl != null) {
    window.open(serverResponse.normalUrl, '_blank');
}

The following images demonstrate the user experience of redirecting to the card information collection page on Web or App platforms.

1.png

Common questions

Q: How to handle different payment experiences?

A: The normalUrl  returned from card payments integrated via API is an H5 link. For WEB and WAP scenarios, you can directly redirect to this URL. For APP scenarios, it is recommended to load the normalUrl through a WebView to enhance the user experience.

Q: What should be noted when passing the paymentRedirectUrl parameter?

A: paymentRedirectUrl is set to an HTTPS address by default. 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: You need to pass an HTTPS address via the paymentRedirectUrl parameter in the pay (One-time Payments) API request to display the payment result on the merchant side.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 result Server-side

Whether the authorization succeeds or fails, Antom will send the authorized payment result to you through the notifyPayment (Subscription) API. Please follow the steps below to obtain the authorized payment result notification.

  1. Configure the webhook URL to receive asynchronous notifications: Set the paymentNotifyUrl parameter in the pay (One-time Payments) API request or configure the webhook URL in the Antom Dashboard.

The following code shows a sample of the asynchronous notification request:

copy
{
  "notifyType": "PAYMENT_RESULT",
  "result": {
    "resultCode": "SUCCESS",
    "resultStatus": "S",
    "resultMessage": "success"
  },
  "paymentRequestId": "2020010123456789XXXX",
  "paymentId": "2020010123456789XXXX",
  "paymentAmount": {
    "value": "8000",
    "currency": "EUR"
  },
  "paymentCreateTime": "2020-01-01T12:01:00+08:30",
  "paymentTime": "2020-01-01T12:01:01+08:30"
}
  1. Verify the asynchronous notification

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.

You need to verify the signature of the payment notification sent by Antom.

copy
 /**
     * 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("Invalid notify signature");
            }

            // 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("receive payment notify: " + 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();
    }
  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.
copy
{
    "result": {
        "resultCode": "SUCCESS",
        "resultStatus": "S",
        "resultMessage": "success"
    }
}

Step 5: Capture and obtain the capture result Server-side

Note: Capture will be triggered only when the authorized payment is successful.

If payment is successful, Antom will automatically initiate capture for you, while you can also initiate capture manually. Antom will send the capture result notification to you through the notifyCapture (One-time Payments) API, while you can also query the capture result. Shipping of goods should be based on the capture result. For specific steps, refer to Capture.

Step 6: Obtain subscription notifications Server-side

After the subscription takes effect, Antom will send you the following subscription notifications:

First-time subscription notification

Antom will send the following event notifications via HTTPS to the webhook you configured in the API or in the Antom Dashboard.

Notification type

API

Request message

Subscription status notification

After the subscription takes effect, Antom will send the subscription result notification to you through the notifySubscription API.

  • When the value of subscriptionNotificationType in the request message is CREATE, subscriptionStatus indicates whether the subscription is active (ACTIVE) or terminated (TERMINATED).
  • When the value of subscriptionNotificationType is TERMINATE, the subscription is terminated.

Current deduction result notification

After a subscription payment is successfully activated or renewed, Antom will send the current subscription deduction result to you through the notifyPayment (Subscription) API.

When the value of notifyType in the request message is PAYMENT_RESULT, the result.resultStatus parameter indicates whether the current deduction is successful (S) or failed (F).

Obtain the subcription status notification by following the steps below:

  1. Set the webhook URL to receive notifications: Configure through the subscriptionInfo.subscriptionNotifyUrl  parameter in the pay (One-time Payments) API. The following are examples of notifications for the two subscription statuses:
  • When the value of subscriptionNotificationType in the request message is CREATE, subscriptionStatus indicates the status of the subscription:
  • ACTIVE: indicates that the subscription is active.
  • TERMINATEDindicates that the subscription is terminated.
copy
{
  "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.
copy
{
  "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"
}
  1. Verify the asynchronous notification

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.

You need to verify the signature of the payment notification sent by Antom.

copy
/**
     * receive subscription notify
     *
     * @param request    request
     * @param notifyBody notify body
     * @return Result
     */
    @PostMapping("/receiveSubscriptionNotify")
    @ResponseBody
    public Result receiveSubscriptionNotify(HttpServletRequest request, @RequestBody String notifyBody) {
        // retrieve the required parameters from http request
        String requestUri = request.getRequestURI();
        String requestMethod = request.getMethod();

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

        try {
            // verify the signature of notification
            boolean verifyResult = WebhookTool.checkSignature(requestUri, requestMethod, clientId,
                    requestTime, signature, notifyBody, ANTOM_PUBLIC_KEY);
            if (!verifyResult) {
                throw new RuntimeException("Invalid notify signature");
            }

            // deserialize the notification body
            AlipaySubscriptionNotify subscriptionNotify = JSON.parseObject(notifyBody, AlipaySubscriptionNotify.class);

            if (subscriptionNotify != null && SubscriptionNotificationType.CREATE.equals(subscriptionNotify.getSubscriptionNotificationType())) {
                // handle your own business logic.
                // e.g. The subscription information of the user is saved through the relationship between the subscriptionRequestId and the 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();
    }
  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.
copy
{
    "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: 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?

A: For card payments, the default timeout period is 7 days. You can also specify a timeout period through the subscriptionExpiryTime field.

Q: What are the differences between the current deduction result notification, the authorization notification, and the capture notification?

A: The authorized payment notification includes information related to 3DS authentication and other authorization details. The capture notification reflects the final payment result and is recommended as the basis for shipment. The current deduction result notification contains subscription cycle information, including the start time, end time, and period number of the current cycle.

Q: Can I initiate manual capture for the first payment of the subscription?

A: Yes. You need to set the value of the paymentFactor.captureMode parameter to MANUAL in the pay (One-time Payments) API, and call the capture (One-time Payments) API manually after receiving the asynchronous notification of successful authorized payment. In this scenario, the first payment is only considered successful when the capture is successful, and only then will Antom generate the subsequent periodic deduction plan.

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 and deduction frequency will follow the periodRule defined during subscription creation, for example, daily, monthly, quarterly, or yearly billing. The explanation is as follows:

First payment deduction time

(paymentTime = periodStartTime)

Subscription cycle

Next payment deduction time (paymentTime)

Next cycle effective time (periodStartTime)

2024-09-25T20:10:17+08:00

To set the subscription cycle to 3 days, you need to pass in the following parameters:

  • periodRule.periodCount = 3
  • periodRule.periodType = DAY

2024-09-27T20:20:04+08:00

2024-09-28T20:10:17+08:00

2024-09-25T20:10:17+08:00

To set the subscription cycle to one week, you need to pass in the following parameters:

  • periodRule.periodCount = 1
  • periodRule.periodTypeWEEK

2024-10-01T20:10:17+08:00

2024-10-02T20:10:17+08:00

2024-09-25T20:10:17+08:00

To set the subscription cycle to one month, you need to pass in the following parameters:

  • periodRule.periodCount = 1
  • periodRule.periodTypeMONTH

2024-10-24T20:10:17+08:00

2024-10-25T20:10:17+08:00

2024-09-25T20:10:17+08:00

To set the subscription cycle to one year, you need to pass in the following parameters:

  • periodRule.periodCount = 1
  • periodRule.periodTypeYEAR

2025-09-24T20:10:17+08:00

2025-09-25T20:10:17+08:00

Asynchronous notifications are generally divided into the following scenarios:

Common scenarios

First-time subscription payment

Subsequent periodic deductions

Authorized payment result notification

A notification is sent to inform you of the authorization result and the 3DS authentication result.

A notification is sent to inform you of the authorization result and the 3DS authentication result.

Capture result notification

Authorization success will trigger a notification, and the capture result serves as the basis for shipping.Authorization success will trigger a notification, and the capture result serves as the basis for shipping.

Subscription status notification

A notification is sent to inform you of the subscription creation result.

No notification is sent.

Current deduction result notification

A notification is sent to inform you of the current deduction result, amount, and validity period.

A notification is sent to inform you of the current deduction result, amount, and validity period.

The following are sample codes for asynchronous notifications in each scenario:

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

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: Yes. A deduction failure notification will be sent when the deduction fails. In card recurring payment scenarios, Antom will not initiate a retry. If you need to initiate a retry, please contact Antom technical support for a customized solution.

Q: If the first deduction occurs on dates such as February 28, March 31, or April 30 (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?

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 subscription. 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 subscription's subscriptionId.

Q: For card payments, if I initiate the capture manually when the subscription is first created (by setting paymentFactor.captureMode  to MANUAL), how will subsequent automatic deduction be handled?

A: All subsequent automatic renewals are initiated by Antom without merchant involvement in the capture process, which means the value of the paymentFactor.captureMode parameter defaults to AUTOMATIC.

After subscription

After completing the subscription, you can perform the following actions:

Subscription trial

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

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.

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 the 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.

Refer to Refund to learn about Antom refund rules and operation process.

Best practices

Antom provides you with the following best practice solutions: