Skip to main content

Android Native SDK- Merchant's Checkout

SDK Integration prerequisites#

  1. In build.gradle (:app), add the PortOne SDK as a dependency.

    implementation 'com.github.iamport-intl:chaipay-android-native-sdk:V3.0.27'
  2. Add the PortOne authorization key to gradle.properties.

    //Auth Token will be provided by the PortOne Team
    authToken=XXXXXXXXXXXXXXXXXXXXXX
  3. To access the library, add the following snippets to build.gradle (:Project) or settings.gradle.

    repositories {
    maven { url '<https://maven.google.com/>' }
    maven{
    url '<https://jitpack.io>'
    credentials { username authToken }
    }
    }
  4. To access the library, add the following snippets to build.gradle (:Project).

    buildscript {
    ext.kotlin_version = "1.5.10"
    dependencies {
    classpath 'com.google.gms:google-services:3.0.0'
    }
    }
  5. To access checkout methods, initialize the PortOne instance in your checkout activity. You will also require to pass the environment

    private lateinit var portone: PortOne
    private var environment = sandbox // Sandbox || Live
    portone = PortOneImpl(this, "$environment")
  6. Add the following Intent Filter to the Activity to which you want the user to be directed after payment completion. Checkout Activity should be the default. The parameters 'host' and 'scheme' in the data tag will be set according to the redirection url.

    redirectionUrl= **portone://checkout**
    then the host will be **checkout** and the scheme will be **portone**
    <data
    android:host="checkout"
    android:scheme="portone" />
    <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data
    android:host="$host"
    android:scheme="$scheme" />
    </intent-filter>

Checkout#

  1. Make a signature hash to include in the payload.

    internal fun getSignatureHash(
    amount: String,
    currency: String,
    failureUrl: String,
    orderId: String,
    clientKey: String,
    successUrl: String
    ): String {
    val hashMap: HashMap<String, String> = HashMap()
    hashMap["amount"] = amount
    hashMap["currency"] = currency
    hashMap["failure_url"] = failureUrl
    hashMap["merchant_order_id"] = orderId
    hashMap["client_key"] = clientKey
    hashMap["success_url"] = successUrl
    val message = StringBuilder()
    for ((key, value) in hashMap.toSortedMap().entries) {
    val values = URLEncoder.encode(value, "UTF-8")
    if (message.isNotEmpty()) {
    message.append("&$key=$values")
    } else {
    message.append("$key=$values")
    }
    }
    val sha256 = Hashing.hmacSha256(SECRET_KEY.toByteArray(StandardCharsets.UTF_8))
    .hashString(message, StandardCharsets.UTF_8).asBytes()
    val base64: String = Base64.encodeToString(sha256, Base64.DEFAULT)
    Log.i(TAG_CHAI_PAY, "SignatureHash:base64-> $base64")
    return base64.trim()
    }

    Payment Request | PortOne

  1. The methods listed below are explained using examples.

    //To get Available Payment Methods
    portone.getPaymentMethods(RequestBodies.clientKey, RequestBodies.currency, object :
    ApiCallbackInterface<PaymentDto.PaymentMethodResponse> {
    override fun onSucceed(response: PaymentDto.PaymentMethodResponse) {
    LoggerUtil.info("Successful")
    }
    override fun onFailure(
    errorCode: Int?,
    status: String?,
    errorMessage: String,
    throwable: Throwable
    ) {
    LoggerUtil.info("Failed")
    }
    })
    //To get the Otp (MobileNumber=CountryCode+Number)
    portone.getOTP($mobileNo, object :
    ApiCallbackInterface<PaymentDto.OtpResponse> {
    override fun onSucceed(response: PaymentDto.OtpResponse) {
    LoggerUtil.info("Successful")
    }
    override fun onFailure(
    errorCode: Int?,
    status: String?,
    errorMessage: String,
    throwable: Throwable
    ) {
    LoggerUtil.info("Failed")
    }
    })
    //To get the saved crads
    // Token is not a mandatory param
    portone.getSavedCards($token, RequestBodies.clientKey, $mobileNo, $otp, object :
    ApiCallbackInterface<PaymentDto.CreditCardDetailsResponse> {
    override fun onSucceed(response: PaymentDto.CreditCardDetailsResponse) {
    LoggerUtil.info("Successful")
    }
    override fun onFailure(
    errorCode: Int?,
    status: String?,
    errorMessage: String,
    throwable: Throwable
    ) {
    LoggerUtil.info("Failed")
    }
    })
    //To Initiate Checkout Without Tokenization
    val checkoutRequest= PaymentDto.CheckoutWithoutTokenizationRequest()
    portone.checkoutWithoutTokenization(checkoutRequest)
    //To Initiate Checkout Using Tokenization
    val checkoutRequest= PaymentDto.CheckoutUsingTokenizationRequest()
    portone.initiatePaymentWithTokenization(checkoutRequest)
    //To Initiate Checkout Using New Credit Card
    val checkoutRequest= PaymentDto.CheckoutUsingTokenizationRequest()
    val newCard= PaymentDto.NewCard()
    portone.checkoutUsingNewCreditCard(
    paymentDetails = checkoutRequest,
    newCard = newCard
    )
    //To Fetch the Bank List with Details
    portone.getBankList(
    RequestBodies.paymentChannel,
    RequestBodies.getBankListRequest(),
    object : ApiCallbackInterface<PaymentDto.BankListResponse> {
    override fun onSucceed(response: PaymentDto.BankListResponse) {
    LoggerUtil.info("Successful")
    }
    override fun onFailure(
    errorCode: Int?,
    status: String?,
    errorMessage: String,
    throwable: Throwable
    ) {
    LoggerUtil.info("Failed")
    }
    })
    //To fetch the direct Bank Transfer Details
    portone.getDBTDetails(RequestBodies.clientKey,
    object : ApiCallbackInterface<PaymentDto.DBTResponse> {
    override fun onSucceed(response: PaymentDto.DBTResponse) {
    LoggerUtil.info("Successful")
    }
    override fun onFailure(
    errorCode: Int?,
    status: String?,
    errorMessage: String,
    throwable: Throwable
    ) {
    LoggerUtil.info("Failed")
    }
    })
  2. The app needs to obtain its payment status following checkout, which must be handled using intent, and it will give that state to the updatePaymentStatus() method.

    if (null != intent && null != intent.data) {
    val paymentStatus = intent.data.toString()
    portone.updatePaymentStatus(paymentStatus)
    }
  3. To receive the checkout status in HashMap format after the checkout action has been completed, the following method must be added to the checkout activity.

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (resultCode == RESULT_CODE && data != null) {
    when (requestCode) {
    PAYOUT_REQUEST_CODE, PAYMENT_STATUS_REQUEST_CODE -> {
    val paymentStatus: PaymentDto.PaymentStatus? =
    (data.getSerializableExtra(PAYMENT_STATUS)
    ?: "Empty") as PaymentDto.PaymentStatus
    }
    }
    }
    }
  4. Things to be taken care while generating payload:

    1. Mandatory params in payload:

      price
      promo_discount (0 is also acceptable)
      shipping_charges (0 is also acceptable)
    2. If items are provided, please double-check that the values match the total amount: sum(items price * items quantity) + shipping charge - discount = amount


Merchant Centric Card Vault#

  • The following functions can be used once a user has been created and has access to this feature.

    //For adding card for a customer
    val newCard= PaymentDto.NewCard()
    portOne.addCardForCustomer(
    customerUUID,
    jwtToken,
    clientKey,
    newCard,
    object : ApiCallbackInterface<PaymentDto.AddCardsResponse> {
    override fun onSucceed(response: PaymentDto.AddCardsResponse) {
    LoggerUtil.info("Successful")
    }
    override fun onFailure(
    errorCode: Int?,
    status: String?,
    errorMessage: String,
    throwable: Throwable
    ) {
    LoggerUtil.info("Failed")
    }
    })
    //Get the list of Customer for a customer
    portOne.listCardsForCustomer(
    customerUUID,
    JwtToken,
    clientKey,
    object : ApiCallbackInterface<PaymentDto.ListCardsForCustomerResponse> {
    override fun onSucceed(response: PaymentDto.ListCardsForCustomerResponse) {
    LoggerUtil.info("Successful")
    }
    override fun onFailure(
    errorCode: Int?,
    status: String?,
    errorMessage: String,
    throwable: Throwable
    ) {
    LoggerUtil.info("Failed")
    }
    })
    // Delete a Card for Customer
    portOne.deleteCardForCustomer(
    customerUUID,
    jwtToken,
    clientKey,
    PaymentDto.DeleteCardRequest(cardToken),
    object : ApiCallbackInterface<PaymentDto.GenericResponse> {
    override fun onSucceed(response: PaymentDto.GenericResponse) {
    LoggerUtil.info("Successful")
    }
    override fun onFailure(
    errorCode: Int?,
    status: String?,
    errorMessage: String,
    throwable: Throwable
    ) {
    LoggerUtil.info("Failed")
    }
    })

Failover Routing#

  • The Request Model introduces the following two parameters to support failover routing:

    1. isRoutingEnabled= true

    2. Routing Param type should be failover.

    3. Pass the Routing Ref which is set in the merchnat portal.

      val paymentDetails = PaymentDto.CheckoutUsingTokenizationRequest()
      paymentDetails.isRoutingEnabled= true // true || false
      paymentDetails.routingParams= PaymentDto.RoutingParams(type = "failover", routeRef)
      // To Fetch the List of Routes which are created from merchant portal
      portOne.getRoutesList(
      jwtToken,
      clientKey,
      object : ApiCallbackInterface<PaymentDto.RoutesListResponse> {
      override fun onSucceed(response: PaymentDto.RoutesListResponse) {
      LoggerUtil.info("Successful")
      }
      override fun onFailure(
      errorCode: Int?,
      status: String?,
      errorMessage: String,
      throwable: Throwable
      ) {
      LoggerUtil.info("Failed")
      }
      })

PreAuth and Capture Payment#

  • To implement PreAuth one parameter has to be set: transactionType= PREAUTH || PURCHASE

    val paymentDetails= PaymentDto.CheckoutUsingTokenizationRequest()
    paymentDetails.transactionType= "PREAUTH"
    // To Capture the Payment
    portOne.captureTransaction(
    orderRef,
    clientKey,
    jwtToken,
    object : ApiCallbackInterface<PaymentDto.GenericResponse> {
    override fun onSucceed(response: PaymentDto.GenericResponse) {
    LoggerUtil.info("Successful")
    }
    override fun onFailure(
    errorCode: Int?,
    status: String?,
    errorMessage: String,
    throwable: Throwable
    ) {
    LoggerUtil.info("Failed")
    }
    })

Example Integration:#

https://github.com/iamport-intl/chaiport-android-sdk-merchant-demo-app