Integration for Card Payment

7. Integration for Card Payment

To integrate the SDK for a card transaction, complete the following steps:

  1. Add the SDK path in Gradle file.
  2. Add nexus repository path in Gradle file.
  3. Run the Gradle Build command.

7.1 Instantiate SDK

You can Instantiate SDK as shown in the previous section.

7.2 Initialize Payment

You can Initialize Payment as shown in the previous section.

Note: If you have subscribed for Foreign Exchange (FX) Service, the FX API is called. To get the subscription of FX, sales team/system admin.

7.3 Foreign Exchange Service

FX Service provides an omnichannel solution for facilitating the payment of products and/or services in multiple currencies. The service helps to reduce the rate of drop-offs as customers can make payment in the currency they prefer.

The SDK fetches the amount in available card currency, which enables customers to see the option to make payment in multiple currencies. The FX API is called after the initialize API is successful.

Note: FX is available for Mastercard and Visa card transactions only for customers of merchants who subscribe to this service.

The following diagram shows how to integrate FX with the assumption that the communication with Velocity backend is successful.

To retrieve all available currencies of a card, use the getForeignExchangeOffer method. To use this method, refer to the following code sample.

var  saleAmount: mPointAmountInfo = mPointAmountInfo().setCurrency(currency).setPrice(amount)

Use the following code sample to create the mPointExchangeOfferCriteria object for making payment with a new card:

var offerCriteria = mPointExchangeOfferCriteria()
                    .setOrderNumber(orderId)
                    .setCardNumber(cardnumber.toString())
                    .setCardType(cardtype)                                                  .setCountry(CountryConfig.COUNTRY_CODES.getValues()
                               .get(countryid)) 
                    .setSaleAmount(saleAmount) 
                    .setTransactionId(_mPoint.txnInfo.id)                                   .setClientId(CLIENT_ID)
                    .setAccountId(ACCOUNT_ID)
                    .setClientInfo(clientInfo)

_mPoint.getForeignExchangeOffer(offerCriteria)

To handle the response of exchange offer, override the displayForeignExchangeOffers method and implement the mPointForeignExchangeDelegate interface as follows:

override fun displayForeignExchangeOffers (offer: mPointExchangeOffer?, mpoint: mPoint?) {
}

To consume a specific mPointExchangeOffer, use this exchange offer and create mPointForeignExchangeInfo as shown in the following code sample:

  var foreignExchangeInfo 
  = mPointForeignExchangeInfo()
  .setId(offer?.foreignExchangeOfferId!!)                  
         .setExchangeAmount(offer.paymentCurrencyOffers[0]
    .exchangeAmount.price)                           .setExchangeCurrencyId(offer.paymentCurrencyOffers[0]
                                                                            .exchangeCurrency.isoNumericCode)           .setSaleCurrencyId(offer.paymentCurrencyOffers[0]
                                                                                                                                           .saleCurrency.isoNumericCode)                    .setSaleAmount(offer.paymentCurrencyOffers[0]
  .saleAmount.price)
      .setConversionRate(offer.paymentCurrencyOffers[0]
                         .offeredExchangeRate)
      .setHmac(offer.paymentCurrencyOffers[0].validationHmac)

7.4 Authorize Payment

To retrieve specific mPoint cardinfoobject, use the following method. You must provide the card number which your customer enters in the text field; it is an on-click event. This cardinfoobject gives information regarding the card type, such as Visa, Mastercard, and American Express; and maximum and minimum length of the card and card verification value (CVV) number. Based on this information, add validation and modification on your payment screen.

var cardtype = _mPoint.getCardFromPrefix(java.lang.Long.valueOf(cardNumer)!!)

7.4.1 FX Opt-in Transaction

An opt-in transaction is when a customer is making a payment with a new card and selects a card currency other than the original sale currency. The flow of an opt-in transaction is as follows:

  1. Complete the initialize payment successfully.
  2. Consume the FX API successfully.
  3. Finalize the payment offer and invoke the auth API.
  1. Customers opted to make payment in currency other than the sale currency.
  2. Send Opt-in as a Boolean flag as true.
  3. Send standard authorize parameters.

Note: The Opt-in and SetDccOpted depends on a merchant’s requirement.
Refer to Dynamic Currency Conversion to create the mPointForeignExchangeInfo object. For opt-in transactions, refer to the following code:

foreignExchangeInfo?.setDccOpted(true)

To support FX-based routing, send the service-type-id field in the foreign-exchange info node as it enables you to offer various services such as FX and PCC. Send the following ID in service-type-id field.

foreignExchangeInfo?.serviceTypeId = mPointForeignExchangeInfo.SERVICE_TYPE_ID.DCC_OPT_IN

7.4.2 FX Opt-out Transaction

In opt-out transactions, the customer has the option to make payment in available card currencies,
but chooses to make payment in the sale currency. The flow of an opt-out transaction is as follows:

  1. Complete the initialize payment successfully.
  2. Consume the FX API successfully.
  3. Finalize the payment offer and invoke the auth API.
  1. a. Customers opted to make payment using sale currency.
  2. Send Opt-in as a Boolean flag as false.
  3. Send standard authorize parameters.

Refer to Dynamic Currency Conversion to create the mPointForeignExchangeInfo object. For opt-in transactions, refer to the following code:

foreignExchangeInfo?.setDccOpted(false)

For FX opt-out transactions, send the following ID in the service-type-id field:

foreignExchangeInfo?.serviceTypeId =  mPointForeignExchangeInfo.SERVICE_TYPE_ID.DCC_OPT_OUT

7.4.3 ID Values

The values for service-type-id field ID used for a transaction are double-digit numbers - XY in which:

  • X represents the exchange service applicable for a transaction.
  • Y represents the any one of the following types of exchange:
  • 1, which means Opted
  • 2, which means Not-opted

The following table shows the possible values of service-type-id number and how it is derived.

ID (XY)Service (X)Opted (Y)
11FXOpted
12FXNot opted
41PCCOpted
42PCCNot opted

Authorize the payment for a transaction for a card by invoking the authorize method of SDK as shown in the following code sample:

mPoint.authorize(mPointAuthorizeInfo(cardtype)
.setCardNo(java.lang.Long.valueOf(cardNumer))
.setCardExpMonth(Integer.parseInt(expiryMonth))
.setCardExpYear(Integer.parseInt(expiryYear))
.setCvc(tempCvv.toString())
.setNameOnCard(cardName)
.setStoreCard(isSaveCard)
.setCardValidFromMonth(validMonth.toInt())
.setCardValidFromYear(validYear.toInt())
.setClientInfo(clientInfo)
.setAddressInfo(addressInfo))
.setForeignExchangeOffer(foreignExchangeInfo)

.setViaAuthToken(true).setPassword(authToken)

Note: The setViaAuthToken parameter is required only if the authToken parameter is sent in request.

7.4.4 Sending FX Indicator

When the FX API gives an error, a status tag is returned in handleStatus method. As per regulatory requirements, send this status code in authorize API request.
Refer to the following code sample to fetch the status codes in handleStatus method:

var additionalData: RecordMap<String, String>? = null
….
override fun handleStatus(statusInfo: mPointStatusInfo?, client: Client?, p2: mPoint?) {
runOnUiThread {
if(statusInfo.statuses.size > 0 && statusInfo.statuses[0].containsKey("status")){
    val status = statusInfo.statuses[0]["status"] as RecordMap<*, *>
    val code : String = status["@code"] as String
additionalData = RecordMap()
    additionalData!!["cfx_status_code"] = code
}
 	   }
}

Refer to the following code sample to send FX indicator in authorize API request:

_mPoint.authorize(mPointAuthorizeInfo(cardtype)
.setCardNo(java.lang.Long.valueOf(cardNumer))
.setCardExpMonth(Integer.parseInt(expiryMonth))
.setCardExpYear(Integer.parseInt(expiryYear))
.setCvc(tempCvv.toString())
.setNameOnCard(cardName)
.setStoreCard(isSaveCard)
.setCardValidFromMonth(validMonth.toInt())
.setCardValidFromYear(validYear.toInt())
.setClientInfo(clientInfo)
.setAddressInfo(addressInfo))
.setForeignExchangeOffer(foreignExchangeInfo)
.addAdditionalData(additionalData))
.setViaAuthToken(true).setPassword(authToken)

Note: The setViaAuthToken parameter is required only if the authToken parameter is sent in request.

7.5 3DS Redirection

Implement the displayWebView method for 3DS redirection. This method generates a one-time password for a card transaction and provides a WebView instance. 3DS provides an additional layer of security.
The displayWebView method is used in all types of payment such as a stored card, wallet, and APM.

Note: Implementing 3DS redirection depends on the PSP you select for conducting transactions.

override fun displayRaw3DSecureChallenge(mpoint: mPoint): WebView

7.6 Instalments

Customers can use the Instalments feature to make payment in instalments, which is payable in set intervals over a defined period. To add support for card payment with instalments, implement the mPointGetInstallmentPlansDelegate interface.

After customers enter the 11-digit card number, call the getInstallmentPlans API to fetch the available instalment plans for that card shown as follows:

var cardNumber : Long
var cardInfo : mPointCardInfo
cardInfo = _mPoint.getCardFromPrefix(cardNumber)

val installmentPlansSearchCriteria = mPointInstallmentPlansSearchCriteria()
installmentPlansSearchCriteria.binNumber = cardNumber 
installmentPlansSearchCriteria.cardInfo = cardInfo
_mPoint.getInstallmentPlans(installmentPlansSearchCriteria)

To receive result for the getInstallmentPlans API, call in the previous code sample and implement the mPointGetInstallmentPlansDelegate method. The result is returned in the following method:

override fun displayInstallmentPlans(arrListInstallments: java.util.ArrayList<String>?, p1: mPoint?) {
}

Note: The arrListInstallments parameter contains the list of all the Instalment Plans that are available. Populate this data in a drop-down widget so that a customer can select an instalment plan.

To pass the value of the selected instalment, send it in the authorize API in the setInstallmentValue(installmentValue) parameter as shown in the following code sample:

var installmentValue : String  // The Selected Installment Plan

_mPoint.authorize(mPointAuthorizeInfo(cardInfo)
.setCardNo(java.lang.Long.valueOf(cardNumer))
.setCardExpMonth(Integer.parseInt(expiryMonth))
.setCardExpYear(Integer.parseInt(expiryYear))
.setCvc(tempCvv.toString())
.setNameOnCard(cardName)
.setStoreCard(isSaveCard)
.setCardValidFromMonth(validMonth.toInt())
.setCardValidFromYear(validYear.toInt())
.setClientInfo(clientInfo)
.setForeignExchangeOffer(foreignExchangeInfo)
.setViaAuthToken(true)
.setPassword(authToken)
.setAddressInfo(addressInfo)
.addAdditionalData(additionalData)
.setInstallmentValue(installmentValue))

7.7 Split Payment

The split payment option allows customers to split the payment into equal amounts or to enter amounts to split the payment. To allow split payments, you need to check initialize payment response. If a split payment is available, you get split payment node in the response with all required details. You need to read the details from the initialize-payment response. See func override fun displayAvailablePayments(availablePayments: mPointAvailablePayments?, mpoint: mPoint?) {} for how to read split payment node.

After you read the split payment node as shown in above method, you have an array of split payment combinations of type mPointSplitCombination. Store that array for later use. It is the responsibility of the front end to give a UI which provides the customer a toggle switch to choose to split a payment or not. The front end also has to filter and select an appropriate combination object from the combinations array to perform a split payment transaction using the appropriate payment type.

The table below lists the payment type IDs for various form of payments.

Payment methodPayment Type ID
Card1
Voucher2
Wallet3
APM4

The following options are currently available combinations to perform split payment:

  • Card + Card
  • Voucher + Card
  • Voucher + APM
  • Voucher + Wallet

The combination object has an array of mPointSplitPaymentType which includes payment type ID, sequence, and a boolean property is_one_step_authorization. To perform a split payment with Card + Card,

the front end needs to filter and send a combination object with Payment Type ID as 1 for both the sequences. Similarly, the front end needs to filter and send an appropriate combination object in the authorize request to perform a split payment with other forms of payments.

The is_one_step_authorization property has an important role to play in a split payment ecosystem. If is_one_step_authorization value is true, the authorize request needs to include details of both forms of payment. If it is false, the authorize request needs to be called separately for both forms of payment.

After the completion of the first authorize request, the front end needs to call getTxnStatus api, from override fun displayPaymentConfirmation(txn: mPointTxnInfo?, code: Int, mpoint: mPoint) {} method. The response is returned in handleTxnStatus method shown below. If the is_one_step_authorization value is true, you need to poll getTxnStatus api until it returns a success or failure. If value of is_one_step_authorization is false, you need to read the pending amount from the response and make an initialise payment request with that pending amount and session ID.

Refer to the below sample code sample to understand how to call authorize, getTxnStatus and initialise methods.

Note: This code sample is taken from our application to give you an idea of how to integrate or call any given method on mPoint SDK. You need to implement your own classes wherever required.

The code show below is a sample of the calling authorize with split payment method with Card + Card.

var mPointSplitCombination: mPointSplitCombination? = null
var priceInfo: PriceInfo? = null
 
for(splitCombination in this.splitPayment!!.splitCombinations){
    for(paymentType in splitCombination.paymentType){
        if(paymentType.id == mPointCardInfo.PAYMENT_TYPES.CARD.id ){
            mPointSplitCombination = splitCombination
        }
    }
}
 
 
priceInfo = PriceInfo(getCountryCode(country),
                    (((tempAmount.toFloat()) * getDecimalPointMultiplierFromCurrencyId(currencyCode)).roundToLong()),
                    null, null, null, currencyCode,  -1)
                    
                                       
if(null != mPointSplitCombination && null != priceInfo && isSplit){
        _mPoint.authorize(mPointAuthorizeInfo(cardtype)
            .setClientInfo(clientInfo)
            .setViaAuthToken(true)
            .setPassword(authToken)
            .setCardNo(java.lang.Long.valueOf(cardNumer))
            .setCardExpMonth(Integer.parseInt(expiryMonth))
            .setCardExpYear(Integer.parseInt(expiryYear))
            .setCvc(tempCvv).setNameOnCard(cardName)
            .setStoreCard(isSaveCard)
            .setCardValidFromMonth(validMonth.toInt())
            .setCardValidFromYear(validYear.toInt())
            .setForeignExchangeOffer(foreignExchangeInfo)
            .setAddressInfo(addressInfo)
            .addAdditionalData(additionalData)
            .setInstallmentValue(installmentValue)
            .setPendingSplitAmount(priceInfo)
            .setSplitCombinations(mPointSplitCombination))
}               

7.8 Payment Confirmation

Implement the displayPaymentConfirmation call back method to receive the transaction status as shown in the following code sample:

Implement the displayPaymentConfirmation call back method to receive the transaction status as shown in the following code sample:

When using the split payment option, after getting callback in displayPaymentConfirmation you need to call getTxnStatus method to retrieve status of the transactions. When calling the getTxnStatus pass session ID (available in mPoint class) to retrieve all transactions from the current session. To call getTxnStatus, use the following code sample:

if(isSplitPaymentApplicable){
    	if(mpoint!!.sessionId != null && mpoint.sessionId.isNotEmpty()){
   		mPoint.delegate = this
              mPoint.getTxnStatus(-1, "", mpoint.sessionId, clientInfo)
  	  }
}

To get transaction statuses response implement following delegate method:

override fun handleTxnStatus(arrListTxnStatusInfo: ArrayList<mPointTxnStatusInfo>?, paymentStatus: Int, arrListLinkedTransactions: ArrayList<mPointLinkedTransactions>?, mPoint: mPoint?) {
 
            runOnUiThread {
                var pendingAmount: Long = 0
 
                if(null != arrListTxnStatusInfo && arrListTxnStatusInfo.size > 0){
                    for (txnStatusInfo : mPointTxnStatusInfo in arrListTxnStatusInfo){
                        // Retrieve Pending Amount
                        pendingAmount = txnStatusInfo.pendingAmount
                    }
                }
 
                when (paymentStatus) {
                    com.cellpointmobile.sdk.mPoint.PAYMENT_STATUS.MPOINT_PAYMENT_STATUS_PENDING.id -> 
                    // Poll getTxnStatus()
                    getTxnStatus(mPoint!!.sessionId)
                    com.cellpointmobile.sdk.mPoint.PAYMENT_STATUS.MPOINT_PAYMENT_STATUS_COMPLETE.id -> {
                        if(pendingAmount == 0L)
                            // Split Payment Successful
                        else
                            // Retry Payment with Pending Amount
                    }
                    com.cellpointmobile.sdk.mPoint.PAYMENT_STATUS.MPOINT_PAYMENT_STATUS_FAILED.id -> {
                        // Retry Payment with Pending Amount
                    }
                }
            }
    }               

The merchant front end reads the response received to know the payment status. Read the paymentStatus parameter to know the status of the payment. If a transaction status has payment status as:

  • Pending: call the getTxnStatus API again until you get the payment status either as Successful or Failed.
  • Complete: the payment is successful.
  • Failed: retry the payment.

To retry the payment, initialize the payment with the pending amount. This action helps a customer complete the payment using any option.

Send the pending amount you received from back end in the initialize request. After you initialize, a customer can complete the payment using any available payment option or can split the payment. This process repeats until the transaction is successful, fails, or maximum retries are attempted.

Note: If a customer decides not to retry a failed payment, call the Post-Status API as shown in the following code sample to notify that the session is complete:

mPoint.postStatus(mPoint.sessionId)

7.9 Handle Error

A handle error occurs when there an error in parsing. The status code reveals the type of error that has occurred in the SDK. For details of the status code, refer to Status Codes.

override fun handleError(errorInfo: mPointErrorInfo, client: Client, mpoint: mPoint) {}

7.10 Handle Status

The status codes are returned by the SDK in a call back to the handleStatus method. The method enables the application to handle the status appropriately by implementing the method as shown in the following code sample:

The handleStatus method shows an error in the CPD server.

if(isSplitPaymentApplicable){
    if(statusInfo!!.sessionId != null && statusInfo.sessionId.isNotEmpty()){
   	
        mPoint.delegate = this
  mPoint.getTxnStatus(-1, "", statusInfo.sessionId, clientInfo)

  	  }
}
To get transaction statuses response implement handleTxnStatus delegate method and repeat the same steps as mentioned above in handleTxnStatus method.