Skip to content

Tap-Payments/CheckoutSDK-Android

Repository files navigation

CheckoutSDK-Android

Tap payments provides for you a one drop solution to enable a seamless checkout process in your android app flow.

Platform Documentation SDK Version SDK Version

Access all local, regional, & global payment methods

Your customers can scale globally by offering all popular payment methods across MENA, whether that's mada, KNET, Fawry, Apple Pay, Visa, Mastercard, Amex, Tabby, and many more.

Look at it!

Table of Contents


  1. Requirements

  2. Installation with jitpack

  3. PRE SDK Setup

    1. Important Information
  4. SDK SETUP

    1. Configure SDK Session
    2. Configure SDK Transaction Mode
    3. Use Tap PayButton
    4. List Saved Cards
    5. Open SDK Interfaces
    6. Open SDK ENUMs
    7. Open SDK Models
  5. CheckOut Delegate

    1. Payment Success Callback
    2. Payment Failure Callback
    3. Authorization Success Callback
    4. Authorization Failure Callback
    5. Card Saving Success Callback
    6. Card Saving Failure Callback
    7. Card Tokenized Success Callback
    8. Saved Cards List Callback
    9. Session Other Failure Callback
    10. Invalid Card Details
    11. Backend Un-known Error
    12. Invalid Transaction Mode
    13. Session Is Starting Callback
    14. Session Has Started Callback
    15. Session Failed To Start Callback
    16. Session Cancel Callback
    17. User Enabled Save CARD
  6. Documentation

Requirements


To use the SDK the following requirements must be met:

  1. Android Studio 3.4 or newer
  2. Android SDK Tools 29 or newer
  3. Android Platform Version: API 29: Android 10 revision 6 or later
  4. Android targetSdkVersion: 31
  5. Android minSdkVersion: 22
  6. Android compileSdkVersion: 31

Installation with JitPack


JitPack is a novel package repository for JVM and Android projects. It builds Git projects on demand and provides you with ready-to-use artifacts (jar, aar).

To integrate checkoutSDk into your project add it in your root build.gradle at the end of repositories:

	allprojects {
		repositories {
			...
                        jcenter()
			maven { url 'https://jitpack.io' }
		}
	} 
   
}

or in new dependencies :

      dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
    repositories {
        google()
        mavenCentral()
        jcenter()
        maven { url 'https://www.jitpack.io' }


    }

Step 2. Add the dependency

	dependencies {
	        implementation 'com.github.Tap-Payments:CheckoutSDK-Android:Tag'
	}

Step 3. in gradle.properties

      android.useAndroidX=true
      kotlin.code.style=official
      android.nonTransitiveRClass=true
      android.enableJetifier=true

PRE SDK SETUP


If you already have a Tap account, please skip this part.

In order to be able to use the SDK, you have to create a Tap account first. Once you finish your account with our Integration team, please make sure they provided you with the following:

  1. Your sandbox public key.
    1. This will be used to perform testing transactions in our sandbox environment. Will be useful for you in your development phase.
  2. Your production public key.
    1. This will be used to perform actual transactions in our production environment. Will be required for you before releasing your application.
  3. Your tap merchant id.
    1. This will be used as an identifier for the app entity under your Tap account. As you can have multiple apps/websites integrated with Tap under your same Tap account.

Important Information

Supported languages

  1. English.
  2. Arabic.

Supported themes

The sdk auto detects the device's display mode light or dark and displays itself accordingly.

  1. Light mode.
    1. The Checkout SDK will be displayed in light mode and icons will be colored.
  2. Light mode with mono color.
    1. The Checkout SDK will be displayed in light mode and icons will be monochromatic.
  3. Dark mode.
    1. The Checkout SDK will be displayed in dark mode and icons will white.
  4. Dark mode with colors.
    1. The Checkout SDK will be displayed in dark mode and icons will be colored.

Supported SDK modes

  1. Sandbox
    1. Where you can try all different payment methods with no limits and no charges will occur.
    2. Check this for our Testing Cards
  2. Production
    1. Where you can try all different payment methods for real to memic your expected customers' experience. Please note, this will require using real data will incur charges.

Supported transaction modes

  1. Purchase
    1. To be used when you want to deduct the amount from your customer.
  2. Authourize
    1. To be used when you want to hold the amount from your customer.

SDK SETUP


Global variables setup

These variables to be set before starting the Checkout SDK. This will define important parameters for configuring and theming the Checkout SDK itself. Please note, missing to configure these will end up in using default values or the Checkout SDK will throw an error as it cannot start.

  1. The required localisation.
    1. By this you define which language you want the Checkout SDK appears with.
    2. Now we do support: en & ar.
    3. Default value if not set is : en.
       LocalizationManager.setLocale(this, Locale("en"))
    4. If you wish to have your custom locale it can be added as below:
         LocalizationManager.loadTapLocale(resources, R.raw.defaulttaplocalisation)
  2. The required Tap keys.
    1. By this, you define your Tap keys so the sdk can identify you as a merchant.
    2. These are required.
    3. How to set it:
      To set it up, add the following line of code somewhere in your project and make sure it will be called before any usage of checkOutSDK, otherwise an exception will be thrown. Required.
        /**
         * Required step.
         * Configure SDK with your Secret API key and App Bundle name registered with tap company.
         */
        private fun initializeSDK(){
       TapCheckOutSDK.init(this, "pk_kXXXXXXXXXXXXXXXXXXXXXXXX", "pk_XXXXXXXXXXXXXXXXXXXXXXXX", "app_id")  // to be replaced by merchant, you can contact tap support team to get you credentials
        }
  1. authToken - to authorize your requests.// Secret key (format: "pk_XXXXXXXXXXXXXXXXXXXXXXXX")
  2. app_id - replace it using your application ID "Application main package".

Don't forget to import the class at the beginning of the file:

Java:

import company.tap.checkout.TapCheckOutSDK;

Kotlin:

import company.tap.checkout.TapCheckOutSDK
  1. Optional theme variables:
    1. Display mono variant when showing the Light mode theme
      1. If not passed default value is false
      2. How to set it : TapCheckout.displayMonoLight = false
    2. Display colorized variant when showing the Dark mode theme
      1. If not passed default value is false
      2. How to set it : TapCheckout.displayColoredDark = false
    3. If you wish to setup your custom theme , you can do it as below : Kotlin:
ThemeManager.loadTapTheme(resources, R.raw.defaultlighttheme, "lighttheme")

or

 ThemeManager.loadTapTheme(this, urlString)

Configure SDK With Required Data

checkOutSDK should be set up. To set it up, add the following lines of code somewhere in your project and make sure they will be called before any usage of checkOutSDK. Kotlin:

         /**
         * Integrating the SDK
         */

        /**
         * Required step.
         * Configure SDK Session with all required data.
         */
            configureSDKSession()
            
            
         /**
         * If you included Tap Pay Button then configure it first, if not then ignore this step.
         */
            initActionButton()

Below is the list of properties in checkOutSDK class you can manipulate. Make sure you do the setup before any usage of the SDK.

Configure SDK Session

SDKSession is the main interface for checkOutSDK library from you application, so you can use it to start SDK with pay button or without pay button.

Properties

Property Type Description
payButton PayButton Pay Button can be used to start SDK
paymentDataSource PaymentDataSource Payment data source. All input payment information is passed through this protocol. Required.
activityListener Activity Activity. used as a context to setup sdk.
checkOutDelegate Activity Activity. it is used to notify Merchant application with all SDK Events

Methods

Property Type
addSessionDelegate pass your activity that implements CheckOutDelegate interface . you have to override all methods available through this interface
instantiatePaymentDataSource Payment Data Source Object is the main object that is responsible of holding all data required from our backend to return all payment options [ Debit Cards - Credit Cards ] available for this merchant .
setTransactionCurrency Set the transaction currency associated to your account. Transaction currency must be of type TapCurrency("currency_iso_code"). i.e new TapCurrency("KWD")
setTransactionMode SDK offers different transaction modes such as [ TransactionMode.PURCHASE - TransactionMode.AUTHORIZE_CAPTURE]
setCustomer Pass your customer data. Customer must be of type Tap Customer. You can create Tap Customer as following TapCustomer( "cust_id", "cust_firstname", "cust_middlename", "cust_lastname", "cust_email", PhoneNumber("country_code", "MobileNo"), "metdata", )
setAmount Set Total Amount. Amount value must be of type BigDecimal i.e new BigDecimal(40)
setPaymentItems ArrayList that contains payment items. each item of this array must be of type PaymentItem. in case of SAVE_CARD or TOKENIZE_CARD you can pass it null
setTaxes ArrayList that contains Tax items. each item of this array must be of type Tax. in case of SAVE_CARD or TOKENIZE_CARD you can pass it null
setShipping ArrayList that contains Shipping items. each item of this array must be of type Shipping. in case of SAVE_CARD or TOKENIZE_CARD you can pass it null
setPostURL POST URL.
setPaymentDescription Payment description.
setPaymentMetadata HashMap that contains any other payment related data.
setPaymentReference Payment reference. it must be of type Reference object or null
setPaymentStatementDescriptor Payment Statement Description
isRequires3DSecure Enable or Disable 3D Secure
setReceiptSettings Identify Receipt Settings. You must pass Receipt object or null
setAuthorizeAction Identify AuthorizeAction. You must pass AuthorizeAction object or null
setDestination Identify Array of destination. You must pass Destinations object or null
start Start SDK Without using Tap Pay button. You must call this method where ever you want to show TAP Payment screen. Also, you must pass your activity as a context
setButtonView If you included TAP PayButton in your activity then you need to configure it and then pass it to SDKSession through this method.
setDefaultCardHolderName Sets default CardHoldername in the field, without the user need to re-type.(OPTIONAL)
isUserAllowedToEnableCardHolderName Lets default CardHoldername in the field,can be editable or not based on user configuration .(OPTIONAL)
sdkSession.cancelSession(this); Merchant can now cancel the session and stop all process initiating the SDK. .(OPTIONAL)
setTopUp Merchant can now send a topUp object while initiating the SDK. .(OPTIONAL)
**Configure SDK Session Example**

Kotlin:

 // pass your activity as a session delegate to listen to SDK internal payment process follow
        sdkSession.addSessionDelegate(this) //** Required **
        
        // initiate PaymentDataSource
        sdkSession.instantiatePaymentDataSource() //** Required **


        // set transaction currency associated to your account

        sdkSession.setTransactionCurrency(TapCurrency("KWD")) //** Required **


        // Using static CustomerBuilder method available inside TAP TapCustomer Class you can populate TAP TapCustomer object and pass it to SDK
        sdkSession.setCustomer(setCustomer()) //** Required **


        // Set Total Amount. The Total amount will be recalculated according to provided Taxes and Shipping

        settingsManager?.getString("key_amount_name", "1")?.let { BigDecimal(it) }?.let {
            sdkSession.setAmount(
                    it
            )
        }//** Required **


        // Set Payment Items array list
        sdkSession.setPaymentItems(getPaymentItems()) // ** Optional ** you can pass empty array list


        sdkSession.setPaymentType("ALL")  //** Merchant can pass paymentType

        // Set Taxes array list
        sdkSession.setTaxes(ArrayList()) // ** Optional ** you can pass empty array list


        // Set Shipping array list
          sdkSession.setShipping(settingsManager?.getShippingList()) // ** Optional ** you can pass empty array list

        // Post URL
        sdkSession.setPostURL("") // ** Optional **


        // Payment Description
        sdkSession.setPaymentDescription("") //** Optional **

        // Payment Extra Info
        sdkSession.setPaymentMetadata(HashMap()) // ** Optional ** you can pass empty array hash map

        // Payment Reference
        sdkSession.setPaymentReference(null) // ** Optional ** you can pass null

        // Payment Statement Descriptor
        sdkSession.setPaymentStatementDescriptor("") // ** Optional **


        // Enable or Disable Saving Card
        sdkSession.isUserAllowedToSaveCard(true) //  ** Required ** you can pass boolean


        // Enable or Disable 3DSecure
        sdkSession.isRequires3DSecure(true)

        //Set Receipt Settings [SMS - Email ]
        sdkSession.setReceiptSettings(
                Receipt(
                        false,
                        false
                )
        ) // ** Optional ** you can pass Receipt object or null


        // Set Authorize Action
        sdkSession.setAuthorizeAction(null) // ** Optional ** you can pass AuthorizeAction object or null


      //  sdkSession.setDestination(settingsManager?.getDestination()) // ** Optional ** you can pass Destinations object or null
       sdkSession.setDestination(null) // ** Optional ** you can pass Destinations object or null


        sdkSession.setMerchantID("xxxxx") // ** Optional ** you can pass merchant id or null


        sdkSession.setCardType(CardType.ALL) // ** Optional ** you can pass which cardType[CREDIT/DEBIT] you want.By default it loads all available cards for Merchant.

         settingsManager?.getTransactionsMode("key_sdk_transaction_mode")?.let {
            sdkSession.setTransactionMode(
                    it
            )
        }

        sdkSession.setDefaultCardHolderName("TEST TAP"); // ** Optional ** you can pass default CardHolderName of the user .So you don't need to type it.
        sdkSession.isUserAllowedToEnableCardHolderName(false) // ** Optional ** you can enable/ disable  default CardHolderName .
        sdkSession.setSdkMode(SdkMode.SAND_BOX) //** Pass your SDK MODE

Configure SDK Transaction Mode

You have to choose only one Mode of the following modes: PURCHASE , AUTHORIZE_CAPTURE

Note:- - In case of using PayButton, then don't call sdkSession.startSDK(fragmentManager,this,this) because the SDK will start when user clicks the tap pay button.

If you included Tap Pay Button then configure it first, if not then ignore this step.

Use Tap PayButton

Kotlin:

      /**
        * Include pay button in merchant page
        */
          private fun initActionButton() {
          payButton.setButtonDataSource(
              true,
              this.let { LocalizationManager.getLocale(it).language },
              LocalizationManager.getValue("pay", "ActionButton"),
              Color.parseColor(ThemeManager.getValue("actionButton.Valid.paymentBackgroundColor")),
              Color.parseColor(ThemeManager.getValue("actionButton.Valid.titleLabelColor"))
      )

      sdkSession.setButtonView(payButton, this, supportFragmentManager, this)


  }

To populate TAP Customer object

Kotlin:

   fun setCustomer(): TapCustomer { 
        val tapCustomer: TapCustomer? = null
        return TapCustomer(
                "cus_TSxxxxxxxxxxxxx", "firstname", "middlename",
                "lastname", "abcd@gmail.com",
                PhoneNumber("00965", "xxxxxxxx"), "description-metadata",
        )

    }

SDKSession Payment Data Source

PaymentDataSource is an interface which you should implement somewhere in your code to pass payment information in order to be able to access payment flow within the SDK.

Structure

The following table describes its structure and specifies which fields are required for each of the modes.

Member Type Required Description
Android Purchase Authorize Card Saving
mode TransactionMode false Mode of the transactions (purchase or authorize). If this property is not implemented, purchase mode is used.
customer Customer true Customer information. For more details on how to create the customer, please refer to Customer class reference.
currency Currency truefalse Currency of the transaction.
amount BigDecimal false Payment/Authorization amount.
Note: In order to have payment amount either amount or items should be implemented. If both are implemented, items is preferred.
items ArrayList [PaymentItem] false List of items to pay for.
Note: In order to have payment amount either amount or items should be implemented. If both are implemented, items is preferred.
taxes ArrayList [Tax] false You can specify taxation details here. By default, there are no taxes.
Note: Specifying taxes will affect total payment/authorization amount.
shipping ArrayList [Shipping] false You can specify shipping details here. By default, there are no shipping details.
Note: Specifying shipping will affect total payment/authorization amount.
postURL String false The URL which will be called by Tap system notifying that payment has either succeed or failed
paymentDescription String false Description of the payment.
paymentMetadata String false Additional information you would like to pass along with the transaction.
paymentReference Reference false You can keep a reference to the transaction using this property
paymentStatementDescriptor String false Statement descriptor.
require3DSecure Boolean false Defines if 3D secure check is required. If not implemented, treated as true.
Note: If you disable 3D secure check, it still may occure. Final decision is taken by Tap
receiptSettings Receipt false Receipt recipient details.
authorizeAction AuthorizeAction falsetruefalse Action to perform after authorization succeeds.

SDK Open Interfaces

SDK open Interfaces available for implementation through Merchant Project:

  1. CheckOutDelegate
    fun checkoutChargeCaptured(charge: Charge)
    fun checkoutChargeFailed(charge: Charge?)

    fun checkoutAuthorizeCaptured(authorize: Authorize)
     fun checkoutAuthorizeFailed(authorize: Authorize?)


     fun cardSaved(charge: Charge)
     fun cardSavingFailed(charge: Charge)

     fun cardTokenizedSuccessfully(token: Token , saveCard:Boolean)

     fun savedCardsList(cardsList: CardsList)

     fun checkoutSdkError(goSellError: GoSellError?)

     fun sessionIsStarting()
     fun sessionHasStarted()
     fun sessionCancelled()
     fun sessionFailedToStart()

     fun invalidCardDetails()
     fun backendUnknownError(message: GoSellError?)
     fun invalidTransactionMode()
     fun invalidCustomerID()
     fun userEnabledSaveCardOption(saveCardEnabled: Boolean)
     fun  asyncPaymentStarted(charge:Charge)
  1. PaymentDataSource
interface PaymentDataSource {
    /**
     * Transaction currency. @return the currency
     */
    fun getCurrency(): TapCurrency?

    /**
     * TapCustomer. @return the customer
     */
    fun getCustomer(): TapCustomer?

    /**
     * Amount. Either amount or items should return nonnull value. If both return nonnull, then items is preferred. @return the amount
     */
    fun getAmount(): BigDecimal?

    /**
     * List of items to pay for. Either amount or items should return nonnull value. If both return nonnull, then items is preferred. @return the items
     */
    fun getItems(): ArrayList<PaymentItem>?

    /**
     * Transaction mode. If you return null in this method, it will be treated as PURCHASE. @return the transaction mode
     */
    fun getTransactionMode(): TransactionMode?

    /**
     * List of taxes. Optional. Note: specifying taxes will affect total payment amount. @return the taxes
     */
    fun getTaxes(): ArrayList<Tax>?

    /**
     * Shipping list. Optional. Note: specifying shipping will affect total payment amount. @return the shipping
     */
    fun getShipping(): ArrayList<Shipping>?

    /**
     * Tap will post to this URL after transaction finishes. Optional. @return the post url
     */
    fun getPostURL(): String?

    /**
     * Description of the payment. @return the payment description
     */
    fun getPaymentDescription(): String?

    /**
     * If you would like to pass additional information with the payment, pass it here. @return the payment metadata
     */
    fun getPaymentMetadata(): HashMap<String, String>?

    /**
     * Payment reference. Implement this property to keep a reference to the transaction on your backend. @return the payment reference
     */
    fun getPaymentReference(): Reference?

    /**
     * Payment statement descriptor. @return the payment statement descriptor
     */
    fun getPaymentStatementDescriptor(): String?

    /**
     * Defines if user allowed to save card. @return the allowUserToSaveCard
     * @return
     */
    fun getAllowedToSaveCard(): Boolean

    /**
     * Defines if 3D secure check is required. @return the requires 3 d secure
     */
    fun getRequires3DSecure(): Boolean

    /**
     * Receipt dispatch settings. @return the receipt settings
     */
    fun getReceiptSettings(): Receipt?

    /**
     * Action to perform after authorization succeeds. Used only if transaction mode is AUTHORIZE_CAPTURE. @return the authorize action
     */
    fun getAuthorizeAction(): AuthorizeAction?

    /**
     * The Destination array contains list of Merchant desired destinations accounts to receive money from payment transactions
     */
    fun getDestination(): Destinations?

    fun getMerchant(): Merchant?
    fun getPaymentDataType(): String?

    /**
     * Defines if user wants all cards or specific card types.
     */
    fun getCardType(): CardType?

    /**
     * Defines the default cardHolderName. Optional. @return the default CardHolderName
     */
    fun getDefaultCardHolderName(): String?

    /**
     * Defines if user allowed to edit the cardHolderName. @return the enableEditCardHolderName
     * @return
     */
    fun getEnableEditCardHolderName(): Boolean

    /**
     * Defines the cardIssuer details. Optional. @return the default CardIssuer
     */
    fun getCardIssuer(): CardIssuer?

    fun getTopup(): TopUp?

    fun getSelectedCurrency():String?

    fun getSelectedAmount():BigDecimal?

    fun getPaymentOptionsResponse():PaymentOptionsResponse?

    fun getMerchantData(): MerchantData?

    fun getBinLookupResponse() : BINLookupResponse?

    /**
     * Defines the SDK mode . Optional. @return the default Sandbox
     */
    fun getSDKMode(): SdkMode?
     /**
     * Defines the Payment options. Optional.
     */
    fun getAvailablePaymentOptionsCardBrands(): ArrayList<PaymentOption>?
    /**
     * Defines the TokenConfig for header
     */
    fun getTokenConfig(): String?

    /**
     * Defines the AuthKeys.
     */
    fun getAuthKeys(): String?

    fun getInitOptionsResponse():InitResponseModel?
}

SDK Open ENUMs

SDK open Enums available for implementation through Merchant Project:

  1. TransactionMode
enum class TransactionMode {
    PURCHASE,
    AUTHORIZE_CAPTURE

}

2.SdkMode

enum class SdkMode {
/**
* Sandbox is for testing purposes
*/
@SerializedName("Sandbox")
SAND_BOX,
/**
* Production is for live
*/
@SerializedName("Production")
PRODUCTION
}
  1. SdkIdentifier
enum class SdkIdentifier {
   /* react-native
    */
    @SerializedName("react-native")
    ReactNative,
    /**
     * Flutter
     */
    @SerializedName("Flutter")
    Flutter,

    /**
     * Native
     */
    @SerializedName("Native")
    Native

}

4.CardType

/**
 * The Merchant can set different cardTypes CREDIT ,DEBIT , ALL to allow user his choice*/
enum class CardType {

    CREDIT,
    DEBIT,
    ALL
}

SDK Open Models

SDK open Models available for implementation through Merchant Project:

  1. TapCustomer
class TapCustomer(
    /**
     * Gets identifier.
     *
     * @return the identifier
     */
    @field:Expose @field:SerializedName("id") val identifier: String?,
    /**
     * Gets first name.
     *
     * @return the first name
     */
    @field:Expose @field:SerializedName("first_name") var firstName: String?,
    middleName: String?,
    lastName: String?,
    email: String?,
    phone: PhoneNumber?,
    metaData: String?
) :
    Serializable {

    /**
     * Gets middle name.
     *
     * @return the middle name
     */
    @SerializedName("middle_name")
    @Expose
    val middleName: String?

    /**
     * Gets last name.
     *
     * @return the last name
     */
    @SerializedName("last_name")
    @Expose
    val lastName: String?

    /**
     * Gets email.
     *
     * @return the email
     */
    @SerializedName("email")
    @Expose
    val email: String?

    @SerializedName("phone")
    @Expose
    private val phone: PhoneNumber?
    /**
     * Gets meta data.
     *
     * @return the meta data
     */
    /**
     * The Meta data.
     */
    @SerializedName("metadata")
    var metaData: String?

    /**
     * Gets phone.
     *
     * @return the phone
     */
    fun getPhone(): PhoneNumber? {
        return phone
    }

    override fun toString(): String {
        return """TapCustomer {
        id =  '$identifier'
        email =  '$email'
        first_name =  '$firstName'
        middle_name =  '$middleName'
        last_name =  '$lastName'
        phone  country code =  '${phone?.countryCode}'
        phone number =  '${phone?.number}'
        metadata =  '$metaData'
    }"""
    }
    ////////////////////////// ############################ Start of Builder Region ########################### ///////////////////////
    /**
     * The type TapCustomer builder.
     */
    class CustomerBuilder
    /**
     * Client app can create a customer object with only customer id
     *
     * @param innerId the inner id
     */(private val nestedIdentifier: String) {
        private var nestedFirstName: String? = null
        private var nestedMiddleName: String? = null
        private var nestedLastName: String? = null
        private var nestedEmail: String? = null
        private var nestedPhone: PhoneNumber? = null
        private var nestedMetaData: String? = null

        /**
         * First name customer builder.
         *
         * @param innerFirstName the inner first name
         * @return the customer builder
         */
        fun firstName(innerFirstName: String?): CustomerBuilder {
            nestedFirstName = innerFirstName
            return this
        }

        /**
         * Middle name customer builder.
         *
         * @param innerMiddle the inner middle
         * @return the customer builder
         */
        fun middleName(innerMiddle: String?): CustomerBuilder {
            nestedMiddleName = innerMiddle
            return this
        }

        /**
         * Last name customer builder.
         *
         * @param innerLastName the inner last name
         * @return the customer builder
         */
        fun lastName(innerLastName: String?): CustomerBuilder {
            nestedLastName = innerLastName
            return this
        }

        /**
         * Email customer builder.
         *
         * @param innerEmail the inner email
         * @return the customer builder
         */
        fun email(innerEmail: String?): CustomerBuilder {
            nestedEmail = innerEmail
            return this
        }

        /**
         * Phone customer builder.
         *
         * @param innerPhone the inner phone
         * @return the customer builder
         */
        fun phone(innerPhone: PhoneNumber?): CustomerBuilder {
            nestedPhone = innerPhone
            return this
        }

        /**
         * Metadata customer builder.
         *
         * @param innerMetadata the inner metadata
         * @return the customer builder
         */
        fun metadata(innerMetadata: String?): CustomerBuilder {
            nestedMetaData = innerMetadata
            return this
        }

        /**
         * Build customer.
         *
         * @return the customer
         */
        fun build(): TapCustomer {
            return TapCustomer(
                nestedIdentifier, nestedFirstName, nestedMiddleName, nestedLastName,
                nestedEmail, nestedPhone, nestedMetaData
            )
        }
    } ////////////////////////// ############################ End of Builder Region ########################### ///////////////////////

    //  Constructor is private to prevent access from client app, it must be through inner Builder class only
    init {
        firstName = firstName
        this.middleName = middleName
        this.lastName = lastName
        this.email = email
        this.phone = phone
        this.metaData = metaData
    }
}

2.TapCurrency

class TapCurrency(isoCode: String) {
    /**
     * Gets iso code.
     *
     * @return the iso code
     */
    val isoCode: String

    /**
     * Instantiates a new Tap currency.
     *
     * @param isoCode the iso code
     * @throws CurrencyException the currency exception
     */
    init {
        if (isoCode.isEmpty()) {
            this.isoCode = isoCode
        } else {
            val code = isoCode.toLowerCase()
            if (!LocaleCurrencies.checkUserCurrency(code)) {
                throw CurrencyException.getUnknown(code)
            }
            this.isoCode = code
        }
    }
}

3.AuthorizeAction

class AuthorizeAction(void: AuthorizeActionType, i: Int) {
    @SerializedName("type")
    @Expose
    private var type: AuthorizeActionType? = AuthorizeActionType.VOID

    @SerializedName("time")
    @Expose
    private var timeInHours = 168

    /**
     * Gets default.
     *
     * @return the default
     */
   open fun getDefault() {
        return AuthorizeAction(AuthorizeActionType.VOID, 168)
    }

    /**
     * Gets type.
     *
     * @return the type
     */
    fun getType(): AuthorizeActionType? {
        return type
    }

    /**
     * Gets time in hours.
     *
     * @return the time in hours
     */
    fun getTimeInHours(): Int {
        return timeInHours
    }

    /**
     * Instantiates a new Authorize action.
     *
     * @param type        the type
     * @param timeInHours the time in hours
     */
    fun AuthorizeAction(type: AuthorizeActionType?, timeInHours: Int) {
        this.type = type
        this.timeInHours = timeInHours
    }
}
  1. Destination
data class Destination(
    // Destination unique identifier (Required)
    @SerializedName("id") @Expose
    private var id: String? = null,

    // Amount to be transferred to the destination account (Required)
    @SerializedName("amount")
    @Expose
    private val amount: BigDecimal? = null,

    // Currency code (three digit ISO format) (Required)
    @SerializedName("currency")
    @Expose
    private val currency: String? = null,

    //Description about the transfer (Optional)
    @SerializedName("description")
    @Expose
    private val description: String? = null,

    //Merchant reference number to the destination (Optional)
    @SerializedName("reference")
    @Expose
    private val reference: String? = null
)

5.Destinations

data class Destinations(

    @SerializedName("amount") @Expose
    private var amount: BigDecimal? = null,

    @SerializedName("currency")
    @Expose
    private val currency: String? = null,

    @SerializedName("count")
    @Expose
    private val count: Int = 0,

    @SerializedName("destination")
    @Expose
    private val destination: ArrayList<Destination>? = null
)

6.PaymentItem

class PaymentItem(name: String,
                  @Nullable description: String,
                  quantity: Quantity,
                  amountPerUnit: BigDecimal,
                  @Nullable discount: AmountModificator?,
                  @Nullable taxes: ArrayList<Tax>?){
    @SerializedName("name")
    @Expose
    var name: String? = null


    @SerializedName("description")
    @Expose
     var description: String? = null

    @SerializedName("quantity")
    @Expose
     var quantity: Quantity? = null

    @SerializedName("amount_per_unit")
    @Expose
     var amountPerUnit: BigDecimal? = null

    @SerializedName("discount")
    @Expose
     var discount: AmountModificator? = null

    @SerializedName("taxes")
    @Expose
     var taxes: ArrayList<Tax>? = null

    @SerializedName("total_amount")
    @Expose
     var totalAmount: BigDecimal? = null


    init {
        this.name = name
        this.description = description
        this.quantity = quantity
        this.amountPerUnit = amountPerUnit
        this.discount = discount
        this.taxes = taxes
        totalAmount = AmountCalculator.calculateTotalAmountOf(listOf(this),null,null)

        println("calculated total amount : " + totalAmount)
    }

    /**
     * Gets amount per unit.
     *
     * @return the amount per unit
     */
    @JvmName("getAmountPerUnit1")
    fun getAmountPerUnit(): BigDecimal? {
        return amountPerUnit
    }

    /**
     * Gets quantity.
     *
     * @return the quantity
     */
    @JvmName("getQuantity1")
    fun getQuantity(): Quantity? {
        return quantity
    }

    /**
     * Gets discount.
     *
     * @return the discount
     */
    @JvmName("getDiscount1")
    fun getDiscount(): AmountModificator? {
        return discount
    }

    /**
     * Gets plain amount.
     *
     * @return the plain amount
     */
    fun getPlainAmount(): BigDecimal {
        println("  #### getPlainAmount : " + getAmountPerUnit())
        System.out.println("  #### this.getQuantity().getValue() : " + getQuantity()?.value)
        println("  #### result : " + getAmountPerUnit()!!.multiply(getQuantity()?.value))
        return getAmountPerUnit()!!.multiply(getQuantity()?.value)
    }

    /**
     * Gets discount amount.
     *
     * @return the discount amount
     */
    fun getDiscountAmount(): BigDecimal? {
        return if (getDiscount() == null) {
            BigDecimal.ZERO
        } else when (getDiscount()!!.getType()) {
            AmountModificatorType.PERCENTAGE -> getPlainAmount().multiply(getDiscount()!!.getNormalizedValue())
            AmountModificatorType.FIXED -> getDiscount()?.getValue()
            else -> BigDecimal.ZERO
        }
    }

    /**
     * Gets taxes amount.
     *
     * @return the taxes amount
     */
    fun getTaxesAmount(): BigDecimal? {
        val taxationAmount = getPlainAmount().subtract(getDiscountAmount())
        return AmountCalculator.calculateTaxesOn(taxationAmount, taxes)
    }


    class PaymentItemBuilder
    /**
     * public constructor with only required data
     *
     * @param name          the name
     * @param quantity      the quantity
     * @param amountPerUnit the amount per unit
     */(private var nestedName: String,
        private var nestedQuantity: Quantity,
        private var nestedAmountPerUnit: BigDecimal) {
        private var nestedDescription: String? = null
        private var nestedDiscount: AmountModificator? = null
        private var nestedTaxes: ArrayList<Tax>? = null
        private var nestedTotalAmount: BigDecimal? = null

        /**
         * Description payment item builder.
         *
         * @param innerDescription the inner description
         * @return the payment item builder
         */
        fun description(innerDescription: String?): PaymentItemBuilder {
            nestedDescription = innerDescription
            return this
        }

        /**
         * Discount payment item builder.
         *
         * @param innerDiscount the inner discount
         * @return the payment item builder
         */
        fun discount(innerDiscount: AmountModificator?): PaymentItemBuilder {
            nestedDiscount = innerDiscount
            return this
        }

        /**
         * Taxes payment item builder.
         *
         * @param innerTaxes the inner taxes
         * @return the payment item builder
         */
        fun taxes(innerTaxes: ArrayList<Tax>?): PaymentItemBuilder {
            nestedTaxes = innerTaxes
            return this
        }

        /**
         * Total amount payment item builder.
         *
         * @param innerTotalAmount the inner total amount
         * @return the payment item builder
         */
        fun totalAmount(innerTotalAmount: BigDecimal?): PaymentItemBuilder {
            nestedTotalAmount = innerTotalAmount
            return this
        }

        /**
         * Build payment item.
         *
         * @return the payment item
         */
        fun build(): PaymentItem {
            return PaymentItem(nestedName, nestedDescription!!, nestedQuantity, nestedAmountPerUnit,
                    nestedDiscount, nestedTaxes)
        }
    }


}
  1. Receipt
data class Receipt(
    @SerializedName("id") @Expose
    var id: Boolean,

    @SerializedName("email")
    @Expose
    val email: Boolean = false,

    @SerializedName("sms")
    @Expose
    private val sms: Boolean = false
) : Serializable

8.Reference

data class Reference(
    @SerializedName("acquirer") @Expose
    private var acquirer: String? = null,

    @SerializedName("gateway")
    @Expose
    private val gateway: String? = null,

    @SerializedName("payment")
    @Expose
    private val payment: String? = null,

    @SerializedName("track")
    @Expose
    private val track: String? = null,

    @SerializedName("transaction")
    @Expose
    private val transaction: String? = null,

    @SerializedName("order")
    @Expose
    private val order: String? = null,

    @SerializedName("gosell_id")
    @Expose
    private val gosell_id: String? = null
) : Serializable
  1. Shipping
data class Shipping(
    @SerializedName("name") private var name: String,
    @SerializedName("description") @Nullable val description: String,
    @SerializedName("amount") val amount: BigDecimal
)

9.Tax

data class Tax(
    @SerializedName("name") var name: String,
    @SerializedName("description") val description: String,
    @SerializedName("amount") val amount: AmountModificator
)

10.TopUp

data class TopUp(
    @SerializedName("id") @Expose
    var Id: String? = null,
    @SerializedName("wallet_id")
    @Expose
    var walletId: String? = null,

    @SerializedName("created")
    @Expose
    var created: Long? = null,

    @SerializedName("status")
    @Expose
    var status: String? = null,

    @SerializedName("amount")
    @Expose
    var amount: BigDecimal? = null,

    @SerializedName("currency")
    @Expose
    var currency: String? = null,

    @SerializedName("charge")
    @Expose
    var charge: TopchargeModel? = null,

    @SerializedName("customer")
    @Expose
    var customer: TopCustomerModel? = null,

    @SerializedName("reference")
    @Expose
    var topUpReference: TopUpReference? = null,

    @SerializedName("application")
    @Expose
    var application: TopUpApplication? = null,

    @SerializedName("response")
    @Expose
    var response: Response? = null,

    @SerializedName("post")
    @Expose
    var post: TopupPost? = null,

    @SerializedName("metadata")
    @Expose
    var metadata: MetaData? = null
) : Serializable

data class TopchargeModel(
    @SerializedName("id") @Expose
    private var id: String? = null
) : Serializable

data class TopCustomerModel(
    @SerializedName("id") @Expose
    private var id: String? = null
) : Serializable

data class TopUpApplication(
    @SerializedName("amount") @Expose
    var amount: BigDecimal? = null,
    @SerializedName("currency") @Expose
    var currency: String? = null
) : Serializable

data class TopUpReference(
    @SerializedName("order") @Expose
    var order: String? = null,
    @SerializedName("transaction")
    @Expose
    val transaction: String? = null
) : Serializable

data class TopupPost(
    @SerializedName("url") @Expose
    val url: String? = null
) : Serializable

data class MetaData(
    @SerializedName("udf1") @Expose
    private var udf1: String? = null,
    @SerializedName("udf2")
    @Expose
    private var udf2: String? = null
) : Serializable
  1. CardsList
class CardsList(
    responseCode: Int,
    `object`: String,
    has_more: Boolean,
    data: ArrayList<SavedCard>?
) {
    private val responseCode: Int = responseCode
    private val `object`: String
    private val has_more: Boolean
    private var cards: ArrayList<SavedCard>?

    /**
     * Gets Response Code
     * @return responseCode
     */
    fun getResponseCode(): Int {
        return responseCode
    }

    /**
     * Gets Object type
     * @return object
     */
    fun getObject(): String {
        return `object`
    }

    /**
     * Check if customer has more cards
     * @return has_more
     */
    fun isHas_more(): Boolean {
        return has_more
    }

    /**
     * Gets cards.
     *
     * @return the cards
     */
    fun getCards(): ArrayList<SavedCard>? {
        if (cards == null) {
            cards = ArrayList<SavedCard>()
        }
        return cards
    }

    init {
        this.`object` = `object`
        this.has_more = has_more
        cards = data
    }
}

CheckOut Delegate

CheckOutDelegate is an interface which you may want to implement to receive payment/authorization/card saving status updates and update your user interface accordingly when payment window closes. Below are listed down all available callbacks:

checkout Success Callback

Notifies the receiver that payment has succeed.

Declaration

Kotlin:

- fun checkoutChargeCaptured(charge: Charge)

Arguments

charge: Successful charge object.

checkout Failure Callback

Notifies the receiver that payment has failed.

Declaration

Kotlin:

- fun checkoutChargeFailed(charge: Charge?) 

Arguments

charge: Charge object that has failed (if reached the stage of charging).

Authorization Success Callback

Notifies the receiver that authorization has succeed.

Declaration

Kotlin:

-  fun checkoutAuthorizeCaptured(authorize: Authorize)

Arguments

authorize: Successful authorize object.

Authorization Failure Callback

Notifies the receiver that authorization has failed.

Declaration

Kotlin:

- fun checkoutAuthorizeFailed(authorize: Authorize?)

Arguments

authorize: Authorize object that has failed (if reached the stage of authorization).

Card Saving Success Callback

Notifies the receiver that the customer has successfully saved the card.

Declaration

Kotlin:

- fun cardSaved(charge: Charge) // you have to cast Charge object to SaveCard object first to get card info 

Arguments

Charge: Charge object with the details.

Card Saving Failure Callback

Notifies the receiver that the customer failed to save the card.

Declaration

Kotlin:

- fun cardSavingFailed(charge: Charge)

Arguments

Charge: Charge object with the details (if reached the stage of card saving).

Card Tokenized Success Callback

Notifies the receiver that the card has successfully tokenized.

Declaration

Kotlin:

- fun cardTokenizedSuccessfully(token: Token)

Arguments

token: card token object.

Saved Cards List Callback

Notifies the receiver with list of saved cards for a customer. If customer has no cards then you will receive the same response but with empty cards array.

Declaration

Kotlin:

-  fun savedCardsList(cardsList: CardsList)

Arguments

cardsList: CardsList model that holds the response.

Session Other Failure Callback

Notifies the receiver if any other error occurred.

Declaration

Kotlin:

- fun checkoutSdkError(goSellError: GoSellError?)

Arguments

GoSellError: GoSellError object with details of error.

Invalid Card details

Notifies the client that card data passed are invalid

Declaration

Kotlin:

- fun invalidCardDetails()

Backend Unknown Error

Notifies the client that an unknown error has occurred in the backend

Declaration

Kotlin:

-  fun backendUnknownError(message: GoSellError?)

Invalid Transaction Mode

Notifies the client that Transaction Mode not configured.

Declaration

Kotlin:

-  fun invalidTransactionMode()

User Enabled Save Card call back

Notifies the receiver (Merchant Activity) that the user wants to save his card.

Declaration

Kotlin:

- fun userEnabledSaveCardOption(saveCardEnabled: Boolean)

Session Is Starting Callback

Notifies the receiver that session is about to start, but hasn't yet shown the SDK UI. You might want to use this method if you are not using PayButton in your application and want to show a loader before SDK UI appears on the screen.

Declaration

Kotlin:

- fun sessionIsStarting()

Session Has Started Callback

Notifies the receiver that session has successfully started and shown the SDK UI on the screen. You might want to use this method if you are not using PayButton in your application and want to hide a loader after SDK UI has appeared on the screen.

Declaration

Kotlin:

-  fun sessionHasStarted()

Session Failed To Start Callback

Notifies the receiver that session has failed to start.

Declaration

Kotlin:

-  fun sessionFailedToStart()

Session Cancel Callback

Notifies the receiver (Merchant Activity) that the user cancelled payment process, clicked on soft back button, clicked hard back button or clicked Header cancel button.

Declaration

Kotlin:

- fun sessionCancelled()

Documentation

Documentation is available at [github-pages][2].
Also documented sources are attached to the library. [1]:https://www.tap.company/developers/