# Accept payments with EasySafePay (SDK)

> EasySafePay enables merchants to create a fast, secure, and seamless payment experience entirely within their website or app, offering one-click password‑free payments, strong security controls, and lightweight integration with comprehensive client SDKs and server APIs.

 Antom EasySafePay is a minimalist payment solution focused on small-amount, high-frequency payment scenarios. With its innovative "bind payment method upon first payment" design and one-click payment feature, it significantly simplifies the payment process. Buyers can choose to pay directly or perform payment method binding during the first transaction, and subsequent payments can be processed instantly without repeated verification.

 This solution leverages industry-leading intelligent risk control systems, dynamic polling technology, and payment failure recovery strategies to ensure transaction security while achieving top-tier payment success rates in the industry. It creates a win-win-win scenario for buyer payment experience, merchant conversion rates, and platform ecosystem value.

  

<!-- ToggleTab query="platform" -->

**Tab: Web/WAP**

## User experience {#jvgmU1}

 Through simple browser integration, you can quickly enable digital wallet and online banking payment functionalities. Different payment methods vary in their browser-side user experience. For specific interaction differences, refer to the table below:

 | **​**     **Payment method category** | **​**     **Payment method** | **Terminal type** | **First-time payment** | **Subsequent payments** |
| --- | --- | --- | --- | --- |
| Digital wallet | - [Alipay](https://docs.antom.com/ac/antomop/alipay_cn.md?platform=auto_debit) - [AlipayHK](https://docs.antom.com/ac/antomop/aplusalipayhk.md?platform=auto_debit) - [DANA](https://docs.antom.com/ac/antomop/DANA.md?platform=auto_debit) - [GCash](https://docs.antom.com/ac/antomop/gcash.md?platform=auto_debit) - [PayPay (SmartPayment)](https://docs.antom.com/ac/antomop/paypay_mdx.md?platform=auto_debit) - [Touch'n Go eWallet](https://docs.antom.com/ac/antomop/touchngo.md?platform=auto_debit) - TrueMoney | Web | Complete the payment within the payment method app. | Complete the payment on the merchant page. |
| Online banking | - [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md) | Web | Complete the payment on the payment method page. | Complete the payment on the payment method page. |
| Digital wallet | - [AlipayHK](https://docs.antom.com/ac/antomop/aplusalipayhk.md?platform=auto_debit) - [DANA](https://docs.antom.com/ac/antomop/DANA.md?platform=auto_debit) | WAP | Complete the payment on the merchant page. | Complete the payment on the merchant page. |
| - [Alipay](https://docs.antom.com/ac/antomop/alipay_cn.md?platform=auto_debit) - [GCash](https://docs.antom.com/ac/antomop/gcash.md?platform=auto_debit) - [PayPay (SmartPayment)](https://docs.antom.com/ac/antomop/paypay_mdx.md?platform=auto_debit) - TrueMoney - [Touch'n Go eWallet](https://docs.antom.com/ac/antomop/touchngo.md?platform=auto_debit) | WAP | Redirect to the payment method app to complete payment. | Complete the payment on the merchant page. |  |
| Online banking | - [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md) | WAP | Complete the payment on the merchant page. | Complete the payment on the merchant page. |

<!-- TabGroup -->

**Tab: Digital wallet**

In the digital wallet payment scenario, the system will guide the buyer to complete the transaction on the merchant's page or within the payment method app after the buyer confirms the payment. The first payment verification and subsequent simplified payment process are illustrated as follows:

<!-- TabGroup -->

**Tab: First payment**

The first payment requires security authentication. Once authorized, the buyer will be enabled for password-free payments on subsequent transactions.

 ![Web user experience showing the digital wallet first payment flow where buyers complete security authentication to enable password-free payments for subsequent transactions](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/7088aa21-f14a-4d8a-9af1-c838ebd71bc0.png)

**Tab: Subsequent payments**

Subsequent payments will be processed automatically upon order submission, without requiring password entry.

 ![Web user experience showing the digital wallet subsequent payment flow where payments are processed automatically without requiring password entry](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/aa2e0346-2a2c-44ac-b04e-7974da476441.png)

<!-- /TabGroup -->
 ---

**Tab: Online banking**

The online banking process is illustrated as follows, including first payment authentication and subsequent simplified payment flows.

<!-- TabGroup -->

**Tab: First payment**

The first payment requires security authentication. Once authorized, the buyer will be enabled for password-free payments on subsequent transactions.

 ![Web user experience showing the online banking first payment flow where buyers complete security authentication to enable password-free payments](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/fcc53ba9-5af0-4fc8-ab81-192eb2922791.png)

**Tab: Subsequent payments**

Subsequent payments will be processed automatically upon order submission, without requiring password entry.

 ![Web user experience showing the online banking subsequent payment flow where payments are processed automatically without password entry](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/611de0c3-fe11-4512-898a-2cac4b7b1449.png)

<!-- /TabGroup -->
 ---

<!-- /TabGroup -->

## Payment flow {#4Fltgr}

<!-- TabGroup -->

**Tab: First payment**

The first payment flow chart:

 ![Sequence diagram illustrating the EasySafePay first payment flow among Buyer, Merchant Client, Merchant Server, and Antom: the buyer enters the checkout page, the merchant creates a payment session via the createPaymentSession API, the client SDK renders the payment interface and manages redirections, the buyer completes authorization, and the merchant receives asynchronous notifyAuthorization and notifyPayment notifications or queries payment status through the inquiryPayment API](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/31e77630-b716-48f5-8fce-64a8c937a31e.png)

 1. **The buyer enters the checkout page.**
2. **Create a payment session request.**  
   After the buyer selects a payment method and submits the order, you can obtain the payment session by calling the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API.
3. **Invoke the client SDK.**  
   Invoke the SDK using a payment session and the SDK will automatically collect payment elements, render the payment interface, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics. For detailed interaction differences across payment methods, refer to the   [User experience](#jvgmU1)   table  .
4. **Obtain the authorization result.**  
 When the authorization is successful, Antom sends you the asynchronous notification through the    [**notifyAuthorization**](https://docs.antom.com/ac/ams/notifyauth.md)        API.
5. **Obtain the payment result.**  
   Obtain the payment result using one of the following methods:

   - Asynchronous notification: Specify     *paymentNotifyUrl*     in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)        to send asynchronous notifications to you.
  - Synchronous inquiry: Call the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)        API to check the real-time payment status.

**Tab: Subsequent payments**

The subsequent payment flow chart:

 ![Sequence diagram illustrating the EasySafePay subsequent payment flow among Buyer, Merchant Client, Merchant Server, and Antom: the buyer enters the checkout page, the merchant creates a payment session using the previously authorized paymentMethodId via the createPaymentSession API, the client SDK renders the payment interface, the buyer submits the order, and the merchant receives an asynchronous notifyPayment notification or uses the inquiryPayment API to check payment status](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/458d34c9-5e85-4c13-99ca-9aa43b6f1adf.png)

 1. **The buyer enters the checkout page.**
2. **Create a payment session request.**  
   After the buyer selects a payment method and submits the order, you can obtain the payment session by calling the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API.
3. **Invoke the client SDK.**  
 Invoke the SDK using a payment session and the SDK will automatically collect payment elements, render the payment interface, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics. For detailed interaction differences across payment methods, refer to the   [User experience](#jvgmU1)    table.
4. **Obtain the payment result.**  
   Obtain the payment result using one of the following methods:

   - Asynchronous notification: Specify     *paymentNotifyUrl*     in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)        to send asynchronous notifications to you.
  - Synchronous inquiry: Call the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)        API to check the real-time payment status.

<!-- /TabGroup -->
 ---

## Integration preparations {#zmnOh}

 Before you start integrating, read the   [Integration Guide](https://docs.antom.com/integration_guide_en.md)   and   [API Overview](https://docs.antom.com/ac/ams/api_fund.md)   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](https://docs.antom.com/ac/sdks/server_sdks.md)  .
- If you need to conduct joint debugging by connecting the sandbox with the production environment, please contact Antom technical support at least two business days in advance to request configuration. The sandbox environment and production environment require separate configuration.

 Refer to  [Integrate the SDK package for Web/WAP](https://docs.antom.com/ac/sdks/web.md)   to complete integration preparations.

## Integration steps {#CnuPc}

 Start your integration by taking the following steps:

 1. (Optional) Preload the SDK
2. Create a payment session
3. Invoke the SDK
4. Obtain the authorization and payment result

### (Optional) Step 1: Preload the SDK **[Client-side]** {#O3V7T}

 Preloading the SDK during the checkout page initialization significantly improves the rendering performance with no negative impact. It is recommended to trigger preloading of the SDK when the buyer selects a payment method.

 Follow the code example below to perform the preloading:   ```javascript
AMSEasyPay.preload();

```

### Step 2: Create a payment session **[Server-side]** {#VWjfJ}

 When a buyer selects a payment method provided by Antom, you need to collect essential information including the payment request ID, order amount, payment method, order description, payment redirect page URL, and payment result notification URL.

 Call the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API to create a payment session and initialize the Antom SDK using the     *paymentSessionData*     value returned in the response.

 The table below lists the parameter specifications for calling the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API during the first and subsequent payments:

 > **[INFO]** **Note**    : For subsequent payments with   [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md)  , simply keep the parameters consistent with the first payment. The buyer can open the   [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md)   webpage and enter the phone number to proceed directly with the payment.

 | **Parameter type** | **Parameter name** | **Required** **(First-time payment)** | **Required** **(Subsequent payments)** | **Description** |
| --- | --- | --- | --- | --- |
| Base parameter | *productCode* | Yes | Yes | The value is fixed as   `AGREEMENT_PAYMENT`   in the EasySafePay scenario. |
| *productScene* | Yes | Yes | The value is fixed as   `EASY_PAY`   in the EasySafePay scenario. |  |
| *paymentRequestId* | Yes | Yes | The unique ID assigned by a merchant to identify a payment request. |  |
| *paymentMethod.paymentMethodType* | Yes | Yes | The payment method type that is included in   [payment method](https://docs.antom.com/ac/pm/enumeration_values.md)   options. |  |
| *paymentMethod.paymentMethodId* | No | Yes | The unique ID that is used to identify a payment method. T   he value of this parameter is that of     *accessToken*     from the   [**notifyAuthorization**](https://docs.antom.com/ac/ams/notifyauth.md)   API. |  |
| *settlementStrategy* | No | No | The settlement strategy for the payment request.    If the merchant agreement supports multiple settlement currencies, they must be specified in the API request. |  |
| *paymentAmount.value* | Yes | Yes | The value of the amount as a positive integer in the smallest currency unit. For details about the smallest currency unit, see   [Smallest unit of the currency](https://docs.antom.com/ac/ref/cc.md#ONkIe)   . |  |
| *paymentAmount.currency* | Yes | Yes | The transaction currency, which is a 3-letter currency code that follows the   [ISO 4217](https://www.iso.org/iso-4217-currency-codes.html)   standard. |  |
| *paymentSessionExpiryTime* | No | No | The specific date and time after which the payment session will expire. The default expiration time is 1 hour after the session creation. For example, if the session is created at 2023-7-27T12:00:01+08:30, the session expiration time is 2023-7-27T13:00:01+08:30. |  |
| *paymentRedirectUrl* | Yes | Yes | The merchant page URL that the user is redirected to after the payment is completed. The page display according to the server-side result and should not default to a fixed payment success page. - If the payment is initiated from a Web or WAP platform, pass the WAP URL. - If the payment is initiated from an App, pass the scheme URL. |  |
| *paymentNotifyUrl* | No | No | The URL that is used to receive the payment result notification.    it must be an HTTPS URL. This field can be omitted if already configured via Antom Dashboard. |  |
| Authorization parameter | *agreementInfo.authState* | Yes | No | The unique ID generated by the merchant to initiate an Easy   Safe   Pay authorization. |
| Order    parameter | *order.ord*     *erAmount* | Yes | Yes | The order amount of the merchant that directly provides services or goods to the customer |
| *order.referenceOrderId* | Yes | Yes | The unique ID to identify the order on the merchant side. |  |
| *order.orderDescription* | Yes | Yes | Summary description of the order. |  |
| *order.buyer.referenceBuyerId* | No | No | Submit buyer information for risk assessment. Provide at least one of these fields:     *referenceBuyerId*    ,     *buyerPhoneNo*    , or     *buyerEmail*    . |  |
|  | *order.buyer.*   - *buyerPhoneNo*   - *buyerEmail* | No | No | Buyer's account. Providing relevant payment account information can effectively improve the payment success rate and reduce the risk of buyer attrition. Please refer to the table below for specific format requirements. |

 The parameter format for the buyer's payment account for each payment method is as follows:

 | **Payment method** | **Parameter format** |
| --- | --- |
| [AlipayHK](https://docs.antom.com/ac/antomop/aplusalipayhk.md?platform=auto_debit) | It is recommended to prioritize using a mobile phone number: - Mobile number:     - Hong Kong, China: 852-12****78. The phone number must be 8 digits long, excluding the prefix.   - China: 86-137****5678. The phone number must be 11 digits long, excluding the prefix.   - Email: xxx@xxx.com |
| [DANA](https://docs.antom.com/ac/antomop/DANA.md?platform=auto_debit) | 62-8569****7288. The phone number starts with 8 and is no more than 12 digits long, excluding the prefix. |
| [Alipay](https://docs.antom.com/ac/antomop/alipay_cn.md?platform=auto_debit) [GCash](https://docs.antom.com/ac/antomop/gcash.md?platform=auto_debit) [Touch'n Go eWallet](https://docs.antom.com/ac/antomop/touchngo.md?platform=auto_debit) TrueMoney [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md) | The buyer is authenticated on the payment method side, and no parameters need to be passed in.    *userloginId.* |

 During the first-time payment, passing the buyer's payment account will auto-fill the buyer's account on the payment page, eliminating manual input. Below is a comparison of the user experience with and without these fields:

<!-- TabGroup -->

**Tab: With account parameter passed**

Login account input is not required.

 ![User experience showing the merchant checkout page when the buyer's payment account parameter is passed, where the login account input field is pre-filled and manual input is not required](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/4ec4f8db-a7bc-477d-8dcb-e48523e758f5.png)

**Tab: Without account parameter passed**

Manual input of login account is required.

 ![User experience showing the merchant checkout page when the buyer's payment account parameter is not passed, requiring manual input of the login account](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/25f256b6-e891-4e4a-95ec-862043a4d19a.png)

<!-- /TabGroup -->
 Below are code examples for first and subsequent payments.

<!-- TabGroup -->

**Tab: First payment**

The following sample code shows how to call the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API:

   ```java
@@PostMapping("/payment/createSession")
public ResponseEntity<ApiResponse> createPaymentSession(@RequestBody PaymentVO payment) {
    AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
    alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
    alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);

    // replace with paymentRequestId
    String paymentRequestId = UUID.randomUUID().toString();
    alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);

    // convert amount unit(in practice, amount should be calculated on your serverside)
    // For details, please refer to: <a href="https://docs.antom.com/ac/ref/cc">Usage rules of the Amount object</a>
    long amountMinorLong = Money.of(CurrencyUnit.of(payment.currency), new BigDecimal(payment.amountValue)).getAmountMinorLong();

    // set amount
    Amount amount = Amount.builder().currency(payment.currency).value(String.valueOf(amountMinorLong)).build();
    alipayPaymentSessionRequest.setPaymentAmount(amount);

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

    User loginUser = users.get(payment.getUserId());

    // set buyer info
    Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();

    // set paymentMethod
    PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType(payment.paymentMethodType).build();
    if (loginUser.getPaymentMethodTypeAccessToken().containsKey(payment.getPaymentMethodType())) {
        // buyer has authorized
        String accessToken = loginUser.getPaymentMethodTypeAccessToken().get(payment.getPaymentMethodType());
        paymentMethod.setPaymentMethodId(accessToken);
    } else {
        // set agreementInfo
        // replace with your authState
        String authState = UUID.randomUUID().toString();
        AgreementInfo agreementInfo = AgreementInfo.builder().authState(authState).build();
        alipayPaymentSessionRequest.setAgreementInfo(agreementInfo);

        // save the paymentMethodType corresponding to the authState
        authStatePayment.put(authState, payment);

        // The login ID that the user used to register in the payment method client. The login ID can be the user's email address or phone number.
        // Specify this parameter to free users from manually entering their login IDs.
        if(StringUtil.isNotBlank(loginUser.getPhoneNumber()){
            buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
        }
        if(StringUtil.isNotBlank(loginUser.getEmail() && "ALIPAY_HK".equals(payment.getPaymentMethodType())){
            buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
        }
    }
    alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);

    // replace with your orderId
    String orderId = UUID.randomUUID().toString();
    // set order info
    Order order = Order.builder().referenceOrderId(orderId)
    .orderDescription("antom sdk testing order").orderAmount(amount).buyer(buyer).build();
    alipayPaymentSessionRequest.setOrder(order);

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

    // replace with your redirect URL
    alipayPaymentSessionRequest.setPaymentRedirectUrl(
            "http://localhost:8080/index.html?paymentRequestId=" + paymentRequestId);

    AlipayPaymentSessionResponse alipayPaymentSessionResponse;
    try {
        long startTime = System.currentTimeMillis();
        System.out.println("payment request: " + JSON.toJSONString(alipayPaymentSessionRequest));
        alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
        System.out.println("payment response: " + JSON.toJSONString(alipayPaymentSessionResponse));
        System.out.println("payment request cost time: " + (System.currentTimeMillis() - startTime) + "ms");
    } catch (AlipayApiException e) {
        return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), e));
    }
    return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), alipayPaymentSessionResponse));
}
```

   The following code shows a sample of the request message:

   ```json
{
  "agreementInfo": {
    "authState": "authState001",
    "userLoginId": "userLoginId001"
  },
  "order": {
    "buyer": {
      "referenceBuyerId": "referenceBuyerId001"
    },
    "orderAmount": {
      "currency": "CNY",
      "value": "100"
    },
    "orderDescription": "orderDescription001",
    "referenceOrderId": "referenceOrderId001"
  },
  "paymentAmount": {
    "currency": "CNY",
    "value": "100"
  },
  "paymentMethod": {
    "paymentMethodType": "ALIPAY_CN"
  },
  "paymentNotifyUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/record/notify?env=main_online&paymentMethodType=ALIPAY_CN",
  "paymentRedirectUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/result",
  "paymentRequestId": "paymentRequestId001",
  "productCode": "AGREEMENT_PAYMENT",
  "productScene": "EASY_PAY",
  "settlementStrategy": {
    "settlementCurrency": "USD"
  }
}
```

   The following code shows a sample of the response message:

 ```json
{
    "paymentSessionData": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3cjK3CVpnMXY7BfQlIvwNqQWtXHEMUo0R5pQwnSyNtxTA==&&SG&&188&&eyJh***",
    "paymentSessionExpiryTime": "2024-09-27T15:57:30+08:00",
    "paymentSessionId": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3fI21eGbgq240lFVquZsLrM",
    "result": {
        "resultCode": "SUCCESS",
        "resultMessage": "success.",
        "resultStatus": "S"
    }
}
```

 Please take the next step according to the value of the     *result.resultStatus*    .

 | ***resultStatus*** | **Message** | **Further actions** |
| --- | --- | --- |
| `S` | The payment session is successfully created. | Return the obtained     *paymentSessionData*     to the merchant's frontend. For specific operational steps, refer to   [Step 4](#O3ijB)  . |
| `F` | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
| `U` | The payment session creation failed due to unknown reasons. | Replace the     *paymentRequestId*     and     *authstate*     value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |

 > **[INFO]** **Note**    : If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new     *paymentRequestId*     and     *authstate*     value.

**Tab: Subsequent payments**

The following sample code shows how to call the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API:

   ```java
public static void createPaymentSession() {
  AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
  alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
  alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);

  // replace with your paymentRequestId
  String paymentRequestId = UUID.randomUUID().toString();
  alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);

  // set amount
  // you should convert amount unit(in practice, amount should be calculated on your server side)
  Amount amount = Amount.builder().currency("HKD").value("98080").build();
  alipayPaymentSessionRequest.setPaymentAmount(amount);

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

  // set paymentMethod
  PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType("ALIPAY_HK")
  .paymentMethodId("28288803001319861727421828000Cv96OFlYoi17100****").build();
  alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);

  // set buyer info
  Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();

  // replace with your orderId
  String orderId = UUID.randomUUID().toString();
  // set order Info
  Order order = Order.builder().referenceOrderId(orderId).
  orderDescription("antom api testing order").orderAmount(amount).buyer(buyer).build();
  alipayPaymentSessionRequest.setOrder(order);

  // replace with your notify url
  alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com");

  // replace with your redirect url
  alipayPaymentSessionRequest.setPaymentRedirectUrl("http://www.yourRedirectUrl.com");

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

```

   The following code shows a sample of the request message:

   ```json
{
    "order": {
        "buyer": {
            "referenceBuyerId": "yourBuyerId"
        },
        "orderAmount": {
            "currency": "HKD",
            "value": "98080"
        },
        "orderDescription": "antom api testing order",
        "referenceOrderId": "5e445b58-49ad-4552-a36d-d38f311a090d"
    },
    "paymentAmount": {
        "currency": "HKD",
        "value": "98080"
    },
    "paymentMethod": {
        "paymentMethodId": "28288803001319861727421828000Cv96OFlYoi17100****",
        "paymentMethodType": "ALIPAY_HK"
    },
    "paymentNotifyUrl": "http://www.yourNotifyUrl.com",
    "paymentRedirectUrl": "http://www.yourRedirectUrl.com",
    "paymentRequestId": "5810a84e-3a3e-4e47-bbac-9dfe3f2dd2b3",
    "productCode": "AGREEMENT_PAYMENT",
    "productScene": "EASY_PAY",
    "settlementStrategy": {
        "settlementCurrency": "USD"
    }
}
```

   The following code shows a sample of the response message:

   ```json
 {
  "paymentSessionData": "paymentSessionData****",
  "paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
  "paymentSessionId": "paymentSessionId****",
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": "success.",
    "resultStatus": "S"
  }
}
```

 Please take the next step according to the value of the     *result.resultStatus*    .

 | ***resultStatus*** | **Message** | **Further actions** |
| --- | --- | --- |
| `S` | The payment session is successfully created. | Return the obtained     *paymentSessionData*     to the merchant's frontend. For specific operational steps, refer to   [Step 4](#O3ijB)  . |
| `F` | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
| `U` | The payment session creation failed due to unknown reasons. | Replace the     *paymentRequestId*     value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |

 > **[INFO]** **Note**    : If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new     *paymentRequestId*     value.

<!-- /TabGroup -->
 ---

 > **[INFO]** **Common questions**
>
>  **Q: Can I use Chinese characters in the value of the request parameters?**
>
>  A: To avoid incompatibility of a certain payment method, do not use Chinese characters for parameters in the request.
>
>   **Q: How to set the URL to receive the payment notification?**
>
>  A: Specify     *paymentNotifyUrl*     in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API to receive the asynchronous notification about the payment result (  [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)  ), or configure the receiving URL in Antom Dashboard. If the URL is specified in both the request and Antom Dashboard, the value specified in the request takes precedence.
>
>   **Q: What is the difference between**       ***paymentAmount***       **and**       ***orderAmount***      **?**  
>  A:     *paymentAmount*     refers to the payment amount, while     *orderAmount*     refers to the order amount. The actual charged amount is determined by     *paymentAmount*    .
>
>   **Q: What does**       ***paymentSessionExpiryTime***       **specifically refer to in payment requests?**  
>  A:     *paymentSessionExpiryTime*     indicates the validity period from successful payment session creation until the buyer submits the payment. After submission, the payment processing timeout is 10 minutes. Therefore, the maximum total duration from session creation to payment completion is 1 hour and 10 minutes.
>
>   **Q: Which parameters should be prioritized in the response message?**  
>  A:    Pay attention to the following key parameters:
>
>  - *result.resultStatus*    :    Indicates the result of the API call   .
> - *paymentSessionData*    :    Encrypted payment session data, which is passed to the frontend for initializing the Antom SDK.
> - *paymentSessionExpiryTime*    : Expiration timestamp of the payment session.

### Step 3: Invoke the SDK   **[Client-side]** {#O3ijB}

 After obtaining the     *paymentSessionData*     value on the merchant server side, the merchant client can invoke the SDK to redirect the checkout page to the payment method authorization page. When the buyer submits a payment request, the SDK will automatically handle encrypted communication, risk control verification, page redirection, and payment instruction execution, enabling an end-to-end payment authorization process.

#### 1\. Instantiate the SDK {#s89tW}

 1. Use   `AMSEasyPay`  to create the SDK instance. The configuration object includes the following parameters:

 | **Parameter name** | **Required** | **Description** |
| --- | --- | --- |
| *environment* | Yes | Used to specify the environment information   . Valid values are: - `sandbox`  : Sandbox environment - `prod`  : Production environment |
| *locale* | No | Used to specify the language information. Select the appropriate value based on the region of the payment method. Valid values for this parameter are listed as follows.If a value not in the following list is used, the English is used instead. - `en_US`  : English - `in_ID`  : Indonesian - `ms_MY`  : Malay - `tl_PH`  : Filipino - `ko_KR`  : Korean - `zh_CN`  : Simplified Chinese - `zh_HK`  : Traditional Chinese |
| *onEventCallback* | No | A callback function that returns a specific event code when a payment event occurs during SDK runtime. > **[INFO]** **Note**    : After a successful payment, the payment result is not returned by this function by default; instead, the user is redirected to the payment success page you specified. However, when     *notRedirectAfterComplete*     is set to   `true`   and the payment process is completed within the SDK, the system will not perform a redirect after a successful payment but will instead provide an event callback. |

 The following sample code shows how to instantiate the SDK using npm or CDN:

<!-- TabGroup -->

**Tab: npm**

```javascript
import { AMSEasyPay } from '@alipay/ams-checkout' // Manage the package

const checkoutApp = new AMSEasyPay({
  environment: "sandbox",
  locale: "en_US",
  onEventCallback: ({code, message})=>{},
});

```

**Tab: CDN**

```javascript
const checkoutApp = new window.AMSEasyPay({
  environment: "sandbox",
  locale: "en_US",
  onEventCallback: ({code, message})=>{},
});

```

<!-- /TabGroup -->

 2. Use   `createComponent`   in the instance object to create a payment component. The parameters involved are as follows:

 | **Parameter name** | **Required** | **Description** |
| --- | --- | --- |
| *sessionData* | Yes | Create a configuration object using the     *sessionData*     parameter: Use the complete data of the value of     *paymentSessionData*     obtained in the response of the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API as the value of this parameter. |
| *notRedirectAfterComplete* | No | Boolean type. Valid values are: - `false`  : Default value. Indicates that redirection to your page will occur after the payment is completed. The same applies when the value is empty. - `true`  : Indicates that there will be no redirection. You need to monitor the subsequent process after the payment is completed through client-side event codes.   > **[INFO]** **Note**    : - This parameter applies only to scenarios where the payment is completed within the SDK. > - The event codes returned by the client-side are only used as a reference for the redirection operation of the client page. For transaction status updates, refer to the results returned by the server's   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   or   [**inquirePayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API. |

 The following sample code shows how to create the component:

 ```javascript
async function create(sessionData) {
  await checkoutApp.createComponent({
    sessionData: sessionData,
    notRedirectAfterComplete: false // Set as false by default to indicate that it will redirect to your page after the payment is completed.
  });
}
```

 The images below show the rendering effect when the SDK redirects the checkout page to the payment method authorization page:

<!-- TabGroup -->

**Tab: Web**

The image below shows the redirection from the merchant checkout page to the payment method page.

 ![Web user experience showing redirection from the merchant checkout page to the payment method authorization page during the EasySafePay SDK integration](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/b588fdeb-b3a6-40e5-8d53-e007cb729e5d.png)

**Tab: WAP**

The image below shows the merchant checkout page launches a half-screen pop-up or redirects to the digital wallet app.

 ![Mobile WAP user experience showing the merchant checkout page launching a half-screen pop-up or redirecting to the digital wallet app for payment authorization](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/00bb75ea-3cc4-4c04-a0a9-d8a1bf38f8c3.png)

<!-- /TabGroup -->

#### 2\. Handle SDK callback event codes {#omIkM}

 Below are the event codes returned by   `onEventCallback`   and handling recommendations:

 | **Code** | **Description** | **Further action** |
| --- | --- | --- |
| SDK_CALL_URL_SUCCESS | Successfully launched the payment method app or redirected to the merchant page. | No further action is needed. |
| SDK_LAUNCH_PAYMENT_APP_ERROR | This event code indicates one of the following situations: - Failed to invoke the app of the buyer's selected payment method or failed to redirect to the checkout page of the payment method. - Failed to redirect to the merchant page. | Check whether the     *paymentRedirectUrl*     parameter is correctly passed when calling the        [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API. Web/WAP scenarios rarely experience redirection exceptions. However, in the event of any exceptions, it is recommended to verify the redirection link. For mobile app scenarios, if frequent redirection exceptions occur, contact Antom Technical Support to troubleshoot redirection or cross-application calling issues. |
| SDK_PAYMENT_CANCEL | The buyer canceled the payment (the buyer exited the payment page without submitting the order). | You can re-invoke the SDK using     *paymentSessionData*     within its validity period; If it has expired, you need to initiate a new   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        request. |
| SDK_PAYMENT_SUCCESSFUL | Indicates that the payment is successful on the wallet side. | Please obtain the final payment result from Antom server. You can use the        [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)        API or the        [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)        API to confirm the result. Suggest redirecting buyers to the payment result page. > **[INFO]** **Note**    : This event code is returned only when the payment process is completed within the SDK. |
| SDK_PAYMENT_FAIL | Indicates that the payment is unsuccessful on the wallet side. | Please obtain the final payment result from Antom server. You can use the        [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)        API or the        [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)      API to confirm the result. Suggest redirecting buyers to the payment result page. > **[INFO]** **Note**    : This event code is returned only when the payment process is completed within the SDK. |

 The following sample code shows how to handle the callback function:

 ```javascript
// Step 2: Create onEventCallback handler.
function onEventCallback({ code }) {
  switch (code) {
    case 'SDK_PAYMENT_CANCEL':
      console.log(
        'The buyer canceled the payment (the buyer exited the payment page without submitting the order). You can re-invoke the SDK using paymentSessionData within its validity period; If it has expired, you need to initiate a new createPaymentSession (EasySafePay) request.'
      );
      break;
    case 'SDK_CALL_URL_SUCCESS':
      console.log('Successfully launched the payment method app or redirected to the merchant page.');
      break;
    case 'SDK_LAUNCH_PAYMENT_APP_ERROR':
      console.log('Failed to redirect to the checkout page of the payment method, or failed to redirect to the merchant page. Check whether the paymentRedirectUrl parameter is correctly passed when calling the createPaymentSession (EasySafePay) request. Web/WAP scenarios rarely experience redirection exceptions. However, in the event of any exceptions, it is recommended to verify the redirection link.');
      break;
    case 'SDK_PAYMENT_SUCCESSFUL':
      console.log('The wallet has successfully processed the payment. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. Suggest redirecting buyers to the payment result page.');
      break;
    case 'SDK_PAYMENT_FAIL':
      console.log('The wallet failed to process the payment. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result. Suggest redirecting buyers to the payment result page.');
      break;
    default:
      console.log(code);
  }
};
```

#### 3\. Free SDK component resources {#Wl6og}

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

 - When the buyer switches views to exit the checkout page, free the component resources created in the        [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API.
- When the buyer initiates multiple payments, free the component resources created in the previous   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API.
- After obtaining the final payment result, free the component resources.

 The following sample code shows how to free components:

 ```javascript
// Free SDK component resources
checkoutApp.unmount();
```

 > **[INFO]** **Common questions**
>
>  **Q: Can an**      **`AMSEasyPay`**      **instance execute**     **`createComponent`**     **multiple times?**  
>  A: No. If you need to initiate a new payment, you need to create a new   `AMSEasyPay`   instance.
>
>   **Q: Are SDK calls required for both first and subsequent payments?**  
>  A: Yes.

**Tab: iOS**

## User experience {#KPRit}

 This iOS integration guide is designed to help you quickly integrate the digital wallet and online banking payment functions within the app and easily complete the payment interface rendering. The user experience of each payment method on the iOS side varies; refer to the table below for specific interaction experiences:

 | **​**     **Payment method category** | **​**     **Payment method** | **Terminal type** | **First-time payment** | **Subsequent payments** |
| --- | --- | --- | --- | --- |
| Digital wallet | - [AlipayHK](https://docs.antom.com/ac/antomop/aplusalipayhk.md?platform=auto_debit) - [DANA](https://docs.antom.com/ac/antomop/DANA.md?platform=auto_debit) | iOS | Complete the payment on the merchant page. | Complete the payment on the merchant page. |
| - [Alipay](https://docs.antom.com/ac/antomop/alipay_cn.md?platform=auto_debit) - [GCash](https://docs.antom.com/ac/antomop/gcash.md?platform=auto_debit) - [PayPay (SmartPayment)](https://docs.antom.com/ac/antomop/paypay_mdx.md?platform=auto_debit) - TrueMoney - [Touch'n Go eWallet](https://docs.antom.com/ac/antomop/touchngo.md?platform=auto_debit) | iOS | Redirect to the payment method app to complete payment. | Complete the payment on the merchant page. |  |
| Online banking | - [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md) | iOS | Complete the payment on the merchant page. | Complete the payment on the merchant page. |

<!-- TabGroup -->

**Tab: Digital wallet**

Below is the user experience for first and subsequent payments using digital wallets.

<!-- TabGroup -->

**Tab: First payment**

Upon the first payment, the buyer can choose to pay immediately or complete the authorization process. After successful authorization, subsequent payments will be processed by the password-free feature.

<!-- TabGroup -->

**Tab: Pay on the merchant page**

![Mobile user experience showing the digital wallet first payment flow where buyers complete security authentication to enable password-free payments for subsequent transactions on the merchant page](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/4ec4f8db-a7bc-477d-8dcb-e48523e758f5.png)

**Tab: Pay on the payment method app**

![Mobile user experience showing the digital wallet first payment flow where buyers complete security authentication to enable password-free payments for subsequent transactions on the payment method app](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/cac1a674-5136-4593-9139-64899f0b1fd0.png)

<!-- /TabGroup -->

**Tab: Subsequent payments**

Subsequent payments are processed without requiring a password upon order submission.

 ![Mobile user experience showing digital wallet subsequent payment processed automatically without requiring password entry upon order submission](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/ea965bd3-9e82-4bc3-9b0d-be6154032bd6.png)

<!-- /TabGroup -->
 ---

**Tab: Online banking**

Below is the user experience for first and subsequent payments using online banking payment methods.

<!-- TabGroup -->

**Tab: First payment**

Upon the first payment, the buyer can choose to pay immediately or complete the authorization process. After successful authorization, subsequent payments will be processed by the password-free feature.

 ![Mobile user experience showing the online banking first payment where the buyer completes the authorization process to enable subsequent password-free payments](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/1d0f98c2-dbc1-4501-bcee-7e72628bed6f.png)

**Tab: Subsequent payments**

Subsequent payments are processed without requiring a password upon order submission.

 ![Mobile user experience showing the online banking subsequent payment processed automatically without requiring password upon order submission](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/48e3199b-45ea-456c-8814-45bec8918798.png)

<!-- /TabGroup -->
 ---

<!-- /TabGroup -->

## Payment flow {#XtDt3}

<!-- TabGroup -->

**Tab: First payment**

The first payment flow chart:

 ![Sequence diagram illustrating the EasySafePay first payment flow among Buyer, Merchant Client, Merchant Server, and Antom: the buyer enters the checkout page, the merchant creates a payment session via the createPaymentSession API, the client SDK renders the payment interface and manages redirections, the buyer completes authorization, and the merchant receives asynchronous notifyAuthorization and notifyPayment notifications or queries payment status through the inquiryPayment API.](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/31e77630-b716-48f5-8fce-64a8c937a31e.png)

 1. **The buyer enters the checkout page.**
2. **Create a payment session request.**  
   After the buyer selects a payment method and submits the order, you can obtain the payment session by calling the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API.
3. **Invoke the client SDK.**  
   Invoke the SDK using a payment session and the SDK will automatically collect payment elements, render the payment interface, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics. For detailed interaction differences across payment methods, refer to the   [User experience](#jvgmU1)   table  .
4. **Obtain the authorization result.**  
 When the authorization is successful, Antom sends you the asynchronous notification through the   [**notifyAuthorization**](https://docs.antom.com/ac/ams/notifyauth.md)        API.
5. **Obtain the payment result.**  
   Obtain the payment result using one of the following methods:

   - Asynchronous notification: Specify     *paymentNotifyUrl*     in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)        to send asynchronous notifications to you.
  - Synchronous inquiry: Call the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)        API to check the real-time payment status.

**Tab: Subsequent payments**

The subsequent payment flow chart:

 ![Sequence diagram illustrating the EasySafePay subsequent payment flow among Buyer, Merchant Client, Merchant Server, and Antom: the buyer enters the checkout page, the merchant creates a payment session using the previously authorized paymentMethodId via the createPaymentSession API, the client SDK renders the payment interface, the buyer submits the order, and the merchant receives an asynchronous notifyPayment notification or uses the inquiryPayment API to check payment status.](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/458d34c9-5e85-4c13-99ca-9aa43b6f1adf.png)

 1. **The buyer enters the checkout page.**
2. **Create a payment session request.**  
   After the buyer selects a payment method and submits the order, you can obtain the payment session by calling the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API.
3. **Invoke the client SDK.**  
 Invoke the SDK using a payment session and the SDK will automatically collect payment elements, render the payment interface, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics. For detailed interaction differences across payment methods, refer to the   [User experience](#jvgmU1)   table  .
4. **Obtain the payment result.**  
   Obtain the payment result using one of the following methods:

   - Asynchronous notification: Specify     *paymentNotifyUrl*     in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)        to send asynchronous notifications to you.
  - Synchronous inquiry: Call the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)        API to check the real-time payment status.

<!-- /TabGroup -->
 ---

## Integration preparations {#uAenb}

 Before you start integrating, read the   [Integration Guide](https://docs.antom.com/integration_guide_en.md)   and   [API Overview](https://docs.antom.com/ac/ams/api_fund.md)   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](https://docs.antom.com/ac/sdks/server_sdks.md)  .
- If you need to conduct joint debugging by connecting the sandbox with the production environment, please contact Antom technical support at least two business days in advance to request configuration. The sandbox environment and production environment require separate configuration.

 Refer to  [Integrate the SDK package for iOS](https://docs.antom.com/ac/sdks/ios.md)   to complete integration preparations.

## Integration steps {#WkuR9}

 Start your integration by taking the following steps:

 1. (Optional) Preload the SDK
2. Create a payment session
3. Invoke the SDK
4. Obtain the authorization and payment result

### (Optional) Step 1: Preload the SDK **[Client-side]** {#GcEXM}

 Preloading the SDK during the checkout page initialization significantly improves the rendering performance with no negative impact. It is recommended to trigger preloading of the SDK when the buyer selects a payment method.

 Follow the code example below to perform the preloading:   ```objectivec
[AMSEasyPay.shared preload];
```

### Step 2: Create a payment session **[Server-side]** {#EZvir}

 When a buyer selects a payment method provided by Antom, you need to collect essential information including the payment request ID, order amount, payment method, order description, payment redirect page URL, and payment result notification URL.

 Call the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API to create a payment session and initialize the Antom SDK using the     *paymentSessionData*     value returned in the response.

 The table below lists the parameter specifications for calling the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API during the first and subsequent payments:

 > **[INFO]** **Note**    : For subsequent payments with   [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md)  , simply keep the parameters consistent with the first payment. The buyer can open the   [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md)   webpage and enter the phone number to proceed directly with the payment.

 | **Parameter type** | **Parameter name** | **Required** **(First-time payment)** | **Required** **(Subsequent payments)** | **Description** |
| --- | --- | --- | --- | --- |
| Base parameter | *productCode* | Yes | Yes | The value is fixed as   `AGREEMENT_PAYMENT`   in the EasySafePay scenario. |
| *productScene* | Yes | Yes | The value is fixed as   `EASY_PAY`   in the EasySafePay scenario. |  |
| *paymentRequestId* | Yes | Yes | The unique ID assigned by a merchant to identify a payment request. |  |
| *paymentMethod.paymentMethodType* | Yes | Yes | The payment method type that is included in   [payment method](https://docs.antom.com/ac/pm/enumeration_values.md)   options. |  |
| *paymentMethod.paymentMethodId* | No | Yes | The unique ID that is used to identify a payment method. T   he value of this parameter is that of     *accessToken*     from the   [**notifyAuthorization**](https://docs.antom.com/ac/ams/notifyauth.md)   API. |  |
| *settlementStrategy* | No | No | The settlement strategy for the payment request.    If the merchant agreement supports multiple settlement currencies, they must be specified in the API request. |  |
| *paymentAmount.value* | Yes | Yes | The value of the amount as a positive integer in the smallest currency unit. For details about the smallest currency unit, see   [Smallest unit of the currency](https://docs.antom.com/ac/ref/cc.md#ONkIe)   . |  |
| *paymentAmount.currency* | Yes | Yes | The transaction currency, which is a 3-letter currency code that follows the   [ISO 4217](https://www.iso.org/iso-4217-currency-codes.html)   standard. |  |
| *paymentSessionExpiryTime* | No | No | The specific date and time after which the payment session will expire. The default expiration time is 1 hour after the session creation. For example, if the session is created at 2023-7-27T12:00:01+08:30, the session expiration time is 2023-7-27T13:00:01+08:30. |  |
| *paymentRedirectUrl* | Yes | Yes | The merchant page URL that the user is redirected to after the payment is completed. The page display according to the server-side result and should not default to a fixed payment success page. - If the payment is initiated from a Web or WAP platform, pass the WAP URL. - If the payment is initiated from an App, pass the scheme URL. |  |
| *paymentNotifyUrl* | No | No | The URL that is used to receive the payment result notification.    it must be an HTTPS URL. This field can be omitted if already configured via Antom Dashboard. |  |
| Authorization parameter | *agreementInfo.authState* | Yes | No | The unique ID generated by the merchant to initiate an Easy   Safe   Pay authorization. |
| Order    parameter | *order.ord*     *erAmount* | Yes | Yes | The order amount of the merchant that directly provides services or goods to the customer |
| *order.referenceOrderId* | Yes | Yes | The unique ID to identify the order on the merchant side. |  |
| *order.orderDescription* | Yes | Yes | Summary description of the order. |  |
| *order.buyer.referenceBuyerId* | No | No | Submit buyer information for risk assessment. Provide at least one of these fields:     *referenceBuyerId*    ,     *buyerPhoneNo*    , or     *buyerEmail*    . |  |
|  | *order.buyer.*   - *buyerPhoneNo*   - *buyerEmail* | No | No | Buyer's account. Providing relevant payment account information can effectively improve the payment success rate and reduce the risk of buyer attrition. Please refer to the table below for specific format requirements. |

 The parameter format for the buyer's payment account for each payment method is as follows:

 | **Payment method** | **Parameter format** |
| --- | --- |
| [AlipayHK](https://docs.antom.com/ac/antomop/aplusalipayhk.md?platform=auto_debit) | It is recommended to prioritize using a mobile phone number: - Mobile number:     - Hong Kong, China: 852-12****78. The phone number must be 8 digits long, excluding the prefix.   - China: 86-137****5678. The phone number must be 11 digits long, excluding the prefix.   - Email: xxx@xxx.com |
| [DANA](https://docs.antom.com/ac/antomop/DANA.md?platform=auto_debit) | 62-8569****7288. The phone number starts with 8 and is no more than 12 digits long, excluding the prefix. |
| [Alipay](https://docs.antom.com/ac/antomop/alipay_cn.md?platform=auto_debit) [GCash](https://docs.antom.com/ac/antomop/gcash.md?platform=auto_debit) [Touch'n Go eWallet](https://docs.antom.com/ac/antomop/touchngo.md?platform=auto_debit) TrueMoney [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md) | The buyer is authenticated on the payment method side, and no parameters need to be passed in.    *userloginId.* |

 During the first-time payment, passing the buyer's payment account will auto-fill the buyer's account on the payment page, eliminating manual input. Below is a comparison of the user experience with and without these fields:

<!-- TabGroup -->

**Tab: With account parameter passed**

Login account input is not required.

 ![User experience showing the merchant checkout page when the buyer's payment account parameter is passed, where the login account input field is pre-filled and manual input is not required](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/4ec4f8db-a7bc-477d-8dcb-e48523e758f5.png)

**Tab: Without account parameter passed**

Manual input of login account is required.

 ![User experience showing the merchant checkout page when the buyer's payment account parameter is not passed, requiring manual input of the login account](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/25f256b6-e891-4e4a-95ec-862043a4d19a.png)

<!-- /TabGroup -->
 Below are code examples for first and subsequent payments.

<!-- TabGroup -->

**Tab: First payment**

The following sample code shows how to call the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API:

 ```java
@PostMapping("/payment/createSession")
public ResponseEntity<ApiResponse> createPaymentSession(@RequestBody PaymentVO payment) {
    AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
    alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
    alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);

    // replace with your paymentRequestId
    String paymentRequestId = UUID.randomUUID().toString();
    alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);

    // convert amount unit(in practice, amount should be calculated on your server side)
    // For details, refer to: <a href="https://docs.antom.com/ac/ref/cc">Usage rules of the Amount object</a>
    long amountMinorLong = Money.of(CurrencyUnit.of(payment.currency), new BigDecimal(payment.amountValue)).getAmountMinorLong();

    // set amount
    Amount amount = Amount.builder().currency(payment.currency).value(String.valueOf(amountMinorLong)).build();
    alipayPaymentSessionRequest.setPaymentAmount(amount);

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

    User loginUser = users.get(payment.getUserId());

    // set paymentMethod
    PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType(payment.paymentMethodType).build();
    if (loginUser.getPaymentMethodTypeAccessToken().containsKey(payment.getPaymentMethodType())) {
        // buyer has authorized
        String accessToken = loginUser.getPaymentMethodTypeAccessToken().get(payment.getPaymentMethodType());
        paymentMethod.setPaymentMethodId(accessToken);
    } else {
        // set agreementInfo
        // replace with your authState
        String authState = UUID.randomUUID().toString();
        // The login ID that the buyer used to register in the payment method client. The login ID can be the buyer's email address or phone number.
        // Specify this parameter to free buyers from manually entering their login IDs.
        String userLoginId = loginUser.getPhoneNumber();
        AgreementInfo agreementInfo = AgreementInfo.builder().authState(authState).userLoginId(userLoginId).build();
        alipayPaymentSessionRequest.setAgreementInfo(agreementInfo);

        // save the paymentMethodType corresponding to the authState
        authStatePayment.put(authState, payment);
    }
    alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);

    // set buyer info
    Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();

    // replace with your orderId
    String orderId = UUID.randomUUID().toString();
    // set order Info
    Order order = Order.builder().referenceOrderId(orderId)
            .orderDescription("antom sdk testing order").orderAmount(amount).buyer(buyer).build();
    alipayPaymentSessionRequest.setOrder(order);

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

    // replace with your redirect url
    alipayPaymentSessionRequest.setPaymentRedirectUrl(
            "http://localhost:8080/index.html?paymentRequestId=" + paymentRequestId);

    AlipayPaymentSessionResponse alipayPaymentSessionResponse;
    try {
        long startTime = System.currentTimeMillis();
        System.out.println("payment request: " + JSON.toJSONString(alipayPaymentSessionRequest));
        alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
        System.out.println("payment response: " + JSON.toJSONString(alipayPaymentSessionResponse));
        System.out.println("payment request cost time: " + (System.currentTimeMillis() - startTime) + "ms
");
    } catch (AlipayApiException e) {
        return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), e));
    }
    return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), alipayPaymentSessionResponse));
}
```

   The following code shows a sample of the request message:

   ```json
{
  "agreementInfo": {
    "authState": "authState001",
    "userLoginId": "userLoginId001"
  },
  "order": {
    "buyer": {
      "referenceBuyerId": "referenceBuyerId001"
    },
    "orderAmount": {
      "currency": "CNY",
      "value": "100"
    },
    "orderDescription": "orderDescription001",
    "referenceOrderId": "referenceOrderId001"
  },
  "paymentAmount": {
    "currency": "CNY",
    "value": "100"
  },
  "paymentMethod": {
    "paymentMethodType": "ALIPAY_CN"
  },
  "paymentNotifyUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/record/notify?env=main_online&paymentMethodType=ALIPAY_CN",
  "paymentRedirectUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/result",
  "paymentRequestId": "paymentRequestId001",
  "productCode": "AGREEMENT_PAYMENT",
  "productScene": "EASY_PAY",
  "settlementStrategy": {
    "settlementCurrency": "USD"
  }
}
```

   The following code shows a sample of the response message:

 ```json
{
    "paymentSessionData": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3cjK3CVpnMXY7BfQlIvwNqQWtXHEMUo0R5pQwnSyNtxTA==&&SG&&188&&eyJh***",
    "paymentSessionExpiryTime": "2024-09-27T15:57:30+08:00",
    "paymentSessionId": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3fI21eGbgq240lFVquZsLrM",
    "result": {
        "resultCode": "SUCCESS",
        "resultMessage": "success.",
        "resultStatus": "S"
    }
}
```

 Please take the next step according to the value of the     *result.resultStatus*    .

 | ***resultStatus*** | **Message** | **Further actions** |
| --- | --- | --- |
| `S` | The payment session is successfully created. | Return the obtained     *paymentSessionData*     to the merchant's frontend. For specific operational steps, refer to   [Step 4](#O3ijB)  . |
| `F` | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
| `U` | The payment session creation failed due to unknown reasons. | Replace the     *paymentRequestId*     and     *authstate*     value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |

 > **[INFO]** **Note**    : If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new     *paymentRequestId*     and     *authstate*     value.

**Tab: Subsequent payments**

The following sample code shows how to call the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API:

 ```java
public static void createPaymentSession() {
  AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
  alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
  alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);

  // replace with your paymentRequestId
  String paymentRequestId = UUID.randomUUID().toString();
  alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);

  // set amount
  // you should convert amount unit(in practice, amount should be calculated on your server side)
  Amount amount = Amount.builder().currency("HKD").value("98080").build();
  alipayPaymentSessionRequest.setPaymentAmount(amount);

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

  // set paymentMethod
  PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType("ALIPAY_HK")
  .paymentMethodId("28288803001319861727421828000Cv96OFlYoi17100****").build();
  alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);

  // set buyer info
  Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();

  // replace with your orderId
  String orderId = UUID.randomUUID().toString();
  // set order Info
  Order order = Order.builder().referenceOrderId(orderId).
  orderDescription("antom api testing order").orderAmount(amount).buyer(buyer).build();
  alipayPaymentSessionRequest.setOrder(order);

  // replace with your notify url
  alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com");

  // replace with your redirect url
  alipayPaymentSessionRequest.setPaymentRedirectUrl("http://www.yourRedirectUrl.com");

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

```

   The following code shows a sample of the request message:

   ```json
{
    "order": {
        "buyer": {
            "referenceBuyerId": "yourBuyerId"
        },
        "orderAmount": {
            "currency": "HKD",
            "value": "98080"
        },
        "orderDescription": "antom api testing order",
        "referenceOrderId": "5e445b58-49ad-4552-a36d-d38f311a090d"
    },
    "paymentAmount": {
        "currency": "HKD",
        "value": "98080"
    },
    "paymentMethod": {
        "paymentMethodId": "28288803001319861727421828000Cv96OFlYoi17100****",
        "paymentMethodType": "ALIPAY_HK"
    },
    "paymentNotifyUrl": "http://www.yourNotifyUrl.com",
    "paymentRedirectUrl": "http://www.yourRedirectUrl.com",
    "paymentRequestId": "5810a84e-3a3e-4e47-bbac-9dfe3f2dd2b3",
    "productCode": "AGREEMENT_PAYMENT",
    "productScene": "EASY_PAY",
    "settlementStrategy": {
        "settlementCurrency": "USD"
    }
}
```

   The following code shows a sample of the response message:

   ```json
 {
  "paymentSessionData": "paymentSessionData****",
  "paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
  "paymentSessionId": "paymentSessionId****",
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": "success.",
    "resultStatus": "S"
  }
}
```

 Please take the next step according to the value of the     *result.resultStatus*    .

 | ***resultStatus*** | **Message** | **Further actions** |
| --- | --- | --- |
| `S` | The payment session is successfully created. | Return the obtained     *paymentSessionData*     to the merchant's frontend. For specific operational steps, refer to   [Step 4](#O3ijB)  . |
| `F` | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
| `U` | The payment session creation failed due to unknown reasons. | Replace the     *paymentRequestId*     value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |

 > **[INFO]** **Note**    : If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new     *paymentRequestId*     value.

<!-- /TabGroup -->
 ---

 > **[INFO]** **Common questions**
>
>  **Q: Can I use Chinese characters in the value of the request parameters?**
>
>  A: To avoid incompatibility of a certain payment method, do not use Chinese characters for parameters in the request.
>
>   **Q: How to set the URL to receive the payment notification?**
>
>  A: Specify     *paymentNotifyUrl*     in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API to receive the asynchronous notification about the payment result (  [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)  ), or configure the receiving URL in Antom Dashboard. If the URL is specified in both the request and Antom Dashboard, the value specified in the request takes precedence.
>
>   **Q: What is the difference between**       ***paymentAmount***       **and**       ***orderAmount***      **?**  
>  A:     *paymentAmount*     refers to the payment amount, while     *orderAmount*     refers to the order amount. The actual charged amount is determined by     *paymentAmount*    .
>
>   **Q: What does**       ***paymentSessionExpiryTime***       **specifically refer to in payment requests?**  
>  A:     *paymentSessionExpiryTime*     indicates the validity period from successful payment session creation until the buyer submits the payment. After submission, the payment processing timeout is 10 minutes. Therefore, the maximum total duration from session creation to payment completion is 1 hour and 10 minutes.
>
>   **Q: Which parameters should be prioritized in the response message?**  
>  A:    Pay attention to the following key parameters:
>
>  - *result.resultStatus*    :    Indicates the result of the API call.
> - *paymentSessionData*    :    Encrypted payment session data, which is passed to the frontend for initializing the Antom SDK.
> - *paymentSessionExpiryTime*    : Expiration timestamp of the payment session.

### Step 3: Invoke the SDK   **[Client-side]** {#e557I}

 After obtaining the     *paymentSessionData*     value on the merchant server side, the merchant client can invoke the SDK to redirect the checkout page to the payment method authorization page. When the buyer submits a payment request, the SDK will automatically handle encrypted communication, risk control verification, page redirection, and payment instruction execution, enabling an end-to-end payment authorization process.

#### 1\. Instantiate the SDK {#NYusM}

 1. Use   `AMSEasyPayConfiguration`  to create the SDK instance. The configuration object includes the following parameters:

 | **Parameter name** | **Required** | **Description** |
| --- | --- | --- |
| *locale* | No | Used to specify the language information. Select the appropriate value based on the region of the payment method. Valid values for this parameter are listed as follows. If a value not in the following list is used, English is used instead. - `en_US`  : English - `in_ID`  : Indonesian - `ms_MY`  : Malay - `tl_PH`  : Filipino - `ko_KR`  : Korean - `zh_CN`  : Simplified Chinese - `zh_HK`  : Traditional Chinese |
| *options* | No | Used to specify whether to use the sandbox environment. Valid values are: - `"sandbox", "true"`  : Sandbox environment - `"sandbox", "false"`  : Production environment - `"notRedirectAfterComplete", "false"`  : Optional, Boolean type. The default value is   `false`  , indicates that redirection to your page takes place after the payment is complete. The same applies when the value is empty. When the value is   `true`  , redirection will not take place after the payment is complete. You need to use the customer event code to control the payment and complete the subsequent process.   > **[INFO]** **Note**    : - This parameter applies only to scenarios where the payment is completed within the SDK. > - The result and event codes returned by the client-side are only used as a reference for the redirection operation of the client page. For transaction status updates, refer to the results returned by the server's   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   or   [**inquirePayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API. |
| *fromScheme* | No | In the Alipay scenario, when a buyer completes payment in the Alipay wallet, the system will redirect back to your merchant app according to the `exampleForScheme`   configuration. > **[INFO]** **Note**    : In the iOS Native environment, Alipay only supports redirecting to the app's launch page specified by     *componentConfig.fromScheme*    , rather than the     *paymentRedirectUrl*     specified in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API. The specific redirect page needs to be controlled through the event code. |

 2. Create an instance of the     **AMSPaymentProtocol**     API to process the payment callback result, which includes the following method:

 | **Method** | **Required** | **Description** |
| --- | --- | --- |
| `onEventCallback` | No | A callback function that monitors payment events on the checkout page, returning     *eventCode*     and     *eventResult*    . The payment success result will not be returned by this callback function by default. A redirection to the payment success result page that you specified will take place instead. However, when     *notRedirectAfterComplete*     is set to   `true`  , the system will not perform redirection upon payment completion, instead it will provide event callback. > **[INFO]** **Note**    : When integrating with Alipay, if you invoke   `processOrderWithPaymentResult`  , you will receive the payment event codes returned by   `onEventCallback`  . If you do not invoke   `processOrderWithPaymentResult`  , payment event codes will not be returned, but you can query the payment result by calling the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)      API on the server. |

 The following sample code shows how to instantiate the SDK:

 ```objectivec
#import <AMSComponent/AMSComponent-Swift.h>

AMSEasyPayConfiguration *componentConfig = [AMSEasyPayConfiguration new];
// Alipay needs to add fromScheme. Note that this address refers to the corresponding APP startup page after the payment is completed.
componentConfig.fromScheme = @"exampleForScheme";

componentConfig.locale = @"en_US";
// Set the sandbox environment. If you leave it empty, the production environment is used by default.
NSDictionary *options = @{@"sandbox": @"true",
                          @"notRedirectAfterComplete": @"false"};
componentConfig.options = options;

[[AMSEasyPay shared] initConfiguration:componentConfig];

// Set the callback to monitor payment events on the checkout page.
[AMSEasyPay shared].paymentDelegate = self;

#pragma AMSPaymentProtocol
- (void)onEventCallback:(NSString *)eventCode eventResult:(AMSEventResult *)eventResult
{
    NSLog(@"eventCode%@ eventResult%@", eventCode, eventResult);
}

```

 The following image shows the rendering effect of the merchant checkout page invoking a half-screen pop-up or redirecting to the digital wallet app:

 ![Mobile user experience showing the merchant checkout page launching a half-screen pop-up or redirecting to the digital wallet app for payment authorization](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/00bb75ea-3cc4-4c04-a0a9-d8a1bf38f8c3.png)

 3. Use the   `createComponent`   method in the instance object to create a payment component, which includes the following parameter:

 | **Parameter name** | **Required** | **Description** |
| --- | --- | --- |
| *sessionData* | Yes | Create a configuration object using the     *sessionData*     parameter: Use the complete data of the value of     *paymentSessionData*     obtained in the response of the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API as the value of this parameter. |

 The sample code is as follows:

 ```objectivec
[[AMSEasyPay shared] createComponent:sessionData];
```

#### 2\. Handle SDK callback event codes {#pULRI}

 Below are the event codes returned by   `onEventCallback`   and handling recommendations:

 | **Type** | **Code** | **Description** | **Further action** |
| --- | --- | --- | --- |
| Status code | SDK_CALL_URL_SUCCESS | This event code indicates that redirect successfully for the     *paymentRedirectUrl.* | Please obtain the final payment result from Antom server. You can use the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API or the   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   API to confirm the result. |
| SDK_PAYMENT_CANCEL | The buyer canceled the payment (the buyer exited the payment page without submitting the order). | You can re-invoke the SDK using     *paymentSessionData*     within its validity period; If it has expired, you need to initiate a new   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API. |  |
| SDK_PAYMENT_SUCCESSFUL | Indicates that the wallet has successfully processed the payment. | Please obtain the final payment result from Antom server. You can use the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API or the   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   API to confirm the result. > **[INFO]** **Note**    : For payment solutions not integrated with Alipay, suggest redirecting users to the payment result page. |  |
| SDK_PAYMENT_FAIL | Indicates that the wallet failed to process the payment. | Please obtain the final payment result from Antom server. You can use the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API or the   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   API to confirm the result. > **[INFO]** **Note**    : For payment solutions not integrated with Alipay, suggest redirecting users to the payment result page. |  |
| SDK_PAYMENT_PROCESSING (Returned when integrated with Alipay) | Indicates that the payment status of the Alipay walletis unknown. | Please obtain the final payment result from Antom server. You can use the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API or the   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   API to confirm the result. |  |
| SDK_PAYMENT_ERROR (Returned when integrated with Alipay) | Indicates that the payment processing of the Alipay wallet is abnormal. | Please obtain the final payment result from Antom server. You can use the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API or the   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   API to confirm the result. |  |
| Error code ​ | SDK_CREATEPAYMENT_PARAMETER_ERROR | The parameters passed to the `createComponent`   method are not correct. | Check if the parameters are correct and re-initialize the component. |
| SDK_STATUS_ERROR | This event code indicates one of the following situations: - You just call   `createComponent`   when it is still in previous payment flow. - You just call   `createComponent`   without init. - You just call   `createComponent`   when another Popup is active. | Please check the result message, then match the error   situations. |  |
| SDK_INTEGRATION_ERROR | This event code indicates that   some dependencies of SDK is not exist. Currently there are two scenario: - Security SDK is not exist. - Open security browser failed. | Please check whether target module has been integrated. |  |
| SDK_LAUNCH_PAYMENT_APP_ERROR | This event code indicates one of the following situations: - Failed to redirect to the merchant page. - Failed to redirect to the 3D verification page. - The     *paymentRedirectUrl*     parameter was either not passed or incorrectly passed when calling the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API. | Check whether the     *paymentRedirectUrl*     parameter is correctly passed when calling the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API. If frequent redirection exceptions occur, contact Antom Technical Support to troubleshoot redirection or cross-application calling issues. |  |

 The following sample code shows how to handle the callback function:

 ```objectivec
-(void)onEventCallback:(NSString *)eventCode eventResult:(AMSEventResult *)eventResult {
    if ([[_selectMethod title] isEqualToString:@"ALIPAY_CN"]) {
        if ([eventCode isEqualToString:@"SDK_PAYMENT_CANCEL"]) {
            NSLog(@"The buyer canceled the payment (the buyer exited the payment page without submitting the order). You can re-invoke the SDK using paymentSessionData within its validity period; If it has expired, you need to initiate a new createPaymentSession (EasySafePay) request.");
        } else if ([eventCode isEqualToString:@"SDK_PAYMENT_SUCCESSFUL"]) {
            NSLog(@"The Alipay wallet has successfully processed the payment. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result.");
        } else if ([eventCode isEqualToString:@"SDK_PAYMENT_FAIL"]) {
            NSLog(@"The Alipay wallet failed to process the payment. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result.");
        } else if ([eventCode isEqualToString:@"SDK_PAYMENT_PROCESSING"]) {
            NSLog(@"The payment status of the Alipay wallet is unknown. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result.");
        } else if ([eventCode isEqualToString:@"SDK_PAYMENT_ERROR"]) {
            NSLog(@"The payment processing of the Alipay wallet is abnormal. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result.");
        } else {
            NSLog(@"eventCode%@ eventResult%@", eventCode, eventResult);
        }
    } else {
        // Please note that payment success will not be notified through this callback function, but will instead redirect to the success result page you specified.
        if ([eventCode isEqualToString:@"SDK_PAYMENT_CANCEL"]) {
            NSLog(@"The buyer canceled the payment (the buyer exited the payment page without submitting the order). You can re-invoke the SDK using paymentSessionData within its validity period; If it has expired, you need to initiate a new createPaymentSession (EasySafePay) request.");
        } else if ([eventCode isEqualToString:@"SDK_CALL_URL_SUCCESS"]) {
            NSLog(@"Open wallet app or redirect to the merchant page successfully.");
        } else if ([eventCode isEqualToString:@"SDK_LAUNCH_PAYMENT_APP_ERROR"]) {
            NSLog(@"Open wallet app or redirect to the merchant page failed");
        } else if ([eventCode isEqualToString:@"SDK_CREATEPAYMENT_PARAMETER_ERROR"]) {
            NSLog(@"The input parameter provided is invalid. Please check the value and try again.");
        } else {
            NSLog(@"eventCode%@ eventResult%@", eventCode, eventResult);
        }
    }
}

```

#### 3\. Free SDK component resources {#I8dHp}

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

 - When the buyer exits the checkout page,    completely    free the component resources created in the        [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API.
- When the buyer initiates multiple payments, and the parameters in   `initConfiguration`   have changed, free the component resources created in the previous        [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API.

 In the following scenario, you do not need to call `onDestroy`, and the SDK will automatically free partial resources (for iOS SDK AMSComponents 1.33.0 or above).

 - When the buyer initiates multiple payments, and the parameters in   `initConfiguration`   have not changed. The SDK will automatically free partial resources after the payment is completed to reset to the state before   `createComponent`      was called   .

 The following sample code shows how to free components:

 ```objectivec
// Completely free SDK component resources
[[AMSEasyPay shared] onDestroy];
```

 > **[INFO]** **Common questions**
>
>  **Q: Is it mandatory to handle SDK callback events?**  
>  A: For Alipay, you must process event codes to display payment results, but this payment method is optional. Callback events can also be used for logging.
>
>  ​
>
>  **Q: Can an**       ***AMSEasypay***       **instance execute**       ***createComponent***       **multiple times?**  
>  A: No. You need to create a fresh    *AMSEasypay*     instance to initiate a new payment.
>
>  ​
>
>  **Q: Are SDK calls required for both first-time and subsequent payments?**  
>    A: Yes.

#### 4\. Receive notification from callback function (When integrating Alipay) {#GPnIO}

 When integrating with Alipay, the merchant-client can receive notifications from the callback function. After receiving the callback notification, use the   `openURL`   method in the     *AppDelegate*     file to handle the result returned by Alipay:

 - Use   `canProcessOrderWithPaymentResult()`   to check whether the redirect URL, to redirect from the wallet to the merchant side, is valid.
- Use   `processOrderWithPaymentResult()`   to handle the redirection from the wallet to the merchant's side.

 ```objectivec
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
     if ([url.scheme isEqualToString:@"exampleForScheme"]) {
        if ([[AMSEasyPay shared] canProcessOrderWithPaymentResult:url]) {
            [[AMSEasyPay shared] processOrderWithPaymentResult:url];
        }
    }
    return YES;
}
```

**Tab: Android**

## User experience {#J907Z}

 This Android integration guide is designed to help you quickly integrate the digital wallet and online banking payment functions within the app and easily complete the payment interface rendering. The user experience of each payment method on the Android side varies; refer to the table below for specific interaction experiences:

 | **​**     **Payment method category** | **​**     **Payment method** | **Terminal type** | **First-time payment** | **Subsequent payments** |
| --- | --- | --- | --- | --- |
| Digital wallet | - [AlipayHK](https://docs.antom.com/ac/antomop/aplusalipayhk.md?platform=auto_debit) - [DANA](https://docs.antom.com/ac/antomop/DANA.md?platform=auto_debit) | Android | Complete the payment on the merchant page. | Complete the payment on the merchant page. |
| - [Alipay](https://docs.antom.com/ac/antomop/alipay_cn.md?platform=auto_debit) - [GCash](https://docs.antom.com/ac/antomop/gcash.md?platform=auto_debit) - [PayPay (SmartPayment)](https://docs.antom.com/ac/antomop/paypay_mdx.md?platform=auto_debit) - TrueMoney - [Touch'n Go eWallet](https://docs.antom.com/ac/antomop/touchngo.md?platform=auto_debit) | Android | Redirect to the payment method app to complete payment. | Complete the payment on the merchant page. |  |
| Online banking | - [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md) | Android | Complete the payment on the merchant page. | Complete the payment on the merchant page. |

<!-- TabGroup -->

**Tab: Digital wallet**

Below is the user experience for first and subsequent payments using digital wallets.

<!-- TabGroup -->

**Tab: First payment**

Upon the first payment, the buyer can choose to pay immediately or complete the authorization process. After successful authorization, subsequent payments will be processed by the password-free feature.

<!-- TabGroup -->

**Tab: Pay on the merchant page**

![Mobile user experience showing the digital wallet first payment flow where buyers complete security authentication to enable password-free payments for subsequent transactions on the merchant page](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/4ec4f8db-a7bc-477d-8dcb-e48523e758f5.png)

**Tab: Pay on the payment method app**

![Mobile user experience showing the digital wallet first payment flow where buyers complete security authentication to enable password-free payments for subsequent transactions on the payment method app](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/cac1a674-5136-4593-9139-64899f0b1fd0.png)

<!-- /TabGroup -->

**Tab: Subsequent payments**

Subsequent payments are processed without requiring a password upon order submission.

 ![Mobile user experience showing digital wallet subsequent payment processed automatically without requiring password entry upon order submission](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/ea965bd3-9e82-4bc3-9b0d-be6154032bd6.png)

<!-- /TabGroup -->
 ---

**Tab: Online banking**

Below is the user experience for first and subsequent payments using online banking payment methods.

<!-- TabGroup -->

**Tab: First payment**

Upon the first payment, the buyer can choose to pay immediately or complete the authorization process. After successful authorization, subsequent payments will be processed by the password-free feature.

 ![Mobile user experience showing the online banking first payment where the buyer completes the authorization process to enable subsequent password-free payments](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/4ec4f8db-a7bc-477d-8dcb-e48523e758f5.png)

**Tab: Subsequent payments**

Subsequent payments are processed without requiring a password upon order submission.

 ![Mobile user experience showing the online banking subsequent payment processed automatically without requiring password upon order submission](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/48e3199b-45ea-456c-8814-45bec8918798.png)

<!-- /TabGroup -->
 ---

<!-- /TabGroup -->

## Payment flow {#yaWZ3}

<!-- TabGroup -->

**Tab: First payment**

The first payment flow chart:

 ![Sequence diagram illustrating the EasySafePay first payment flow among Buyer, Merchant Client, Merchant Server, and Antom: the buyer enters the checkout page, the merchant creates a payment session via the createPaymentSession API, the client SDK renders the payment interface and manages redirections, the buyer completes authorization, and the merchant receives asynchronous notifyAuthorization and notifyPayment notifications or queries payment status through the inquiryPayment API.](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/31e77630-b716-48f5-8fce-64a8c937a31e.png)

 1. **The buyer enters the checkout page.**
2. **Create a payment session request.**  
   After the buyer selects a payment method and submits the order, you can obtain the payment session by calling the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API.
3. **Invoke the client SDK.**  
   Invoke the SDK using a payment session and the SDK will automatically collect payment elements, render the payment interface, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics. For detailed interaction differences across payment methods, refer to the   [User experience](#jvgmU1)   table  .
4. **Obtain the authorization result.**  
 When the authorization is successful, Antom sends you the asynchronous notification through the   [**notifyAuthorization**](https://docs.antom.com/ac/ams/notifyauth.md)        API.
5. **Obtain the payment result.**  
   Obtain the payment result using one of the following methods:

   - Asynchronous notification: Specify     *paymentNotifyUrl*     in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)        to send asynchronous notifications to you.
  - Synchronous inquiry: Call the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)        API to check the real-time payment status.

**Tab: Subsequent payments**

The subsequent payment flow chart:

 ![Sequence diagram illustrating the EasySafePay subsequent payment flow among Buyer, Merchant Client, Merchant Server, and Antom: the buyer enters the checkout page, the merchant creates a payment session using the previously authorized paymentMethodId via the createPaymentSession API, the client SDK renders the payment interface, the buyer submits the order, and the merchant receives an asynchronous notifyPayment notification or uses the inquiryPayment API to check payment status.](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/458d34c9-5e85-4c13-99ca-9aa43b6f1adf.png)

 1. **The buyer enters the checkout page.**
2. **Create a payment session request.**  
   After the buyer selects a payment method and submits the order, you can obtain the payment session by calling the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API.
3. **Invoke the client SDK.**  
 Invoke the SDK using a payment session and the SDK will automatically collect payment elements, render the payment interface, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics. For detailed interaction differences across payment methods, refer to the   [User experience](#jvgmU1)   table  .
4. **Obtain the payment result.**  
   Obtain the payment result using one of the following methods:

   - Asynchronous notification: Specify     *paymentNotifyUrl*     in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)        to send asynchronous notifications to you.
  - Synchronous inquiry: Call the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)        API to check the real-time payment status.

<!-- /TabGroup -->
 ---

## Integration preparations {#Am1gM}

 Before you start integrating, read the   [Integration Guide](https://docs.antom.com/integration_guide_en.md)   and   [API Overview](https://docs.antom.com/ac/ams/api_fund.md)   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](https://docs.antom.com/ac/sdks/server_sdks.md)  .
- If you need to conduct joint debugging by connecting the sandbox with the production environment, please contact Antom technical support at least two business days in advance to request configuration. The sandbox environment and production environment require separate configuration.

 Refer to   [Integrate the SDK package for Android](https://docs.antom.com/ac/sdks/android.md)   to complete integration preparations.

## Integration steps {#uQqTl}

 Start your integration by taking the following steps:

 1. (Optional) Preload the SDK
2. Create a payment session
3. Invoke the SDK
4. Obtain the authorization and payment result

### (Optional) Step 1: Preload the SDK **[Client-side]** {#DlLOU}

 Preloading the SDK during the checkout page initialization significantly improves the rendering performance with no negative impact. It is recommended to trigger preloading of the SDK when the buyer selects a payment method.

 Follow the code example below to perform the preloading:   ```java
 AMSEasyPay.preload(getApplicationContext());
```

### Step 2: Create a payment session **[Server-side]** {#kdLDD}

 When a buyer selects a payment method provided by Antom, you need to collect essential information including the payment request ID, order amount, payment method, order description, payment redirect page URL, and payment result notification URL.

 Call the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API to create a payment session and initialize the Antom SDK using the     *paymentSessionData*     value returned in the response.

 The table below lists the parameter specifications for calling the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API during the first and subsequent payments:

 > **[INFO]** **Note**    : For subsequent payments with   [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md)  , simply keep the parameters consistent with the first payment. The buyer can open the   [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md)   webpage and enter the phone number to proceed directly with the payment.

 | **Parameter type** | **Parameter name** | **Required** **(First payment)** | **Required** **(Subsequent payments)** | **Description** |
| --- | --- | --- | --- | --- |
| Base parameter | *productCode* | Yes | Yes | The value is fixed as   `AGREEMENT_PAYMENT`   in the EasySafePay scenario. |
| *productScene* | Yes | Yes | The value is fixed as   `EASY_PAY`   in the EasySafePay scenario. |  |
| *paymentRequestId* | Yes | Yes | The unique ID assigned by a merchant to identify a payment request. |  |
| *paymentMethod.paymentMethodType* | Yes | Yes | The payment method type that is included in   [payment method](https://docs.antom.com/ac/pm/enumeration_values.md)   options. |  |
| *paymentMethod.paymentMethodId* | No | Yes | The unique ID that is used to identify a payment method. T   he value of this parameter is that of     *accessToken*     from the   [**notifyAuthorization**](https://docs.antom.com/ac/ams/notifyauth.md)   API after the first payment. |  |
| *settlementStrategy* | No | No | The settlement strategy for the payment request.    If the merchant agreement supports multiple settlement currencies, they must be specified in the API request. |  |
| *paymentAmount.value* | Yes | Yes | The value of the amount as a positive integer in the smallest currency unit. For details about the smallest currency unit, see   [Smallest unit of the currency](https://docs.antom.com/ac/ref/cc.md#ONkIe)  . |  |
| *paymentAmount.currency* | Yes | Yes | The transaction currency, which is a 3-letter currency code that follows the   [ISO 4217](https://www.iso.org/iso-4217-currency-codes.html)   standard. |  |
| *paymentSessionExpiryTime* | No | No | The specific date and time after which the payment session will expire. The default expiration time is 1 hour after the session creation. The maximum expiration time cannot exceed 1 hour. For example, if the session is created at 2023-7-27T12:00:01+08:30, the session expiration time is 2023-7-27T13:00:01+08:30. |  |
| *paymentRedirectUrl* | Yes | Yes | The merchant page URL that the buyer is redirected to after the payment is completed. The page display according to the server-side result and should not default to a fixed payment success page. When the payment is initiated from an app, pass the scheme URL. |  |
| *paymentNotifyUrl* | No | No | The URL that is used to receive the payment result notification.    it must be an HTTPS URL. This parameter can be omitted if already configured via Antom Dashboard. |  |
| Authorization parameter | *agreementInfo.authState* | Yes | No | The unique ID generated by the merchant to initiate an Easy   Safe   Pay authorization. This parameter is only required during the first payment and is not required for subsequent payments. |
| *agreementInfo.userLoginId* | No | No | The login ID that the buyer used to register in the payment method client. The login ID can be the buyer's email address or phone number.    The specific format requirements are shown in the     *"Common userLoginId formats"*     table below. Providing this parameter can effectively increase payment success rates and reduce buyer drop-off risk. |  |
| Order    parameter | *order.ord*     *erAmount* | Yes | Yes | The order amount of the merchant that directly provides services or goods to the buyer. |
| *order.referenceOrderId* | Yes | Yes | The unique ID to identify the order on the merchant side. |  |
| *order.orderDescription* | Yes | Yes | Summary description of the order. |  |
| *order.buyer*   - *referenceBuyerId*   - *buyerPhoneNo*   - *buyerEmail* | Yes | Yes | Submit buyer information for risk assessment. Provide at least one of these parameters:     *referenceBuyerId*    ,     *buyerPhoneNo*    , or     *buyerEmail*    . |  |

 The parameter format for the buyer's payment account for each payment method is as follows:

 | **Payment method** | **Parameter format** |
| --- | --- |
| [AlipayHK](https://docs.antom.com/ac/antomop/aplusalipayhk.md?platform=auto_debit) | It is recommended to prioritize using a mobile phone number: - Mobile number:     - Hong Kong, China: 852-12****78. The phone number must be 8 digits long, excluding the prefix.   - China: 86-137****5678. The phone number must be 11 digits long, excluding the prefix.   - Email: xxx@xxx.com |
| [DANA](https://docs.antom.com/ac/antomop/DANA.md?platform=auto_debit) | 62-8569****7288. The phone number starts with 8 and is no more than 12 digits long, excluding the prefix. |
| [Alipay](https://docs.antom.com/ac/antomop/alipay_cn.md?platform=auto_debit) [GCash](https://docs.antom.com/ac/antomop/gcash.md?platform=auto_debit) [Touch'n Go eWallet](https://docs.antom.com/ac/antomop/touchngo.md?platform=auto_debit) TrueMoney [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md) | The buyer is authenticated on the payment method side, and no parameters need to be passed in.    *userloginId.* |

 During the first-time payment, passing the buyer's payment account will auto-fill the buyer's account on the payment page, eliminating manual input. Below is a comparison of the user experience with and without these fields:

<!-- TabGroup -->

**Tab: With account parameter passed**

Login account input is not required.

 ![User experience showing the merchant checkout page when the buyer's payment account parameter is passed, where the login account input field is pre-filled and manual input is not required](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/4ec4f8db-a7bc-477d-8dcb-e48523e758f5.png)

**Tab: Without account parameter passed**

Manual input of login account is required.

 ![User experience showing the merchant checkout page when the buyer's payment account parameter is not passed, requiring manual input of the login account](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/25f256b6-e891-4e4a-95ec-862043a4d19a.png)

<!-- /TabGroup -->
 Below are code examples for first and subsequent payments.

<!-- TabGroup -->

**Tab: First payment**

The following sample code shows how to call the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API:

 ```java
@PostMapping("/payment/createSession")
public ResponseEntity<ApiResponse> createPaymentSession(@RequestBody PaymentVO payment) {
    AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
    alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
    alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);

    // replace with paymentRequestId
    String paymentRequestId = UUID.randomUUID().toString();
    alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);

    // convert amount unit(in practice, amount should be calculated on your serverside)
    // For details, please refer to: <a href="https://docs.antom.com/ac/ref/cc">Usage rules of the Amount object</a>
    long amountMinorLong = Money.of(CurrencyUnit.of(payment.currency), new BigDecimal(payment.amountValue)).getAmountMinorLong();

    // set amount
    Amount amount = Amount.builder().currency(payment.currency).value(String.valueOf(amountMinorLong)).build();
    alipayPaymentSessionRequest.setPaymentAmount(amount);

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

    User loginUser = users.get(payment.getUserId());

    // set buyer info
    Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();

    // set paymentMethod
    PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType(payment.paymentMethodType).build();
    if (loginUser.getPaymentMethodTypeAccessToken().containsKey(payment.getPaymentMethodType())) {
        // buyer has authorized
        String accessToken = loginUser.getPaymentMethodTypeAccessToken().get(payment.getPaymentMethodType());
        paymentMethod.setPaymentMethodId(accessToken);
    } else {
        // set agreementInfo
        // replace with your authState
        String authState = UUID.randomUUID().toString();
        AgreementInfo agreementInfo = AgreementInfo.builder().authState(authState).build();
        alipayPaymentSessionRequest.setAgreementInfo(agreementInfo);

        // save the paymentMethodType corresponding to the authState
        authStatePayment.put(authState, payment);

        // The login ID that the user used to register in the payment method client. The login ID can be the user's email address or phone number.
        // Specify this parameter to free users from manually entering their login IDs.
        if(StringUtil.isNotBlank(loginUser.getPhoneNumber()){
            buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
        }
        if(StringUtil.isNotBlank(loginUser.getEmail() && "ALIPAY_HK".equals(payment.getPaymentMethodType())){
            buyer.setBuyerPhoneNo(loginUser.getPhoneNumber());
        }
    }
    alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);

    // replace with your orderId
    String orderId = UUID.randomUUID().toString();
    // set order info
    Order order = Order.builder().referenceOrderId(orderId)
    .orderDescription("antom sdk testing order").orderAmount(amount).buyer(buyer).build();
    alipayPaymentSessionRequest.setOrder(order);

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

    // replace with your redirect URL
    alipayPaymentSessionRequest.setPaymentRedirectUrl(
            "http://localhost:8080/index.html?paymentRequestId=" + paymentRequestId);

    AlipayPaymentSessionResponse alipayPaymentSessionResponse;
    try {
        long startTime = System.currentTimeMillis();
        System.out.println("payment request: " + JSON.toJSONString(alipayPaymentSessionRequest));
        alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
        System.out.println("payment response: " + JSON.toJSONString(alipayPaymentSessionResponse));
        System.out.println("payment request cost time: " + (System.currentTimeMillis() - startTime) + "ms");
    } catch (AlipayApiException e) {
        return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), e));
    }
    return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), alipayPaymentSessionResponse));
}
```

   The following code shows a sample of the request message:

   ```json
{
  "agreementInfo": {
    "authState": "authState001",
    "userLoginId": "userLoginId001"
  },
  "order": {
    "buyer": {
      "referenceBuyerId": "referenceBuyerId001"
    },
    "orderAmount": {
      "currency": "CNY",
      "value": "100"
    },
    "orderDescription": "orderDescription001",
    "referenceOrderId": "referenceOrderId001"
  },
  "paymentAmount": {
    "currency": "CNY",
    "value": "100"
  },
  "paymentMethod": {
    "paymentMethodType": "ALIPAY_CN"
  },
  "paymentNotifyUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/record/notify?env=main_online&paymentMethodType=ALIPAY_CN",
  "paymentRedirectUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/result",
  "paymentRequestId": "paymentRequestId001",
  "productCode": "AGREEMENT_PAYMENT",
  "productScene": "EASY_PAY",
  "settlementStrategy": {
    "settlementCurrency": "USD"
  }
}
```

   The following code shows a sample of the response message:

 ```json
{
    "paymentSessionData": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3cjK3CVpnMXY7BfQlIvwNqQWtXHEMUo0R5pQwnSyNtxTA==&&SG&&188&&eyJh***",
    "paymentSessionExpiryTime": "2024-09-27T15:57:30+08:00",
    "paymentSessionId": "ZqeGpu7pbMb/I3dNWTTEL3o4w5mXh20j13VnmsE1p3fI21eGbgq240lFVquZsLrM",
    "result": {
        "resultCode": "SUCCESS",
        "resultMessage": "success.",
        "resultStatus": "S"
    }
}
```

 Please take the next step according to the value of the     *result.resultStatus*    .

 | ***resultStatus*** | **Message** | **Further actions** |
| --- | --- | --- |
| `S` | The payment session is successfully created. | Return the obtained     *paymentSessionData*     to the merchant's frontend. For specific operational steps, refer to   [Step 4](#O3ijB)  . |
| `F` | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
| `U` | The payment session creation failed due to unknown reasons. | Replace the     *paymentRequestId*     and     *authstate*     value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |

 > **[INFO]** **Note**    : If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new     *paymentRequestId*     and     *authstate*     value.

**Tab: Subsequent payments**

The following sample code shows how to call the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API:

 ```java
public static void createPaymentSession() {
  AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
  alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
  alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);

  // replace with your paymentRequestId
  String paymentRequestId = UUID.randomUUID().toString();
  alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);

  // set amount
  // you should convert amount unit(in practice, amount should be calculated on your server side)
  Amount amount = Amount.builder().currency("HKD").value("98080").build();
  alipayPaymentSessionRequest.setPaymentAmount(amount);

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

  // set paymentMethod
  PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType("ALIPAY_HK")
  .paymentMethodId("28288803001319861727421828000Cv96OFlYoi17100****").build();
  alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);

  // set buyer info
  Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();

  // replace with your orderId
  String orderId = UUID.randomUUID().toString();
  // set order Info
  Order order = Order.builder().referenceOrderId(orderId).
  orderDescription("antom api testing order").orderAmount(amount).buyer(buyer).build();
  alipayPaymentSessionRequest.setOrder(order);

  // replace with your notify url
  alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com");

  // replace with your redirect url
  alipayPaymentSessionRequest.setPaymentRedirectUrl("http://www.yourRedirectUrl.com");

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

```

   The following code shows a sample of the request message:

   ```json
{
    "order": {
        "buyer": {
            "referenceBuyerId": "yourBuyerId"
        },
        "orderAmount": {
            "currency": "HKD",
            "value": "98080"
        },
        "orderDescription": "antom api testing order",
        "referenceOrderId": "5e445b58-49ad-4552-a36d-d38f311a090d"
    },
    "paymentAmount": {
        "currency": "HKD",
        "value": "98080"
    },
    "paymentMethod": {
        "paymentMethodId": "28288803001319861727421828000Cv96OFlYoi17100****",
        "paymentMethodType": "ALIPAY_HK"
    },
    "paymentNotifyUrl": "http://www.yourNotifyUrl.com",
    "paymentRedirectUrl": "http://www.yourRedirectUrl.com",
    "paymentRequestId": "5810a84e-3a3e-4e47-bbac-9dfe3f2dd2b3",
    "productCode": "AGREEMENT_PAYMENT",
    "productScene": "EASY_PAY",
    "settlementStrategy": {
        "settlementCurrency": "USD"
    }
}
```

   The following code shows a sample of the response message:

   ```json
 {
  "paymentSessionData": "paymentSessionData****",
  "paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
  "paymentSessionId": "paymentSessionId****",
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": "success.",
    "resultStatus": "S"
  }
}
```

 Please take the next step according to the value of the     *result.resultStatus*    .

 | ***resultStatus*** | **Message** | **Further actions** |
| --- | --- | --- |
| `S` | The payment session is successfully created. | Return the obtained     *paymentSessionData*     to the merchant's frontend. For specific operational steps, refer to   [Step 4](#O3ijB)  . |
| `F` | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
| `U` | The payment session creation failed due to unknown reasons. | Replace the     *paymentRequestId*     value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |

 > **[INFO]** **Note**    : If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new     *paymentRequestId*     value.

<!-- /TabGroup -->
 ---

 > **[INFO]** **Common questions**
>
>  **Q: Can I use Chinese characters in the value of the request parameters?**
>
>  A: To avoid incompatibility of a certain payment method, do not use Chinese characters for parameters in the request.
>
>   **Q: How to set the URL to receive the payment notification?**
>
>  A: Specify     *paymentNotifyUrl*     in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)        API to receive the asynchronous notification about the payment result (  [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)  ), or configure the receiving URL in Antom Dashboard. If the URL is specified in both the request and Antom Dashboard, the value specified in the request takes precedence.
>
>   **Q: What is the difference between**       ***paymentAmount***       **and**       ***orderAmount***      **?**  
>  A:     *paymentAmount*     refers to the payment amount, while     *orderAmount*     refers to the order amount. The actual charged amount is determined by     *paymentAmount*    .
>
>   **Q: What does**       ***paymentSessionExpiryTime***       **specifically refer to in payment requests?**  
>  A:     *paymentSessionExpiryTime*     indicates the validity period from successful payment session creation until the buyer submits the payment. After submission, the payment processing timeout is 10 minutes. Therefore, the maximum total duration from session creation to payment completion is 1 hour and 10 minutes.
>
>   **Q: Which parameters should be prioritized in the response message?**  
>  A:    Pay attention to the following key parameters:
>
>  - *result.resultStatus*    :    Indicates the result of the API call   .
> - *paymentSessionData*    :    Encrypted payment session data, which is passed to the frontend for initializing the Antom SDK.
> - *paymentSessionExpiryTime*    : Expiration timestamp of the payment session.

### Step 3: Invoke the SDK   **[Client-side]** {#Fv7YU}

 After obtaining the     *paymentSessionData*     value on the merchant server side, the merchant client can invoke the SDK to redirect the checkout page to the payment method authorization page. When the buyer submits a payment request, the SDK will automatically handle encrypted communication, risk control verification, page redirection, and payment instruction execution, enabling an end-to-end payment authorization process.

#### 1\. Instantiate the SDK {#Npugo}

 1. Use   `AMSEasyPayConfiguration`  to create the SDK instance. The configuration object includes the following parameters:

 | **Parameter name** | **Required** | **Description** |
| --- | --- | --- |
| *setLocale* | No | Used to specify the language information. Select the appropriate value based on the region of the payment method. Valid values for this parameter are listed as follows.   If a value not in the following list is used, the local language is used instead. - `"en", "US"`  : English - `"in", "ID"`  : Indonesian - `"ms", "MY"`  : Malay - `"tl", "PH"`  : Filipino - `"ko", "KR"`  : Korean - `"zh", "CN"`  : Simplified Chinese - `"zh", "HK"`  : Traditional Chinese |
| *setOption* | No | Used to specify whether to use the sandbox environment, the window alignment mode, and the redirection after the payment is complete. Valid values are: - `"sandbox", "true"`  : Sandbox environment - `"sandbox", "false"`  : Production environment - `"windowGravity","LANDSCAPE_CENTER"`  : Center the window in landscape mode. - `"windowGravity","LANDSCAPE_RIGHT"`  : Align the window to the right in landscape mode. - `"notRedirectAfterComplete", "false"`  : Optional, Boolean type. The default value is   `false`   , indicates that redirection to your page takes place after the payment is complete. The same applies when the value is empty. When the value is   `true`  , redirection will not take place after the payment is complete. You need to use the customer event code to control the payment and complete the subsequent process.   > **[INFO]** **Note**    : - This parameter applies only to scenarios where the payment is completed within the SDK. > - The result and event codes returned by the client-side are only used as a reference for the redirection operation of the client page. For transaction status updates, refer to the results returned by the server's   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   or   [**inquirePayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API. |

 2. Create an instance of the     **setOnCheckoutListener**     API to handle corresponding events that occur in subsequent processes, which include the following method:

 | **Method** | **Required** | **Description** |
| --- | --- | --- |
| `onEventCallback` | No | A callback function that monitors payment events on the checkout page, returning     *eventCode*     and     *eventResult*    . The payment success result will not be returned by this callback function by default. A redirection to the payment success result page that you specified will take place instead. However, when     *notRedirectAfterComplete*     is set to   `true`  , the system will not perform redirection upon payment completion, instead it will provide event callback. > **[INFO]** **Note**    : When integrating with Alipay, you will receive the payment event codes returned by   `onEventCallback`  . |

 The following sample code shows how to instantiate the SDK:

 ```java
// Step 1: Create the AMSEasyPayConfiguration type.
AMSEasyPayConfiguration configuration = new AMSEasyPayConfiguration();
configuration.setLocale(new Locale("en", "US"));
// Set the sandbox environment. If you leave it empty, the production environment is used by default.
configuration.setOption("sandbox", "true");
// Set as false by default
configuration.setOption("notRedirectAfterComplete", "false");
// Set the callback to monitor payment events on the checkout page.
configuration.setOnCheckoutListener(new OnCheckoutListener() {
    @Override
    public void onEventCallback(String eventCode, AMSEventResult eventResult) {
        // For eventCode, refer to the respective sample codes or event codes.
        Toast.makeText(activity, "eventCode=" + eventCode + " message=" + message, Toast.LENGTH_SHORT).show();
    }
});

// Instantiate AMSEasyPay.
AMSEasyPay checkout = new AMSEasyPay.Builder(activity, configuration).build();

```

 The following image shows the rendering effect of the merchant checkout page invoking a half-screen pop-up or redirecting to the digital wallet app:

 ![Mobile user experience showing the merchant checkout page launching a half-screen pop-up or redirecting to the digital wallet app for payment authorization](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/00bb75ea-3cc4-4c04-a0a9-d8a1bf38f8c3.png)

 3. Use the   `createComponent`   method in the instance object to create a payment component, which includes the following parameter:

 | **Parameter name** | **Required** | **Description** |
| --- | --- | --- |
| *sessionData* | Yes | Create a configuration object using the     *sessionData*     parameter: Use the complete data of the value of     *paymentSessionData*     obtained in the response of the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API as the value of this parameter. |

 The sample code is as follows:

 ```java
checkout.createComponent(activity, sessionData);
```

#### 2\. Handle SDK callback event codes {#B1qMs}

 Below are the event codes returned by   `onEventCallback`   and handling recommendations:

 > **[INFO]** **Note**    : In the Android Native environment, Alipay only supports redirecting to the merchant app's launch page, rather than the     *paymentRedirectUrl*     specified in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API. The specific redirect page needs to be controlled through the event code.

 | **Type** | **Code** | **Description** | **Further action** |
| --- | --- | --- | --- |
| Status code | SDK_CALL_URL_SUCCESS | This event code indicates that redirect successfully for the     *paymentRedirectUrl.* | Please obtain the final payment result from Antom server. You can use the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)      API or the   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   API to confirm the result. |
| SDK_PAYMENT_CANCEL | The buyer canceled the payment (the buyer exited the payment page without submitting the order). | You can re-invoke the SDK using    *paymentSessionData*    within its validity period; if it has expired, you need to initiate a new   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API. |  |
| SDK_PAYMENT_SUCCESSFUL | Indicates that the wallet has successfully processed the payment. | Please obtain the final payment result from Antom server. You can use the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)       API or the   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   API to confirm the result. > **[INFO]** **Note**    : For payment solutions not integrated with Alipay, suggest redirecting users to the payment result page. |  |
| SDK_PAYMENT_FAIL | Indicates that the wallet failed to process the payment. | Please obtain the final payment result from Antom server. You can use the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)      API or the   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   API to confirm the result. > **[INFO]** **Note**    : For payment solutions not integrated with Alipay, suggest redirecting users to the payment result page. |  |
| SDK_PAYMENT_PROCESSING (Returned when integrated with Alipay) | Indicates that the payment status of the   Alipay wallet   is unknown. | Please obtain the final payment result from Antom server. You can use the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)      API or the   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   API to confirm the result. |  |
| SDK_PAYMENT_ERROR (Returned when integrated with Alipay) | Indicates that the payment processing of the Alipay wallet is abnormal. | Please obtain the final payment result from Antom server. You can use the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)      API or the   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   API to confirm the result. |  |
| Error code ​ | SDK_INTERNAL_ERROR | SDK internal error. | Contact Antom Technical Support. |
| SDK_CREATEPAYMENT_PARAMETER_ERROR | The parameters passed to the `createComponent`   method are not correct. | Check if the parameters are correct and re-initialize the component. |  |
| SDK_STATUS_ERROR | This event code indicates one of the following situations:   ​ - You just call   `createComponent`   when it is still in previous payment flow. - You just call   `createComponent`   without init. - You just call   `createComponent`   when another Popup is active. | Please check the result message, then match the error    situations. |  |
| SDK_INTEGRATION_ERROR | This event code indicates that    some dependencies of SDK is not exist. Currently there are two scenario: - Security SDK is not exist. - Open security browser failed. | Please check whether target module has been integrated. |  |
| SDK_LAUNCH_PAYMENT_APP_ERROR | This event code indicates one of the following situations: - Failed to invoke the app of the buyer's selected payment method or failed to redirect to the checkout page of the payment method. - Failed to redirect to the merchant page. - The     *paymentRedirectUrl*     parameter is not correctly passed when calling the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API. | Check whether the     *paymentRedirectUrl*     parameter is correctly passed when calling the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API. If frequent redirection exceptions occur, contact Antom Technical Support to troubleshoot redirection or cross-application calling issues. |  |

 The following sample code shows how to handle the callback function:

 ```java
configuration.setOnCheckoutListener(new OnCheckoutListener() {
            @Override
            public void onEventCallback(String eventCode, AMSEventResult eventResult) {
                if (selectPayment != null && selectPayment.getPaymentMethodCode().equals("ALIPAY_CN")) {
                    switch (eventCode) {
                        case "SDK_PAYMENT_CANCEL":
                            AlertUtils.showAlertWithMessage(MainActivity.this, "The buyer canceled the payment (the buyer exited the payment page without submitting the order). You can re-invoke the SDK using paymentSessionData within its validity period; If it has expired, you need to initiate a new createPaymentSession (EasySafePay) request.");
                            break;
                        case "SDK_PAYMENT_SUCCESSFUL":
                            AlertUtils.showAlertWithMessage(MainActivity.this, "The Alipay wallet has successfully processed the payment. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result.");
                            break;
                        case "SDK_PAYMENT_FAIL":
                            AlertUtils.showAlertWithMessage(MainActivity.this, "The Alipay wallet failed to process the payment. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result.");
                            break;
                        case "SDK_PAYMENT_PROCESSING":
                            AlertUtils.showAlertWithMessage(MainActivity.this, "The payment status of the Alipay wallet is unknown. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result.");
                            break;
                        case "SDK_PAYMENT_ERROR":
                            AlertUtils.showAlertWithMessage(MainActivity.this, "The payment processing of the Alipay wallet is abnormal. Please obtain the final payment result from Antom server. You can use the inquiryPayment API or the notifyPayment API to confirm the result.");
                            break;
                        default:
                            AlertUtils.showAlertWithMessage(MainActivity.this, "eventCode=" + eventCode + " message=" + eventResult.getMessage());
                            break;
                    }
                } else {
                    // Please note that payment success will not be notified from this callback function, but rather the page will be redirected to the success result page you specified
                    switch (eventCode) {
                        case "SDK_PAYMENT_CANCEL":
                            AlertUtils.showAlertWithMessage(MainActivity.this, "The buyer canceled the payment (the buyer exited the payment page without submitting the order). You can re-invoke the SDK using paymentSessionData within its validity period; If it has expired, you need to initiate a new createPaymentSession (EasySafePay) request.");
                            break;
                        case "SDK_CALL_URL_SUCCESS":
                            AlertUtils.showAlertWithMessage(MainActivity.this, "Open wallet app or redirect to the merchant page successfully.");
                            break;
                        case "SDK_LAUNCH_PAYMENT_APP_ERROR":
                            AlertUtils.showAlertWithMessage(MainActivity.this, "Open wallet app or redirect to the merchant page failed");
                            break;
                        case "SDK_CREATEPAYMENT_PARAMETER_ERROR":
                            AlertUtils.showAlertWithMessage(MainActivity.this, "The input parameter provided is invalid. Please check the value and try again.");
                            break;
                        default:
                            AlertUtils.showAlertWithMessage(MainActivity.this, "eventCode=" + eventCode + " message=" + eventResult.getMessage());
                            break;
                    }
                }

            }
        });

```

#### 3\. Free SDK component resources {#Mq8pz}

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

 - When the buyer exits the checkout page,    completely    free the component resources created in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API.
- When the buyer initiates multiple payments, and the parameters in   `AMSEasyPayConfiguration`   have changed, free the component resources created in the previous   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API.

 In the following scenario, you do not need to call   `onDestroy`  , and the SDK will automatically free partial resources (for SDK 1.33.0 or above).

 - When the buyer initiates multiple payments, and the parameters in   `AMSEasyPayConfiguration`   have not changed. The SDK will automatically free partial resources after the payment is completed to reset to the state before   `createComponent`      was called   .

 The following sample code shows how to free components:

 ```java
// Completely free SDK component resources
checkout.onDestroy();
```

 > **[INFO]** **Common questions**
>
>  **Q: Is it mandatory to handle SDK callback events?**  
>  A: For Alipay, you must process event codes to display payment results, but this payment method is optional. Callback events can also be used for logging.
>
>  ​
>
>  **Q: Can an**       ***AMSEasypay***       **instance execute**       ***createComponent***       **multiple times?**  
>  A: No. You need to create a fresh    *AMSEasypay*     instance to initiate a new payment.
>
>  ​
>
>  **Q: Are SDK calls required for both first-time and subsequent payments?**  
>    A: Yes.

**Tab: WebView**

## User experience {#KPRit}

 The following screenshots show the user experience of wallet and bank transfer respectively:

<!-- TabGroup -->

**Tab: Digital wallet**

In the digital wallet payment scenario, the system will guide the buyer to complete the transaction on the merchant's page or within the payment method app after the buyer confirms the payment. The first payment verification and subsequent simplified payment process are illustrated as follows:

<!-- TabGroup -->

**Tab: First payment**

The first payment requires security authentication. Once authorized, the buyer will be enabled for password-free payments on subsequent transactions.

<!-- TabGroup -->

**Tab: Pay on the merchant page**

![Mobile user experience showing the digital wallet first payment flow where buyers complete security authentication to enable password-free payments for subsequent transactions on the merchant page](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/4ec4f8db-a7bc-477d-8dcb-e48523e758f5.png)

**Tab: Pay on the payment method app**

![Mobile user experience showing the digital wallet first payment flow where buyers complete security authentication to enable password-free payments for subsequent transactions on the payment method app](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/8a4e89b8-83ec-422f-be27-92ac906ff8b0.png)

<!-- /TabGroup -->

**Tab: Subsequent payments**

Subsequent payments are processed without requiring a password upon order submission.

 ![Mobile user experience showing digital wallet subsequent payment processed automatically without password upon order submission](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/81577803-6cd0-4a1b-99d7-42f59e1541ce.png)

<!-- /TabGroup -->

**Tab: Online banking**

Below is the user experience for first and subsequent payments using online banking payment methods.

<!-- TabGroup -->

**Tab: First payment**

For the first payment, the buyer completes the payment authorization process to enable subsequent password-free payments.

 ![Mobile user experience showing the online banking first payment authorization process where the buyer completes authentication to enable subsequent password-free payments](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/3bf28a06-38e5-4769-81e2-8df0ba7f954d.png)

**Tab: Subsequent payments**

Subsequent payments are processed without requiring a password upon order submission.

 ![Mobile user experience showing the online banking subsequent payment automatically processed without password upon order submission](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2025/png/46fa1460-f168-4f3f-a335-a46ad1a911ec.png)

<!-- /TabGroup -->

<!-- /TabGroup -->

## Payment flow {#cNSbC}

 The following are flow chart for the first payment and subsequent payment:

<!-- TabGroup -->

**Tab: First payment**

![Sequence diagram illustrating the EasySafePay first payment flow among Buyer, Merchant Client, Merchant Server, and Antom: the buyer enters the checkout page, the merchant creates a payment session via the createPaymentSession API, the client SDK renders the payment interface and manages redirections, the buyer completes authorization, and the merchant receives asynchronous notifyAuthorization and notifyPayment notifications or queries payment status through the inquiryPayment API](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2026/png/160afc21-bdad-4d68-b1bc-7d03b9446910.png) 1. **The buyer enters the checkout page.**
2. **Preload the Antom SDK when the buyer chooses a payment method.**
3. **Create a payment session request.**  
 After the buyer submits the order, you can obtain the payment session by calling the  [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API.
4. **Invoke the client SDK.**  
   Invoke the SDK using a payment session on the client side and the SDK will automatically collect payment elements, Display the payment page, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics.
5. **Obtain the authorization result.**  
 When the authorization is successful, Antom sends you the asynchronous notification through the  [**notifyAuthorization**](https://docs.antom.com/ac/ams/notifyauth.md)   API.
6. **Obtain the payment result.**  
   Obtain the payment result using one of the following methods:

   - Asynchronous notification: Specify     *paymentNotifyUrl*     in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)        to send asynchronous notifications to you.
  - Synchronous inquiry: Call the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API to check the real-time payment status.

**Tab: Subsequent payments**

![Sequence diagram illustrating the EasySafePay subsequent payment flow among Buyer, Merchant Client, Merchant Server, and Antom: the buyer enters the checkout page, the merchant creates a payment session using the previously authorized paymentMethodId via the createPaymentSession API, the client SDK renders the payment interface, the buyer submits the order, and the merchant receives an asynchronous notifyPayment notification or uses the inquiryPayment API to check payment status](https://idocs-assets.marmot-cloud.com/storage/idocs87c36dc8dac653c1/yuque/idocs/2026/png/2bb139a0-edcb-4231-b1bc-1648705fa193.png) 1. **The buyer enters the checkout page.**
2. **Preload the Antom SDK when the buyer chooses a payment method.**
3. **Create a payment session request.**  
 After the buyer submits the order, you can obtain the payment session by calling the  [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API.
4. **Invoke the client SDK.**  
 Invoke the SDK using a payment session on the client side and the SDK will automatically collect payment elements, Display the payment page, handle page redirections, and guide buyers through payment completion based on the specific payment method's characteristics.
5. **Obtain the payment result.**  
   Obtain the payment result using one of the following methods:

   - Asynchronous notification: Specify     *paymentNotifyUrl*     in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API to set the address for receiving asynchronous notifications. When the payment is successful or expires, Antom will use   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)        to send asynchronous notifications to you.
  - Synchronous inquiry: Call the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API to check the real-time payment status.

<!-- /TabGroup -->

## Integration preparations {#M6SQk}

 Before you start integrating, read the   [Integration Guide](https://docs.antom.com/integration_guide_en.md)   and   [API Overview](https://docs.antom.com/ac/ams/api_fund.md)   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](https://docs.antom.com/ac/sdks/server_sdks.md)  .
- If you need to conduct joint debugging by connecting the sandbox with the production environment, please contact Antom technical support at least two business days in advance to request configuration. The sandbox environment and production environment require separate configuration.

 Version Requirements

 - iOS:

   - Install Xcode 12 or later.
  - Compatible with iOS 11 or later.

 - Android:

   - Compatible with Android 4.4 (API level 19) or later.

 > **[INFO]** **Note**    : Flutter and React Native (RN) development frameworks are not currently supported.

 Refer to   [Integrate the SDK package for Web/WAP](https://docs.antom.com/ac/sdks/web.md)      to complete integration preparations.

## Integration steps {#UR3c3}

 Start your integration by taking the following steps:

 1. (Optional) Preload the SDK
2. Create a payment session
3. Invoke the SDK
4. Obtain the authorization and payment result

### (Optional) Step 1: Preload the SDK **[Client-side]** {#BNfQ0}

 Preloading the SDK during the checkout page initialization significantly improves the rendering performance with no negative impact. It is recommended to trigger preloading of the SDK when the buyer selects a payment method.

 Follow the code example below to perform the preloading:

 ```javascript
AMSEasypay.preload();
```

### Step 2: Create a payment session **[Server-side]** {#jVo9J}

 Call the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API to create a payment session and initialize the Antom SDK using the     *paymentSessionData*     value returned in the response.

 The table below lists the parameter specifications for calling the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API during the first and subsequent payments:

 > **[INFO]** **Note**    : For subsequent payments with   [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md)  , simply keep the parameters consistent with the first payment. The buyer can open the   [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md)   webpage and enter the phone number to proceed directly with the payment.

 | **Parameter type** | **Parameter name** | **Required** **(First-time payment)** | **Required** **(Subsequent payments)** | **Description** |
| --- | --- | --- | --- | --- |
| Base parameter | *productCode* | Yes | Yes | The value is fixed as   `AGREEMENT_PAYMENT`   in the EasySafePay scenario. |
| *productScene* | Yes | Yes | The value is fixed as   `EASY_PAY`   in the EasySafePay scenario. |  |
| *paymentRequestId* | Yes | Yes | The unique ID assigned by a merchant to identify a payment request. |  |
| *paymentMethod.paymentMethodType* | Yes | Yes | The payment method type that is included in   [payment method](https://docs.antom.com/ac/pm/enumeration_values.md)   options. |  |
| *paymentMethod.paymentMethodId* | No | Yes | The unique ID that is used to identify a payment method. T   he value of this parameter is that of     *accessToken*     from the   [**notifyAuthorization**](https://docs.antom.com/ac/ams/notifyauth.md)   API. |  |
| *settlementStrategy* | No | No | The settlement strategy for the payment request.    If the merchant agreement supports multiple settlement currencies, they must be specified in the API request. |  |
| *paymentAmount.value* | Yes | Yes | The value of the amount as a positive integer in the smallest currency unit. For details about the smallest currency unit, see   [Smallest unit of the currency](https://docs.antom.com/ac/ref/cc.md#ONkIe)   . |  |
| *paymentAmount.currency* | Yes | Yes | The transaction currency, which is a 3-letter currency code that follows the   [ISO 4217](https://www.iso.org/iso-4217-currency-codes.html)   standard. |  |
| *paymentSessionExpiryTime* | No | No | The specific date and time after which the payment session will expire. The default expiration time is 1 hour after the session creation. For example, if the session is created at 2023-7-27T12:00:01+08:30, the session expiration time is 2023-7-27T13:00:01+08:30. |  |
| *paymentRedirectUrl* | Yes | Yes | The merchant page URL that the user is redirected to after the payment is completed. The page display according to the server-side result and should not default to a fixed payment success page. - If the payment is initiated from a Web or WAP platform, pass the WAP URL. - If the payment is initiated from an App, pass the scheme URL. |  |
| *paymentNotifyUrl* | No | No | The URL that is used to receive the payment result notification.    it must be an HTTPS URL. This field can be omitted if already configured via Antom Dashboard. |  |
| Authorization parameter | *agreementInfo.authState* | Yes | No | The unique ID generated by the merchant to initiate an Easy   Safe   Pay authorization. |
| Order    parameter | *order.ord*     *erAmount* | Yes | Yes | The order amount of the merchant that directly provides services or goods to the customer |
| *order.referenceOrderId* | Yes | Yes | The unique ID to identify the order on the merchant side. |  |
| *order.orderDescription* | Yes | Yes | Summary description of the order. |  |
| *order.buyer.referenceBuyerId* | No | No | Submit buyer information for risk assessment. Provide at least one of these fields:     *referenceBuyerId*    ,     *buyerPhoneNo*    , or     *buyerEmail*    . |  |
|  | *order.buyer.*   - *buyerPhoneNo*   - *buyerEmail* | No | No | Buyer's account. Providing relevant payment account information can effectively improve the payment success rate and reduce the risk of buyer attrition. Please refer to the table below for specific format requirements. |

 The parameter format for the buyer's payment account for each payment method is as follows:

 | **Payment method** | **Parameter format** |
| --- | --- |
| [AlipayHK](https://docs.antom.com/ac/antomop/aplusalipayhk.md?platform=auto_debit) | It is recommended to prioritize using a mobile phone number: - Mobile number:     - Hong Kong, China: 852-12****78. The phone number must be 8 digits long, excluding the prefix.   - China: 86-137****5678. The phone number must be 11 digits long, excluding the prefix.   - Email: xxx@xxx.com |
| [DANA](https://docs.antom.com/ac/antomop/DANA.md?platform=auto_debit) | 62-8569****7288. The phone number starts with 8 and is no more than 12 digits long, excluding the prefix. |
| [Alipay](https://docs.antom.com/ac/antomop/alipay_cn.md?platform=auto_debit) [GCash](https://docs.antom.com/ac/antomop/gcash.md?platform=auto_debit) [Touch'n Go eWallet](https://docs.antom.com/ac/antomop/touchngo.md?platform=auto_debit) TrueMoney [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md) | The buyer is authenticated on the payment method side, and no parameters need to be passed in.    *userloginId.* |

 Below are code examples for first and subsequent payments.

<!-- TabGroup -->

**Tab: First payment**

The following sample code shows how to call the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API:

 ```javascript
@PostMapping("/payment/createSession")
public ResponseEntity<ApiResponse> createPaymentSession(@RequestBody PaymentVO payment) {
    AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
    alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
    alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);

    // replace with your paymentRequestId
    String paymentRequestId = UUID.randomUUID().toString();
    alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);

    // convert amount unit (in practice, amount should be calculated on your serverside)
    // For details, please refer to: <a href="https://docs.antom.com/ac/ref/cc">Usage rules of the Amount object</a>
    long amountMinorLong = Money.of(CurrencyUnit.of(payment.currency), new BigDecimal(payment.amountValue)).getAmountMinorLong();

    // set amount
    Amount amount = Amount.builder().currency(payment.currency).value(String.valueOf(amountMinorLong)).build();
    alipayPaymentSessionRequest.setPaymentAmount(amount);

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

    User loginUser = users.get(payment.getUserId());

    // set paymentMethod
    PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType(payment.paymentMethodType).build();
    if(loginUser.getPaymentMethodTypeAccessToken().containsKey(payment.getPaymentMethodType())){
        // user has authorized
        String accessToken = loginUser.getPaymentMethodTypeAccessToken().get(payment.getPaymentMethodType());
        paymentMethod.setPaymentMethodId(accessToken);
    }else{
        // set agreementInfo
        // replace with your authState
        String authState = UUID.randomUUID().toString();
        // The login ID that the user used to register in the payment method client. The login ID can be the user's email address or phone number.
        // Specify this parameter to free users from manually entering their login IDs
        String userLoginId = loginUser.getPhoneNumber();
        AgreementInfo agreementInfo = AgreementInfo.builder().authState(authState).userLoginId(userLoginId).build();
        alipayPaymentSessionRequest.setAgreementInfo(agreementInfo);

        // save the paymentMethodType corresponding to the authState
        authStatePayment.put(authState, payment);
    }
    alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);

    // set buyer info
    Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();

    // replace with your orderId
    String orderId = UUID.randomUUID().toString();
    // set order info
    Order order = Order.builder().referenceOrderId(orderId).
    orderDescription("antom sdk testing order").orderAmount(amount).buyer(buyer).build();
    alipayPaymentSessionRequest.setOrder(order);

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

    // replace with your redirect url
    alipayPaymentSessionRequest.setPaymentRedirectUrl(
            "http://localhost:8080/index.html?paymentRequestId=" + paymentRequestId);

    AlipayPaymentSessionResponse alipayPaymentSessionResponse;
    try {
        long startTime = System.currentTimeMillis();
        System.out.println("payment request: " + JSON.toJSONString(alipayPaymentSessionRequest));
        alipayPaymentSessionResponse = CLIENT.execute(alipayPaymentSessionRequest);
        System.out.println("payment response: " + JSON.toJSONString(alipayPaymentSessionResponse));
        System.out.println("payment request cost time: " + (System.currentTimeMillis() - startTime) + "ms
");
    } catch (AlipayApiException e) {
        return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), e));
    }
    return ResponseEntity.ok().body(new ApiResponse(paymentRequestId, payment.getUserId(), alipayPaymentSessionResponse));
}
```

 The following code shows a sample of the request message:

 ```json
{
  "agreementInfo": {
    "authState": "authState001",
    "userLoginId": "userLoginId****"
  },
  "order": {
    "buyer": {
      "referenceBuyerId": "referenceBuyerId****"
    },
    "orderAmount": {
      "currency": "CNY",
      "value": "100"
    },
    "orderDescription": "orderDescription001",
    "referenceOrderId": "referenceOrderId****"
  },
  "paymentAmount": {
    "currency": "CNY",
    "value": "100"
  },
  "paymentMethod": {
    "paymentMethodType": "ALIPAY_CN"
  },
  "paymentNotifyUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/record/notify?env=main_online&paymentMethodType=ALIPAY_CN",
  "paymentRedirectUrl": "http://debug1688017773824.test.alipay.net:9090/amsdemo/result",
  "paymentRequestId": "paymentRequestId****",
  "productCode": "AGREEMENT_PAYMENT",
  "productScene": "EASY_PAY",
  "settlementStrategy": {
    "settlementCurrency": "USD"
  }
}
```

 The following code shows a sample of the response message, including the following key parameters:

 - *paymentSessionData*    : Encrypted payment session data. This data is passed to the frontend for invoking the Antom SDK.
- *paymentSessionExpiryTime*    : Expiration time of the payment session.

 ```json
{
  "paymentSessionData": "paymentSessionData****",
  "paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
  "paymentSessionId": "paymentSessionId****",
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": "success.",
    "resultStatus": "S"
  }
}
```

 Please take the next step according to the value of the     *result.resultStatus*    .

 | ***resultStatus*** | **Message** | **Further actions** |
| --- | --- | --- |
| `S` | The payment session is successfully created. | Return the obtained     *paymentSessionData*     to the merchant's frontend. |
| `F` | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
| `U` | The payment session creation failed due to unknown reasons. | Replace the     *paymentRequestId*     and     *authstate*     value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |

 > **[INFO]** **Note**    : If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new     *paymentRequestId*     and     *authstate*     value.

**Tab: Subsequent payments**

The following sample code shows how to call the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API:

 ```javascript
public static void createPaymentSession() {
    AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
    alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
    alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);

    // replace with your paymentRequestId
    String paymentRequestId = UUID.randomUUID().toString();
    alipayPaymentSessionRequest.setPaymentRequestId(paymentRequestId);

    // set amount
  // you should convert amount unit (in practice, amount should be calculated on your server side)
    Amount amount = Amount.builder().currency("HKD").value("98080").build();
    alipayPaymentSessionRequest.setPaymentAmount(amount);

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

    // set paymentMethod
    PaymentMethod paymentMethod = PaymentMethod.builder().paymentMethodType("ALIPAY_HK")
    .paymentMethodId("28288803001319861727421828000Cv96OFlYoi17100****").build();
    alipayPaymentSessionRequest.setPaymentMethod(paymentMethod);

    // set buyer info
    Buyer buyer = Buyer.builder().referenceBuyerId("yourBuyerId").build();

    // replace with your orderId
    String orderId = UUID.randomUUID().toString();
    // set order Info
    Order order = Order.builder().referenceOrderId(orderId).
    orderDescription("antom api testing order").orderAmount(amount).buyer(buyer).build();
    alipayPaymentSessionRequest.setOrder(order);

    // replace with your notify url
    alipayPaymentSessionRequest.setPaymentNotifyUrl("http://www.yourNotifyUrl.com");

    // replace with your redirect url
    alipayPaymentSessionRequest.setPaymentRedirectUrl("http://www.yourRedirectUrl.com");

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

 The following code shows a sample of the request message:

 ```json
{
  "order": {
    "buyer": {
      "referenceBuyerId": "yourBuyerId"
    },
    "orderAmount": {
      "currency": "HKD",
      "value": "98080"
    },
    "orderDescription": "antom api testing order",
    "referenceOrderId": "5e445b58-49ad-4552-a36d-d38f311****"
  },
  "paymentAmount": {
    "currency": "HKD",
    "value": "98080"
  },
  "paymentMethod": {
    "paymentMethodId": "28288803001319861727421828000Cv96OFlYoi17100****",
    "paymentMethodType": "ALIPAY_HK"
  },
  "paymentNotifyUrl": "http://www.yourNotifyUrl.com",
  "paymentRedirectUrl": "http://www.yourRedirectUrl.com",
  "paymentRequestId": "5810a84e-3a3e-4e47-bbac-9dfe3f2d****",
  "productCode": "AGREEMENT_PAYMENT",
  "productScene": "EASY_PAY",
  "settlementStrategy": {
    "settlementCurrency": "USD"
  }
}
```

 The following code shows a sample of the response message, including the following key parameters:

 - *paymentSessionData*    : Encrypted payment session data. This data is passed to the frontend for invoking the Antom SDK.
- *paymentSessionExpiryTime*    : Expiration time of the payment session.

 ```json
{
  "paymentSessionData": "paymentSessionData****",
  "paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
  "paymentSessionId": "paymentSessionId****",
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": "success.",
    "resultStatus": "S"
  }
}
```

 Please take the next step according to the value of the     *result.resultStatus*    .

 | ***resultStatus*** | **Message** | **Further actions** |
| --- | --- | --- |
| `S` | The payment session is successfully created. | Return the obtained     *paymentSessionData*     to the merchant's frontend. |
| `F` | The payment session creation failed. | Check and verify whether the required request parameters (including the header parameters and body parameters) of the current API are correctly passed and valid. |
| `U` | The payment session creation failed due to unknown reasons. | Replace the     *paymentRequestId*     value, then retry the API call to resolve the issue. If the problem persists, contact Antom Technical Support. |

 > **[INFO]** **Note**    : If you do not receive a response, it may be due to a network timeout. Please retry the API call with a new     *paymentRequestId*     value.

<!-- /TabGroup -->
 > **[INFO]** **Common questions**
>
>  **Q: Can I use Chinese characters in the value of the request parameters?**
>
>  A: To avoid incompatibility of a certain payment method, do not use Chinese characters for parameters in the request.
>
>  ​
>
>  **Q: How to set the URL to receive the payment notification?**
>
>  A: Specify     *paymentNotifyUrl*     in the        [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API to receive the asynchronous notification about the payment result     **(**   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)  ), or configure the receiving URL in Antom Dashboard. If the URL is specified in both the request and Antom Dashboard, the value specified in the request takes precedence.
>
>  ​
>
>  **Q: What is the difference between**       ***paymentAmount***       **and**       ***orderAmount***      **?**  
>  A:    *paymentAmount*     refers to the payment amount, while     *orderAmount*     refers to the order amount. The actual charged amount is determined by     *paymentAmount*    .
>
>  ​
>
>  **Q: What does**       ***paymentSessionExpiryTime***       **specifically refer to in payment requests?**  
>  A:    *paymentSessionExpiryTime*     indicates the validity period from successful payment session creation until the buyer submits the payment. After submission, the payment processing timeout is 10 minutes. Therefore, the maximum total duration from session creation to payment completion is 1 hour and 10 minutes.

### Step 3: Invoke the SDK **[Server-side]** {#uzRYD}

 After obtaining the     *paymentSessionData*     value on the merchant server side, the merchant client can invoke the SDK to redirect the checkout page to the payment method authorization page. When the buyer submits a payment request, the SDK will automatically handle encrypted communication, risk control verification, page redirection, and payment instruction execution, enabling an end-to-end payment authorization process.

#### 1\. Instantiate the SDK {#U7jDh}

 1. Use   `AMSEasyPay`   to create the SDK instance. The configuration object includes the following parameters:

 | **Parameter name** | **Required** | **Description** |
| --- | --- | --- |
| *environment* | Yes | Used to specify the environment information   . Valid values are: - `sandbox`  : Sandbox environment. - `prod`  : Production environment. |
| *locale* | No | Used to specify the language information. Select the appropriate value based on the region of the payment method. Valid values for this parameter are listed as follows.If a value not in the following list is used, the English is used instead. - `en_US`  : English - `in_ID`  : Indonesian - `ms_MY`  : Malay - `tl_PH`  : Filipino - `ko_KR`  : Korean - `zh_CN`  : Simplified Chinese - `zh_HK`  : Traditional Chinese |
| *onEventCallback* | No | A callback function used to listen for payment events on the checkout page, returning     *eventCode*     and     *eventResult*    . During the payment process, set     *isNativeAppWebview*     to   `true`   and additionally monitor the following events: - `SDK_REDIRECT`  : Triggered when redirecting to a third-party payment page.     *eventResult.redirectUrls*     contains the redirection information.   After payment completion: - When     *notRedirectAfterComplete*     is   `true`   and payment is completed within the SDK, the payment result triggers a callback. Returns   `SDK_PAYMENT_SUCCESSFUL`   for successful payments and   `SDK_PAYMENT_FAIL`   for failed payments. If redirected to a payment method's page, no event code will be returned. - When     *notRedirectAfterComplete*     is   `false`  , the payment result does not trigger a callback but directly loads your specified result page (the     *paymentRedirectUrl*     specified in   [**pay (Checkout Payment)**](https://docs.antom.com/ac/ams/payment_cashier.md)   API).   > **[INFO]** **Note**    : Event codes should only be used for handling frontend navigation. Payment results must be determined based on the server-side payment status. |

 The following sample code shows how to instantiate the SDK using npm or CDN:

<!-- TabGroup -->

**Tab: npm**

```java
import { AMSEasyPay } from '@alipay/ams-checkout' // manage the package

const checkoutApp = new AMSEasyPay({
  environment: "sandbox",
  locale: "en_US",
  onEventCallback: ({code, message})=>{},
});
```

**Tab: CDN**

```java
const checkoutApp = new window.AMSEasyPay({
  environment: "sandbox",
  locale: "en_US",
  onEventCallback: ({code, message})=>{},
});
```

<!-- /TabGroup -->
 2. Use   `createComponent`   in the instance object to create a payment component. The parameters involved are as follows:

 | **Parameter name** | **Required** | **Description** |
| --- | --- | --- |
| *sessionData* | Yes | Create a configuration object using the     *sessionData*     parameter: Use the complete data of the value of     *paymentSessionData*     obtained in the response of the        [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API as the value of this parameter. |
| *isNativeAppWebview* | No | Indicates whether it is an in-app webview. Valid values are: - `true`  : The merchant integrates the web SDK within an in-app webview. - `false`  : The merchant integrates the web SDK via an H5 webpage. |
| *notRedirectAfterComplete* | No | Boolean type. Valid values are: - `false`  : Default value. The system will automatically redirect to the merchant's page upon payment completion. The same applies when the value is empty. - `true`  : The system will not automatically redirect to the merchant's page after payment completion.     - If the payment is completed within the SDK, the subsequent flow will be monitored through client-side event codes.   - If the payment is completed by redirecting to the payment method app, the process relies on that payment method's callback capability.   > **[INFO]** **Note**    : - This parameter applies only to scenarios where the payment is completed within the SDK. > - The event codes returned by the client-side are only used as a reference for the redirection operation of the client page. For transaction status updates, refer to the results returned by the server's   [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   or   [**inquirePayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API. |

 The following sample code shows how to create the component:

 ```java
async function create(sessionData) {
  await checkoutApp.createComponent({
    sessionData: sessionData,
    isNativeAppWebview: true, // Set as false by default to indicate that the merchant integrates the web SDK via an H5 webpage.
    notRedirectAfterComplete: false // Set as false by default to indicate that it will redirect to your page after the payment is completed.
  });
}
```

 3. Listen for event code to handle redirection events.

 By monitoring the   `SDK_REDIRECT`   event code, you can handle the subsequent process. An example code snippet is shown below:

 ```java
import { AMSEasyPay } from '@alipay/ams-checkout' // Package management

const checkoutApp = new AMSEasyPay({
  environment: "sandbox",
  locale: "en_US",
  onEventCallback: ({code, message, result}) => {
    switch (code) {
      case 'SDK_REDIRECT':
        // Handle redirect logic
        const redirectUrls = result?.redirectUrls || {};
        const jsonString = JSON.stringify(redirectUrls);

        // Check if the current environment's espJSBridge is available
        if (window.espJSBridge) {
            // Call the sdkRedirect method of espJSBridge, passing the redirect information.
            // This approach is for reference; merchants can also use their own native communication methods for data transfer.
            window.espJSBridge.sdkRedirect(jsonString)

            // After data transfer is complete, perform component cleanup
            checkoutApp.unmount();
        }
  
        break;
      default:
        console.log(code);
    }
  },
});
```

 4. Handle redirection events using a WebView container.

 Use a WebView container to manage in-app redirection events. The following are sample codes for iOS and Android respectively:

<!-- TabGroup -->

**Tab: iOS**

```java
// Step 1: Create webview container
let url = "https://www.merchantWeb.com"
let webView = WKWebView()
webView.load(URLRequest(url: url))
webView.configuration.userContentController.addUserScript(
    WKUserScript(
        source: "window.espJSBridge = { sdkRedirect: function(message) { window.webkit.messageHandlers.espJSBridge.postMessage(message); } }",
        injectionTime: .atDocumentStart,
        forMainFrameOnly: true
    )
)
webView.configuration.userContentController.add(self, name: "espJSBridge")

// Step 2: Handle redirect event
extension DemoViewController: WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        // Monitor redirect event
        if message.name == "espJSBridge",
            let bodyString = message.body as? String,
            let bodyData = bodyString.data(using: .utf8),
            let body = try? JSONSerialization.jsonObject(with: bodyData, options: []) as? [String: Any]
        {
            let applinkUrl = body["applinkUrl"] as? String
            let schemeUrl = body["schemeUrl"] as? String
            let normalUrl = body["normalUrl"] as? String
  
            // Redirect to link
            // Attempt to redirect to applinkUrl
            tryRedirect(url: applinkUrl) { [weak self] success in
              // If failed, attempt to redirect to schemeUrl
              if !success {
                    self?.tryRedirect(url: schemeUrl) { [weak self] success in
                        // If failed, attempt to redirect to normalUrl
                        if !success {
                            self?.tryRedirect(url: normalUrl) { _ in }
                        }
                    }
                }
            }
        }
    }
}

func tryRedirect(url: String?, completion: @escaping (Bool) -> Void) {
    guard let url = url, let url = URL(string: url) else {
        completion(false)
        return
    }
    UIApplication.shared.open(url) { success in
        completion(success)
    }
}
```

**Tab: Android**

```java
// Step 1: Create webview container
WebView webView;
webView = findViewById(R.id.webView);
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webView.addJavascriptInterface(new JSBridgeInterface(this), "espJSBridge");
webView.loadUrl(url);

// Step 2: Handle redirect event
public class JSBridgeInterface {
    private Context mContext;

    public JSBridgeInterface(Context context) {
        mContext = context;
    }

    // Monitor redirect event
    @JavascriptInterface
    public void sdkRedirect(String redirectInfo) {
        JSONObject jsonObject = JSONObject.parseObject(redirectInfo);
        String schemeUrl = jsonObject.getString("schemeUrl");
        String applinkUrl = jsonObject.getString("applinkUrl");
        String normalUrl = jsonObject.getString("normalUrl");

        // Attempt to redirect to schemeUrl
        if (openRedirectionUrl(schemeUrl, true)) {
            return;
        }

        // Attempt to redirect to applinkUrl
        if (openRedirectionUrl(applinkUrl, false)) {
            return;
        }

        // Attempt to redirect to normalUrl
        if (openRedirectionUrl(normalUrl, false)) {
            return;
        }

        showToast(mContext, "Failed to open URL");
    }

    private boolean openRedirectionUrl(String url, boolean isScheme) {
        if (TextUtils.isEmpty(url)) {
            return false;
        }
        try {
            Intent intent = isScheme ? Intent.parseUri(url, Intent.URI_INTENT_SCHEME) : new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            startActivity(mContext, intent, null);
            return true;
        } catch (Exception exception) {
            showToast(mContext, exception.getMessage()); // Display prompt message
            return false;
        }
    }

    private void showToast(Context context, String message) {
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
    }
}
```

<!-- /TabGroup -->

#### 2\. Handle SDK callback event codes {#OxaBd}

 Below are the event codes returned by   `onEventCallback`   and handling recommendations:

 | **Code** | **Description** | **Further action** |
| --- | --- | --- |
| SDK_REDIRECT | Triggered when redirection to a third-party payment page (such as Alipay, digital wallet applications, etc.) is required. The     *eventResult.redirectUrls*     object returned by this event contains redirect URLs for different environments. | Obtaining redirect URLs from     *redirectUrls*    : - iOS: Prioritize using     *applinkUrl*    , followed by     *schemeUrl*    , and finally     *normalUrl*    . - Android: Prioritize using     *schemeUrl*    , followed by     *applinkUrl*    , and finally     *normalUrl*    . |
| SDK_CALL_URL_SUCCESS | Successfully launched the payment method app or redirected to the merchant page. | No further action is needed. |
| SDK_LAUNCH_PAYMENT_APP_ERROR | This event code indicates one of the following situations: - Failed to invoke the app of the buyer's selected payment method or failed to redirect to the checkout page of the payment method. - Failed to redirect to the merchant page. | Check whether the     *paymentRedirectUrl*     parameter is correctly passed when calling the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API. Web/WAP scenarios rarely experience redirection exceptions. However, in the event of any exceptions, it is recommended to verify the redirection link. For mobile app scenarios, if frequent redirection exceptions occur, contact Antom Technical Support to troubleshoot redirection or cross-application calling issues. |
| SDK_PAYMENT_CANCEL | The buyer canceled the payment (the buyer exited the payment page without submitting the order). | You can re-invoke the SDK using     *paymentSessionData*     within its validity period; If it has expired, you need to initiate a new        [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   request. |
| SDK_PAYMENT_SUCCESSFUL | Indicates that the payment is successful on the wallet side. | Please obtain the final payment result from Antom server. You can use the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API or the        [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   API to confirm the result. Suggest redirecting buyers to the payment result page. > **[INFO]** **Note**    : This event code is returned only when the payment process is completed within the SDK. |
| SDK_PAYMENT_FAIL | Indicates that the payment is unsuccessful on the wallet side. | Please obtain the final payment result from Antom server. You can use the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API or the        [**notifyPayment**](https://docs.antom.com/ac/ams/paymentrn_online.md)   API to confirm the result. Suggest redirecting buyers to the payment result page. > **[INFO]** **Note**    : This event code is returned only when the payment process is completed within the SDK. |

 The following sample code shows how to handle the callback function:

 ```java
function onEventCallback({ code, result }) {
  switch (code) {
    case 'SDK_REDIRECT':
      // Handle redirect logic
      break;
    case 'SDK_PAYMENT_CANCEL':
      // Within the validity period, paymentSessionData can be used to reinvoke the SDK
      break;
    default:
      break;
  }
}
```

#### 3\. Free SDK component resources {#cIkid}

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

 - When the buyer switches views to exit the checkout page, free the component resources created in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API.
- When the buyer initiates multiple payments, free the component resources created in the previous   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API.
- After obtaining the final payment result, free the component resources.

 The following sample code shows how to free components:

 ```javascript
// Free SDK component resources
checkoutApp.unmount();
```

 > **[INFO]** **Common questions**
>
>  **Q: Is it mandatory to handle SDK callback events?**  
>  A: Perform the following operations based on the value of    *isNativeAppWebview*    :
>
>  - When     *isNativeAppWebview*     is   `true`  , you need to handle SDK callback events. They are generally categorized into two types:
>
>    - Key callbacks (e.g., payment redirect   `SDK_REDIRECT`  ): Must be handled, otherwise the payment process will be interrupted.
>   - Other callbacks:     *Optional handling*    . You may use these callback events for logging or tracking purposes.
>
>  - When   `isNativeAppWebview`   is   `false`  , callback handling is optional. You may use the callback events for logging or tracking purposes.
>
>  ​
>
>  **Q: Can an**      **AMSEasyPay**      **instance execute**      **createComponent**      **multiple times?**  
>  A: No. If you need to initiate a new payment, you need to create a new   AMSEasyPay    instance.
>
>  ​
>
>  **Q: Are SDK calls required for both first and subsequent payments?**  
>  A: Yes.

<!-- /ToggleTab -->

### Step 4: Obtain authorization and payment result  **[Client-side]** {#XXH3n}

 For the first payment, you can obtain both the authorization and payment results, while for subsequent payments, only the payment result is available. Below are common scenarios:

 | **Type** | **Common scenarios** | **Received asynchronous notification** | **Suggestions** |
| --- | --- | --- | --- |
| First payment | The buyer successfully authorized and paid. | Authorization succeeded, payment succeeded. | - If a payment asynchronous notification is received, advance to the corresponding status. - If an authorization success asynchronous notification is received   , maintain the buyer-token mapping relationship on the merchant side. - If no notification is received by the merchant order closure time, you can call the   [**cancel**](https://docs.antom.com/ac/ams/paymentc_online.md)   API to close the order. |
| The buyer authorized successfully but payment failed (e.g., due to insufficient balance). | Authorization succeeded, payment failed. |  |  |
| The buyer authorization failed (or did not authorize) but payment succeeded. | No authorization asynchronous notification received, payment succeeded. |  |  |
| The buyer authorization failed (or did not authorize) and payment failed (e.g., due to insufficient balance). | No authorization asynchronous notification received, payment failed. |  |  |
| The buyer authorization failed (or did not authorize) and did not submit payment. | No asynchronous notifications received for both authorization and payment. |  |  |
| Subsequent payments | The buyer successfully paid. | Payment succeeded. | - If a payment asynchronous notification is received, advance to the corresponding status. - If no notification is received by the merchant order closure time, you can call the   [**cancel**](https://docs.antom.com/ac/ams/paymentc_online.md)   API to close the order. |
| The buyer payment failed (e.g., due to insufficient balance). | Payment failed. |  |  |

<!-- TabGroup -->

**Tab: Obtain the authorization result**

#### Obtain the authorization result {#G7js1}

 When the authorization is successful during the first payment, Antom sends you the asynchronous notification through the   [**notifyAuthorization**](https://docs.antom.com/ac/ams/notifyauth.md)   API.

 1. Follow the steps below to set the notification webhook URL:

 Log in to   [Antom Dashboard](https://dashboard.alipay.com/global-payments/developers/iNotify)   >     **Developer**     >     **Notification URL**    . Add the notification URL to     **alipay.ams.authorizations.notify**    . Refer to   [Notification URL](https://docs.antom.com/ac/merchant_service/notification.md)   for detailed steps.

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

 ```json
{
    "accessToken": "28288803001319861727421828000Cv96OFlYoi17100****",
    "accessTokenExpiryTime": 2145916817000,
    "authState": "36a38e87-0453-495e-ad17-b46553b918da",
    "authorizationNotifyType": "TOKEN_CREATED",
    "userLoginId": "852-91****67",
    "result": {
        "resultCode": "SUCCESS",
        "resultMessage": "success.",
        "resultStatus": "S"
    }
}
```

 Based on the value of     *result.resultStatus*     in the authorization result notification request (only  `S`  is returned), process as follows:

 `S`  : Indicates successful authorization, and the following parameters are returned:

 | **Parameter name** | **Description** |
| --- | --- |
| *accessToken* | The access token that is used to access the corresponding scope of the user resource. |
| *accessTokenExpiryTime* | The validity period of the     *accessToken*    . For the specific expiry time, refer to The table of    validity period of accessToken   . If the     *accessToken*     expires, you need to guide the buyer to authorize again. |
| *authState* | A unique ID assigned for initiating authorization. This value is used to verify consistency with the     *authState*     specified in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   request. |
| *authorizationNotifyType* | Only   `TOKEN_CREATED`   will be returned, indicating that the buyer successfully initiated a payment authorization on the merchant's client. |
| *userLoginId* | The login ID used by the buyer when registering the payment method. This field has been desensitized. You may store this account for display in subsequent payments. > **[INFO]** **Note**    : Not all payment methods return this information. |

   The table below shows the token validity period for each payment method:

 | **Payment method** | **Validity period of**       ***accessToken*** |
| --- | --- |
| [Alipay](https://docs.antom.com/ac/antomop/alipay_cn.md?platform=auto_debit) | 92 years |
| [AlipayHK](https://docs.antom.com/ac/antomop/aplusalipayhk.md?platform=auto_debit) | 100 years |
| [DANA](https://docs.antom.com/ac/antomop/DANA.md?platform=auto_debit) | 100 years |
| [GCash](https://docs.antom.com/ac/antomop/gcash.md?platform=auto_debit) | 100 years |
| [Touch'n Go eWallet](https://docs.antom.com/ac/antomop/touchngo.md?platform=auto_debit) | 100 years |
| TrueMoney | 100 years |
| [Express Bank Transfer](https://docs.antom.com/ac/antomop/express_bank_transfer.md) | No     *accesstoken*     is returned. The merchant side does not need to maintain an accessToken. |

 2. The result notification sent by Antom is signed by Antom, it is recommended that you verify the signature to confirm that the notification was sent by Antom. Refer to the following code example to verify the notification:

 ```java
@PostMapping("/receiveAuthNotify")
@ResponseBody
public Result receiveAuthNotify(HttpServletRequest request, @RequestBody String notifyBody) {
    // retrieve the required parameters from http request
    String requestUri = request.getRequestURI();
    String requestMethod = request.getMethod();

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

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

        // deserialize the notification body
        AlipayAuthNotify authNotify = JSON.parseObject(notifyBody,AlipayAuthNotify.class);

        if (authNotify != null && "SUCCESS".equals(authNotify.getResult().getResultCode())
                 && "TOKEN_CREATED".equals(authNotify.getAuthorizationNotifyType())) {
            // save buyer's PaymentMethodType corresponding to accessToken
            PaymentVO payment = authStatePayment.get(authNotify.getAuthState());
            User user = users.get(payment.getUserId());
            user.getPaymentMethodTypeAccessToken().put(payment.getPaymentMethodType(), authNotify.getAccessToken());
            return Result.builder().resultCode("SUCCESS").resultMessage("success.").resultStatus(ResultStatusType.S).build();
        }
        // other types of notifications
    } catch (Exception e) {
        return Result.builder().resultCode("FAIL").resultMessage("fail.").resultStatus(ResultStatusType.F).build();
    }

    return Result.builder().resultCode("SYSTEM_ERROR").resultMessage("system error.").resultStatus(ResultStatusType.F).build();
}
```

 3. After receiving the notification, whether the authorization is successful or not, you are not required to sign the response, but each notification request must be responded to in the format specified below. Otherwise, Antom will resend the asynchronous notification.

 ```json
{
  "result": {
    "resultCode": "SUCCESS",
    "resultStatus": "S",
    "resultMessage": "success"
  }
}
```

**Tab: Obtain the payment result**

#### Obtain the payment result {#LjpOp}

 After the first or subsequent payment is completed, you can obtain the payment result through one of the following methods:

 - **Receive the asynchronous notification**    : Receive the    payment result delivered by the Antom server.
- **Inquire about the result**    : Call   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API to query payment status.

<!-- TabGroup -->

**Tab: Receive the asynchronous notification**

1. Follow the steps below to set the notification webhook URL:

 When the payment reaches a final status of success or failure, Antom sends an asynchronous notification to your configured webhook URL. You can choose one of the following two methods to set up the Webhook URL for receiving notifications:

 - **Order-level notification configuration**    : Specify an independent notification URL for each order through the     *paymentNotifyUrl*     parameter in the   [**createPaymentSession (EasySafePay)**](https://docs.antom.com/ac/ams/createpaymentsession_easypay.md)   API request.
- **Merchant-level notification configuration**    : Log in to   [Antom Dashboard](https://dashboard.alipay.com/global-payments/developers/iNotify)   >     **Developer**     >     **Notification**         **URL**     and add a notification URL for the     **alipay.ams.payments.payNotify**     API. For specific operations, refer to   [Notification URL](https://docs.antom.com/ac/merchant_service/notification.md)  .

 > **[INFO]** **Note**    : If you have configured notification URLs through both methods mentioned above, the API settings will take precedence.

 The following code shows a sample of the notification request:

 ```json
{
    "actualPaymentAmount": {
        "currency": "HKD",
        "value": "98080"
    },
    "customsDeclarationAmount": {},
    "notifyType": "PAYMENT_RESULT",
    "paymentAmount": {
        "currency": "HKD",
        "value": "98080"
    },
    "paymentCreateTime": "2024-09-27T00:23:36-07:00",
    "paymentId": "202409271940108001001881E0211235544",
    "paymentRequestId": "bc93d19e-e1f6-4b68-b6b1-3d6ddc2a792a",
    "paymentTime": "2024-09-27T00:23:46-07:00",
    "pspCustomerInfo": {
        "pspCustomerId": "20881221121****",
        "pspName": "ALIPAY_HK"
    },
    "result": {
        "resultCode": "SUCCESS",
        "resultMessage": "success.",
        "resultStatus": "S"
    }
}
```

 The table below displays the possible values returned in the     *resultStatus*     parameter of the response. Please follow the corresponding instructions for handling:

 | ***result.resultStatus*** | **Message** | **Suggestion** |
| --- | --- | --- |
| `S` | Payment was successful. | The following fields can be obtained from: - *paymentrequestld*    : Payment request ID for inquiry, cancellation, and reconciliation. - *paymentld*    : Represents the payment order ID generated by Antom for refund and reconciliation. - *paymentAmount*    : Indicates the currency and amount of payment. |
| `F` | Payment failed. | It is recommended to guide the buyer to place the order again. |

 2. The result notification sent by Antom is signed by Antom, it is recommended that you verify the signature to confirm that the notification was sent by Antom. Refer to the following code example to verify the notification:

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

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

    try {
        // verify the signature of notification
        boolean verifyResult = WebhookTool.checkSignature(requestUri, requestMethod, clientId,
                                                          requestTime, signature, notifyBody, ANTOM_PUBLIC_KEY);
        if (!verifyResult) {
            throw new RuntimeException("Invalid notify signature");
        }
        // deserialize the notification body
        JSONObject jsonObject = JSON.parseObject(notifyBody);
        String notifyType = (String)jsonObject.get("notifyType");
        if("PAYMENT_RESULT".equals(notifyType)){
            AlipayPayResultNotify paymentNotify = jsonObject.toJavaObject(AlipayPayResultNotify.class);
            if (paymentNotify != null && "SUCCESS".equals(paymentNotify.getResult().getResultCode())) {
                // handle your own business logic.
                // e.g. The relationship between payment information and buyers is kept in the database.
                System.out.println("receive payment notify: " + JSON.toJSONString(paymentNotify));
                return Result.builder().resultCode("SUCCESS").resultMessage("success.").resultStatus(ResultStatusType.S).build();
            }
        }
        // other types of notifications
    } catch (Exception e) {
        // handle error condition
        return Result.builder().resultCode("FAIL").resultMessage("fail.").resultStatus(ResultStatusType.F).build();
    }
    return Result.builder().resultCode("SYSTEM_ERROR").resultMessage("system error.").resultStatus(ResultStatusType.F).build();
}
```

 3. After receiving the notification, you are not required to sign the response, but must reply to every notification request in the following standardized format, regardless of whether the payment was successful or not.

 ```json
{
  "result": {
    "resultCode": "SUCCESS",
    "resultStatus": "S",
    "resultMessage": "success"
  }
}
```

**Tab: Inquire about the payment result**

Call the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API to initiate a query on the payment result. The payment status can be checked via polling or scheduled tasks after the payment is initiated.

 The following sample code shows how to call the   [**inquiryPayment**](https://docs.antom.com/ac/ams/paymentri_online.md)   API:

 ```java
public static void inquiryPayment() {
    AlipayPayQueryRequest alipayPayQueryRequest = new AlipayPayQueryRequest();

    // replace with your paymentRequestId
    alipayPayQueryRequest.setPaymentRequestId("yourPaymentRequestId");

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

 The following code shows a sample of the request message:

 ```json
{
  "paymentRequestId": "bc93d19e-e1f6-4b68-b6b1-3d6ddc2a****"
}
```

 The following code shows a sample of the response message:

 ```json
{
  "actualPaymentAmount": {
    "currency": "USD",
    "value": "1"
  },
  "customsDeclarationAmount": {
    "currency": "CNY",
    "value": "7"
  },
  "paymentAmount": {
    "currency": "USD",
    "value": "1"
  },
  "paymentId": "20250305194010800100188690281017336",
  "paymentMethodType": "ALIPAY_CN",
  "paymentRedirectUrl": "https://checkout.antom.com/checkout-page/pages/payment/index.html?sessionData=%2BCUim8L0KviXagaygm9xBL5jZ%2F75w6gAX1nn8pcuFuGkIsMoHtD6U88YSyMrMJvorbwnBg5uQv8e6pyvIpjDQQ%3D%3D%26%26SG%26%26188%26%26eyJleHRlbmRJbmZvIjoie1wiT1BFTl9NVUxUSV9QQVlNRU5UX0FCSUxJVFlcIjpcInRydWVcIixcImxvY2FsZVwiOlwiZW5fVVNcIixcImRpc3BsYXlBbnRvbUxvZ29cIjpcInRydWVcIn0iLCJwYXltZW50U2Vzc2lvbkNvbmZpZyI6eyJwYXltZW50TWV0aG9kQ2F0ZWdvcnlUeXBlIjoiQUxMIiwicHJvZHVjdFNjZW5lIjoiQ0hFQ0tPVVRfUEFZTUVOVCIsInByb2R1Y3RTY2VuZVZlcnNpb24iOiIxLjAifSwic2VjdXJpdHlDb25maWciOnsiYXBwSWQiOiIiLCJhcHBOYW1lIjoiT25lQWNjb3VudCIsImJpelRva2VuIjoiNlRjZGJyMnJGM3JQWXg0aGtWckhxYnZqIiwiZ2F0ZXdheSI6Imh0dHBzOi8vaW1ncy1zZWEuYWxpcGF5LmNvbS9tZ3cuaHRtIiwiaDVnYXRld2F5IjoiaHR0cHM6Ly9vcGVuLXNlYS1nbG9iYWwuYWxpcGF5LmNvbS9hcGkvb3Blbi9yaXNrX2NsaWVudCIsIndvcmtTcGFjZUlkIjoiIn0sInNraXBSZW5kZXJQYXltZW50TWV0aG9kIjpmYWxzZX0%3D",
  "paymentRequestId": "PAYMENT_20250305220039086_AUTO",
  "paymentResultCode": "SUCCESS",
  "paymentResultMessage": "success.",
  "paymentStatus": "SUCCESS",
  "paymentTime": "2025-03-05T06:02:34-08:00",
  "pspCustomerInfo": {
    "pspName": "ALIPAY_CN"
  },
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": "success.",
    "resultStatus": "S"
  }
}
```

 The table below displays the possible values returned in the     *paymentStatus*     parameter of the response. Please follow the corresponding instructions for handling:

 | ***paymentStatus***     ​ | **Message** | **Further actions** |
| --- | --- | --- |
| `SUCCESS` | Payment was successful. | No further action is required. |
| `FAIL` | Payment failed. | Guide the buyer to place a new order. |
| `PROCESSING` | Payment is being processed. |  |
| `CANCELLED` | Payment is canceled. |  |

<!-- /TabGroup -->

<!-- /TabGroup -->
   > **[INFO]** **Common questions**
>
>  **Q: When is the payment notification sent?**
>
>  A: It depends on whether the payment is completed: If the payment is successfully completed, Antom usually sends an asynchronous notification within 3 to 5 seconds.
>
>  ​
>
>  **Q: Is there an asynchronous notification sent for authorization failure?**
>
>  A: No. An asynchronous notification will only be sent if the authorization is successful; there will be no notification returned for authorization failure.
>
>  ​
>
>  **Q: Will the asynchronous notification be re-sent?**
>
>  A: Yes, the asynchronous notification will be re-sent automatically within 24 hours for the following cases:
>
>  - If you didn't receive the asynchronous notification due to network reasons.
> - If you receive an asynchronous notification from Antom, but you didn't make a response to the notification in the sample code format of   [Process the notification](https://docs.antom.com/ac/cashierpay/notifications.md#JtjSl)  .
>
>  The notification can be resent up to 8 times or until a correct response is received to terminate delivery. The sending intervals are as follows: 0 minutes, 2 minutes, 10 minutes, 10 minutes, 1 hour, 2 hours, 6 hours, and 15 hours.
>
>  ​
>
>  **Q: Are the authorization notification and payment result notification sent separately, and will the authorization notification always be received before the payment result notification?**
>
>  A: Due to the uncontrollable nature of network stability, it is possible for the authorization notification to arrive later than the payment result notification.
>
>  ​
>
>  **Q: Is authorization result inquiry supported?**
>
>  A: Currently, calling an interface to query the authorization result is not supported.
>
>  ​
>
>  **Q: When responding to an asynchronous notification, do I need to add a digital signature?**
>
>  A: No. If you receive an asynchronous notification from Antom, you are required to return the response in the sample code format of   [Process the notification](https://docs.antom.com/ac/cashierpay/notifications.md#JtjSl)  , but you do not need to countersign the response.

## After payments {#wkpl5}

### Revoke authorization {#Wrduo}

 After authorization is completed, the buyer can revoke the authorization from either the merchant side or the payment method side. Once revoked, the original authorization token immediately becomes invalid and cannot be used for payments again. For details, refer to   [Revoke](https://docs.antom.com/ac/easypay/revoke.md)  .

### Cancel {#Otb6j}

 You can cancel orders through the   [**cancel**](https://docs.antom.com/ac/ams/paymentc_online.md)   API within the time window (by D+1 day 00:15 GMT+8). For details, refer to   [Cancel](https://docs.antom.com/ac/easypay/cancel.md)  .

### Refund {#kg4oU}

 Refer to   [Refund](https://docs.antom.com/ac/easypay/refund.md)   to learn about Antom refund rules and operation process.

### Reconciliation {#WPkTk}

 After a transaction is completed, use the provided Antom financial reports to perform reconciliation. For settlement rules and reconciliation operations, refer to   [Reconciliation](https://docs.antom.com/ac/easypay/settle_reconcile.md)  .

## Best practices {#O7DPd}

 Antom provides you with the following best practice solutions. Refer to   [Best practices](https://docs.antom.com/ac/easypay/practice.md)   for more details.

 - Intelligent risk control service
- Security expansion package
- Order query after redirecting to the merchant result page
- Merchant-initiated transaction cancellation
- Payment failure retry