Antom, leading provider of tailored payment solutionsAntom, leading provider of tailored payment solutions

EasySafePay (Android)

This article introduces the integration solution to support accepting payments from a desktop browser or mobile browser. After integration, you can access various payment methods like digital wallets, bank cards, and bank transfers.

User experience

The following screenshots show the user experience of wallet and bank transfer. During the first-time payments, buyers can enable password-free payment for subsequent payments. The entire payment process for subsequent payments will be performed on your website or application.

Wallet

With the entire payment process remaining within your website or application, buyers are allowed to pay and enable password-free payments during their first-time payments and make subsequent payments without the need to enter the payment password.

During the first-time payments, the buyer completes the authorization process to pay and enable subsequent password-free payments.

Android.webp

Bank transfer

For bank transfer payment methods, the following graphics show the user experience for the first-time and subsequent payments.

During the first-time payments, users need to input the payment password and verification number.

image.png

Payment flow

When a buyer selects a payment method provided by Antom, you need to collect key information such as the payment request ID, order amount, payment method, order description, payment redirect page URL, and payment result notification URL. Call the createPaymentSession API to make orders and pull up page via SDK.


11111.svg

For various payment methods, the EasySafePay SDK will guide the payment through the following process:

  • The buyer lands on the checkout page.
  • Your server creates a payment session based on the payment method, amount, currency, and goods.
  • Your client creates and invokes the EasySafePay SDK with the payment session.
  • The EasySafePay SDK collects payment elements, displays code information, redirects, invokes, and guides the buyer to complete the payment based on the payment method's characteristics.
  • Your server receives vaulting result notifications.
  • Your server receives payment result notifications.

Quick start

Step 1: Create a payment session Server-side

When a buyer selects a payment method provided by Antom, you need to collect key information such as the payment request ID, order amount, payment method, order description, payment redirect page URL, and payment result notification URL. Call the createPaymentSession API to create a payment session and return the payment session to the client.

Antom provides server-side API libraries for multiple languages. The following codes use Java as an example. You need to install Java 6 or higher.

Install an API library

You can find the latest version on GitHub.

copy
<dependency>
  <groupId>com.alipay.global.sdk</groupId>
  <artifactId>global-open-sdk-java</artifactId>
  <version>2.0.21</version>
</dependency>

Initialize request instance

Create a singleton resource to make a request to Antom.

copy
import com.alipay.global.api.AlipayClient;
import com.alipay.global.api.DefaultAlipayClient;

String merchantPrivateKey = "YOUR PRIVATE KEY";
String alipayPublicKey = "ALIPAY PUBLIC KEY"
AlipayClient defaultAlipayClient = new DefaultAlipayClient(EndPointConstants.SG,
                merchantPrivateKey, alipayPublicKey);

Create a payment session

Creating a payment session involves the following parameters:

Parameter name

Required

Description

paymentRedirectUrl

The merchant page URL that the buyer is redirected to after the payment is completed.

authState

The unique identifier assigned by you to initiate the authorization, which is used to obtain tokens for subsequent secret-free payments. This parameter must be passed only for the first payment, you do not need to pass this parameter for subsequent payments.

paymentNotifyUrl

Payment result notification address. This address must be HTTPS.

paymentSessionExpiryTime

Timeout for payment session. Default is 1 hour, can be set to a timeout within 1 hour, the format of the value follows the ISO 8601 standard. For example, 2019-11-27T12:01:01+08:00.

userLoginId

The buyer's wallet side login account, which can be the buyer's email address or phone number.

order.buyer: referenceBuyerId/buyerPhoneNo/buyerEmail

Pass in buyer information for risk decisions. Pass in referenceBuyerId, buyerPhoneNo, buyerEmail One of these parameters is sufficient.

Above parameters are basic parameters for creating a payment session. For full list of parameters and additional requirements for payment methods, see createPaymentSession (EasySafePay).

The following sample code shows how to call the createPaymentSession API:

copy
AlipayPaymentSessionRequest alipayPaymentSessionRequest = new AlipayPaymentSessionRequest();
alipayPaymentSessionRequest.setClientId(clientId);
alipayPaymentSessionRequest.setPath("/ams/sandbox/api/v1/payments/createPaymentSession");
alipayPaymentSessionRequest.setProductCode(ProductCodeType.AGREEMENT_PAYMENT);
alipayPaymentSessionRequest.setProductScene(ProductSceneConstants.EASY_PAY);

// replace to your paymentRequestId
alipayPaymentSessionRequest.setPaymentRequestId("paymentRequestId001");

Amount amount = new Amount();
// set amount
amount.setCurrency("CNY");
amount.setValue("100");
alipayPaymentSessionRequest.setPaymentAmount(amount);

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

// set agreementInfo
AgreementInfo agreementInfo = new AgreementInfo();
agreementInfo.setAuthState("authState001");
agreementInfo.setUserLoginId("userLoginId001");
alipayPaymentSessionRequest.setAgreementInfo(agreementInfo);

// set paymentMethod
PaymentMethod paymentMethod = new PaymentMethod();
paymentMethod.setPaymentMethodType("ALIPAY_CN");

// set order Info
Order order = new Order();
order.setReferenceOrderId("referenceOrderId001");
order.setOrderDescription("orderDescription001");
order.setOrderAmount(amount);
Buyer buyer = new Buyer();
buyer.setReferenceBuyerId("referenceBuyerId001");
order.setBuyer(buyer);
order.setOrderAmount(amount);
alipayPaymentSessionRequest.setOrder(order);

// replace to your redirect url
alipayPaymentSessionRequest.setPaymentNotifyUrl("https://www.yourNotifyUrl");
alipayPaymentSessionRequest.setPaymentRedirectUrl("https://www.yourMerchantWeb.com");

AlipayPaymentSessionResponse alipayPaymentSessionResponse = defaultAlipayClient
        .execute(alipayPaymentSessionRequest);

The following code shows a sample of the request message:

copy
{
    "settlementStrategy": {
        "settlementCurrency": "USD"
    },
    "productCode": "AGREEMENT_PAYMENT",
    "productScene": "EASY_PAY",
    "paymentNotifyUrl": "https://www.yourNotifyUrl",
    "paymentRequestId": "paymentRequestId001",
    "paymentRedirectUrl": "https://www.yourMerchantWeb.com",
    "paymentMethod": {
        "paymentMethodType": "ALIPAY_CN"
    },
    "agreementInfo": {
        "authState": "authState001",
        "userLoginId":"userLoginId001"
    },
    "paymentAmount": {
        "currency": "CNY",
        "value": "100"
    },
    "order": {
        "orderAmount": {
            "currency": "CNY",
            "value": "100"
        },
        "referenceOrderId": "referenceOrderId001",
        "orderDescription": "orderDescription001",
        "buyer":{
          "referenceBuyerId":"referenceBuyerId001"
        }
        
    }
}

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

  • paymentSessionData: the payment session to be returned to the frontend
  • paymentSessionExpiryTime: the expiration time of the payment session.
copy
{
  "paymentSessionData": "UNvjVWnWPXJA4BgW+vfjsQj7PbOraafHY19X+6EqMz6Kvvmsdk+akdLvoShW5avHX8e8J15P8uNVEf/PcCMyXg==&&SG&&111",
  "paymentSessionExpiryTime": "2023-04-06T03:28:49+08:00",
  "paymentSessionId": "UNvjVWnWPXJA4BgW+vfjsQj7PbOraafHY19X+6EqMz6Ikyj9FPVUOpv+DjiIZqMe",
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": "success.",
    "resultStatus": "S"
  }
}

FAQs

Can Chinese characters be used in the request?

 Do not use Chinese characters for the fields in the request including paymentRequestId, referenceOrderId, orderDescription, and goods to avoid incompatible payment methods, such as QRIS and Mastercard.

How to set the payment result notification address?

Antom will send the payment result through the notifyPayment, which you can specify in the createPaymentSession API via the paymentNotifyUrl parameter. If the address of each payment is the same, you can also configure it in the Antom Dashboard. If you have configured the address and set the parameter in the API, Antom will use the address set in the API.

Step 2: Create and invoke the SDK Client-side

Install

Version Requirements: target at least Android 4.4 (API level 19) or higher.

To integrate the SDK package, please refer to Integrate the SDK Package.

Instantiate the SDK

Create an SDK instance and specify basic configurations. Creating a configuration object includes the following methods:

Parameter name

Required

Description

setLocale

It is used to pass in language information. Valid values are listed as follows. You can choose the value to pass based on the region of the payment method. If other values are passed, the local language is used by default:

  • en_US: English
  • in_ID: Indonesian
  • th_TH: Thai
  • ms_MY: Malay
  • tl_PH: Filipino
  • ko_KR: Korean
  • vi_VN: Vietnamese
  • zh_HK: Traditional Chinese

setOption

It is used to specify whether to use the default loading pattern and the sandbox environment. Valid values are:

  • "sandbox", "true": Sandbox environment
  • "sandbox", "false": Production environment
  • "showLoading", "true": Use the default loading pattern.
  • "showLoading", "false": Do not use the default loading pattern.
  • "windowGravity","LANDSCAPE_CENTER": Center the window in landscape mode.
  • "windowGravity","LANDSCAPE_RIGHT": Align the window to the right in landscape mode.

The following sample code shows how to instantiate the SDK:

copy
// Step 1: Create the AMSEasyPayConfiguration type.
AMSEasyPayConfiguration configuration = new AMSEasyPayConfiguration();
configuration.setLocale(new Locale("en", "US"));
// Specify showLoading as true (default value) to use the default loading pattern. Specify it as false to customize the loading animation based on onEventCallback.
configuration.setOption("showLoading", "true");
// Set the sandbox environment. If you leave it empty, the production environment is used by default.
configuration.setOption("sandbox", "true");
// Set the callback to monitor payment events on the checkout page.
configuration.setOnCheckoutListener(new OnCheckoutListener() {
    @Override
    public void onEventCallback(String eventCode, AMSEventResult eventResult) {
        if("SDK_PAYMENT_CANCEL".equals(eventCode)){
            // Add interactive prompts.
        }
        Toast.makeText(activity, "eventCode=" + eventCode + " message=" + message, Toast.LENGTH_SHORT).show();
    }
});

// Instantiate AMSEasyPay. Create a new AMSEasyPay component before each createPaymentSession API request.
AMSEasyPay checkout = new AMSEasyPay.Builder(activity, configuration).build();

Invoke the SDK

Call the createComponent method:

Parameter name

Required

Description

sessionData

Create a configuration object by using the sessionData parameter: Pass the complete data in the paymentSessionData parameter obtained in the response through the createpaymentSession (Checkout Payment) API to the sessionData parameter.

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

  • When the buyer exits the checkout page, free the component resources created in the createPaymentSession.
  • When the buyer initiates multiple payments, free the component resources created in the previous createPaymentSession.

The following sample code shows how to invoke the SDK:

copy
checkout.createComponent(activity, sessionData);

//Free SDK component resources
checkout.onDestroy();

Step 3: Obtain authorization result or payment result Server-side

You can obtain the authorization and payment results for first-time payments, and a payment result only for subsequent payments. You can obtain the authorization or payment result by one of the following methods:

  • Receive the asynchronous notification
  • Inquire about the result

Receive the asynchronous notification

When the authorization is successful, Antom sends you the asynchronous notification through the notifyAuthorization API. When you receive the notification, you must return a response as instructed in Requirements. Meanwhile, you must update the authorization status of the buyer in your system and display the buyer's desensitized account obtained from the notification on your authorization management page.

The following code shows a sample of the notification request:

copy
{
  "accessToken": "2810123456789012345678901234567890",
  "authState": "AUTHSTATE_SAMPLE_1234567890",
  "authorizationNotifyType": "TOKEN_CREATED",
  "userLoginId": "852-52***184",
  "result": {
    "resultCode": "SUCCESS",
    "resultMessage": "success.",
    "resultStatus": "S"
  }
}

The following sample code shows how to verify the signature of the notification and make a response to the notification:

copy
@RequestMapping(path = "/authResult", method = RequestMethod.POST)
public ResponseEntity<AlipayResponse> authNotifyProcessor(HttpServletRequest request,
                                                          @RequestBody String body) {
    // retrieve the required parameters from the request header.
    String requestTime = request.getHeader("request-time");
    String clientId = request.getHeader("client-id");
    String rawSignature = request.getHeader("signature");
    String signature = "";

    // get valid part from raw signature
    if(rawSignature==null||rawSignature.isEmpty()){
        throw new RuntimeException("empty notify signature");
    }else {
        String[] parts = rawSignature.split("signature=");
        if (parts.length > 1) {
            signature = parts[1];
        }
    }

    // verify auth result notify's signature
    boolean verifyResult = SignatureTool.verify(request.getMethod(), request.getRequestURI(),
            clientId, requestTime, body, signature,
            ALIPAY_PUBLIC_KEY);
    if (!verifyResult) {
        throw new RuntimeException("Invalid notify signature");
    }

    // update the record status with notify result

    // respond the server that we accept the notify
    Result result = new Result("SUCCESS", "success", ResultStatusType.S);
    AlipayResponse response = new AlipayResponse();
    response.setResult(result);
    return ResponseEntity.ok().body(response);
}

FAQs

When will the notification be sent?

It depends on whether the payment is completed:

  • If the payment is successfully completed, Antom will usually send you an asynchronous notification within 3 to 5 seconds. For some payment methods like OTC, the notification might take a bit longer.
  • If the payment is not completed, Antom needs to close the order first before sending an asynchronous notification. The time it takes for different payment methods to close the order varies, usually defaulting to 14 minutes.
Will the asynchronous notification be re-sent?

If you receive an asynchronous notification from Antom, you are required to return the response in the Sample code format. If you do not respond to the asynchronous notification as required, or the asynchronous notification is not delivered due to network reasons, the notification will be automatically resent within 24 hours. 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.

Do I need to add a digital signature to the response?

If you receive an asynchronous notification from Antom, you are required to return the response in the Sample code format, but you do not need to add a digital signature to your response.

How do I understand the meaning of the following key fields in notifyAuthorization API?
  • result: represents the payment result of the order.
  • authState: the vaulting request ID generated by the merchant.
  • accessToken: the auto debit ID generated by Antom used for subsequent payment.
  • userLoginId: the user's desensitized account number.
How do I understand the meaning of the following key fields in nofifyPayment API?
  • result: the payment result of the order.
  • paymentRequestId: the payment request ID generated by the merchant used for querying, canceling, and reconciliation.
  • paymentId: the payment order ID generated by Antom used for refund and reconciliation.
  • paymentAmount: if there is a need for amount reconciliation, you can consume this field.

Inquire about the result

You can call the inquiryPayment API to initiate a query on the result of an order.

Parameter name

Required

Description

paymentRequestId

The payment request ID generated by you.

The parameter is not a full set of parameters, please refer to the inquiryPayment API for full set of parameters and additional requirements for certain payment methods.

The following sample code shows how to call the inquiryPayment API:

copy

AlipayClient defaultAlipayClient = new DefaultAlipayClient(EndPointConstants.SG,
                merchantPrivateKey, alipayPublicKey);

AlipayPayQueryRequest alipayPayQueryRequest = new AlipayPayQueryRequest();
alipayPayQueryRequest.setClientId(CLIENT_ID);
alipayPayQueryRequest.setPath("/ams/sandbox/api/v1/payments/inquiryPayment");

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

The following code shows a sample of the request message:

copy
{
  "paymentRequestId": "2019060811401080010018882020035****"
}

The following code shows a sample of the response message:

copy
{
  "result": {
    "resultCode": "SUCCESS",
    "resultStatus": "S",
    "resultMessage": "Success"
  },
  "paymentStatus": "SUCCESS",
  "paymentRequestId": "pay_1089760038715669_10277574507XXXX",
  "paymentId": "2019060811401080010018882020035XXXX",
  "paymentAmount": {
    "value": "4200",
    "currency": "SGD"
  },
  "paymentCreateTime": "2019-06-01T12:01:01+08:30",
  "paymentTime": "2019-06-01T12:01:01+08:30",
  "transactions": null
}

FAQs

How do I understand the meaning of the following key fields?
  • result: the result of the API call. It only indicates the result of the inquiryPayment API call. The order result should be determined based on the paymentStatus. SUCCESS and FAIL indicate final results, while PROCESSING indicates that the transaction is still in progress.
  • paymentAmount: amount verification. If there is a need for amount verification, this field can be used.
How frequently should I initiate the query?

It is recommended to initiate a round-robin query at an interval of 2 seconds until either the final payment result is retrieved or an asynchronous payment notification is received.

Sample codes

Full sample codes for front-end:

copy
// Step 1: Create the AMSEasyPayConfiguration type.
AMSEasyPayConfiguration configuration = new AMSEasyPayConfiguration();
configuration.setLocale(new Locale("en", "US"));
// Specify showLoading as true (default value) to use the default loading pattern. Specify it as false to customize the loading animation based on onEventCallback.
configuration.setOption("showLoading", "true");
// Set the sandbox environment. If you leave it empty, the production environment is used by default.
configuration.setOption("sandbox", "true");
// Center the window in landscape mode, or align it to the right if not set.
configuration.setOption("windowGravity", "LANDSCAPE_CENTER");
// Set the callback to monitor payment events on the checkout page.
configuration.setOnCheckoutListener(new OnCheckoutListener() {
    @Override
    public void onEventCallback(String eventCode, AMSEventResult eventResult) {
        if("SDK_PAYMENT_CANCEL".equals(eventCode)){
            // Add interactive prompts.
        }
        Toast.makeText(activity, "eventCode=" + eventCode + " message=" + message, Toast.LENGTH_SHORT).show();
    }
});
// Instantiate AMSEasyPay. Create a new AMSEasyPay component before each createPaymentSession API request.
AMSEasyPay checkout = new AMSEasyPay.Builder(activity, configuration).build();

// Step 2: Call createPaymentSession API.
String sessionData = createSessionData()

// Step 3: Initialize the payment and pass the sessionData to the front-end component.
checkout.createComponent(activity,sessionData);

//Step 4: Call onDestroy() method when the buyer exits the merchant page.
checkout.onDestroy(activity,sessionData);

Event codes

Status codes

Returned through the onEventCallback method during the component's runtime lifecycle, and subsequent processing can be done based on the specific event.

  • SDK_START_OF_LOADING: The loading animation starts to be shown when the component is created. When configured to hide loading and use a custom animation, the custom animation can be rendered at this time.
  • SDK_END_OF_LOADING: The loading animation ends when the component is created. When configured to hide loading and use custom animation, the animation can be hidden at this time.
  • SDK_CALL_URL_ERROR: This event code represents one of the following situations in the event information:
    • Failed to redirect to merchant page.
    • Failed to redirect to the 3D challenge page.
    • The paymentRedirectUrl parameter is not specified or is not correctly specified when calling the createPaymentSession request.

In the Web or WAP scenario, redirecting links is usually not abnormal. It is recommended that you verify the redirected link. In the app scenario, if this exception frequently occurs, contact Antom Technical Support to troubleshoot redirection or calling issues.

Error codes

Returned through the onEventCallback or onError method during the component initialization phase, and subsequent processing can be done based on the specific event.

  • SDK_INTERNAL_ERROR: SDK internal error. Contact Antom Technical Support.
  • SDK_CREATEPAYMENT_PARAMETER_ERROR: mountComponent method specified parameter abnormally. Check if the parameters are correct and reinitialize the component.
  • SDK_INIT_PARAMETER_ERROR: AMSEasyPay method specified parameter abnormally. Check if the parameters are correct and re-instantiate the SDK.
  • SDK_CREATECOMPONENT_ERROR: Component initialization exception. Contact Antom Technical Support.
  • SDK_SUBMIT_NETWORK_ERROR: Interface call failed due to network reasons. It may occur in submit method submission. Try to submit it again.