SDK Calls & Integration Guide
Access to the Nexus repository must be configured in the build.gradle
file so that the Tap to Phone SDK is correctly imported into the project. The Nexus repository contains the staging and production versions of the SDK. Follow the steps below to complete the configuration:
Example: Adding Nexus Repository
buildscript {
repositories {
maven {
url = uri("https://nexus.first-tech.net/repository/taponphone-dock/")
credentials {
username = "XXX"
password = "YYY"
}
}
}
}
allprojects {
repositories {
maven {
url = uri("https://nexus.first-tech.net/repository/taponphone-dock/")
credentials {
username = "XXX"
password = "YYY"
}
}
}
}
Consider that the username and password will be provided during the onboarding process by the repository provider, which may be First Tech or the company that purchased the product under the white-label model.

Configure the SDK in the build.gradle
file of the app module
build.gradle
file of the app moduleOpen the
build.gradle
file at the app module level.Add the SDK dependency in the
dependencies
block.
Example:
debugImplementation(libs.taponphone.sdk.v2.hml)
releaseImplementation(libs.taponphone.sdk.v2.release)

As a best programming practice, the path of these variables is configured to be retrieved from the libs.versions.toml
file.

At this point, you can execute the 'Sync Project with Gradle Files' command to synchronize the project.
If an error occurs during 'Sync Project with Gradle Files':
If an error occurs during 'Sync Project with Gradle Files':
Remove the following snippet from the settings.gradle.kts
file:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
And run the command again.
[CTRL + Shift + o]
The expected output in the console should be: BUILD SUCCESSFUL
.

Implementing the use of the SDK
In your project's initialization class (Application
), you must "extend" Application
In this class, it is necessary to replace the terminalConfig
variable, which is instantiated from the TerminalConfigEntity
entity, considering the parameters provided during onboarding with First Tech, which are:
class Application : Application() {
override fun onCreate() {
super.onCreate()
if (!TapOnPhoneInitializer.isApplicationInitAllowed(this)) return
TapOnPhoneInitializer.initializeTerminal(this)
TapOnPhoneInitializer.setTerminalConfig(
TerminalConfigEntity(
companyDocument = BuildConfig.COMPANY_DOCUMENT,
companyName = BuildConfig.COMPANY_NAME,
merchantId = UUID.fromString(BuildConfig.MERCHANT_ID),
terminalNumber = BuildConfig.TERMINAL_NUMBER,
clientId = BuildConfig.CLIENT_ID,
clientSecret = BuildConfig.CLIENT_SECRET,
sdkScope = BuildConfig.SDK_SCOPE,
sdkClientId = BuildConfig.SKD_CLIENT_ID,
sdkClientSecret = BuildConfig.SDK_CLIENT_SECRET,
appVersion = "1.0.0",
packageName = applicationContext.packageName,
sdkOrganization = "Organization 123",
versionCode = (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
packageManager.getPackageInfo(packageName, 0).longVersionCode
} else {
packageManager.getPackageInfo(packageName, 0).versionCode.toLong()
}).toString()
)
)
}
}
companyDocument
→ Your company's CNPJ document without special characters.companyName
→ Your company's trade name.merchantId
→ UUID provided by First Tech during the onboarding process. (Note: This field is the Java UUID object.)terminalNumber
→ Terminal number provided by First Tech during the onboarding process.clientId
→ Client ID provided by First Tech during the onboarding process.clientSecret
→ Client key provided by First Tech during the onboarding process.sdkScope
-> Client Secret for auth, given by FirstTech team, but, submitted by the consummer of this SDKsdkClientId
-> Client ID for SDK, given by FirstTech team, but, submitted by the consummer of this SDKsdkClientSecret
-> Client Secret for SDK, given by FirstTech team, but, submitted by the consummer of this SDKappVersion
-> Version number of the client application.packageName
-> Name of the package where the client application is runningsdkOrganization
-> This figure is provided by First Tech.versionCode
-> Value of the application's versionCode.
All SDK manipulation operations are performed through the ViewModel
, which receives TapOnPhoneApplication
as a parameter during its creation.
private val mppProviderViewModel by lazy { MPPPProviderViewModel(application as TapOnPhoneApplication) }

Starting a payment
Execute the startPaymentFlow()
function, provided by MPPProviderViewModel
. To do this, you need to pass the TransactionInfoEntity
class as a parameter, which receives the following values in its constructor:
installments
: An integer containing the number of installments.paymentType
: One of the options from thePaymentType
ENUM, which can be eitherPaymentType.DEBIT
orPaymentType.CREDIT
.amount
: The total transaction amount, expressed as aLong
.
R$ 23,34
2334
R$ 15,00
1500
R$ 0,15
15
R$0,01
1
private fun startPayment() {
mppProviderViewModel.startPaymentFlow(
TransactionInfoEntity(
paymentType.DEBIT, //IT COULD BE paymentType.CREDIT
100, //For example, this 100 means R$ 1.00,
2 //Number of installments, in this case, two installments
)
)
}
After this step, simply react to the events published in onMessage
and capture the information from the entities of these events.
Reacting to messages
MPPProviderViewModel
provides the LiveData onMessage
, which will receive an 'extended' object from the MPPViewData
class.
In this project, we use the concept of Sealed Classes for a more efficient abstraction. Below, we list all the objects that can be returned in onMessage
and their respective meanings.
TerminalInitializingViewData
The terminal has started the initialization process.
TerminalInitializingErrorViewData
The terminal has completed the initialization process with an error.
TerminalInitializingSuccessViewData
The terminal has successfully completed the initialization process.
TerminalNotCreatedViewData
The terminal instance has not yet been created.
TerminalCreatingViewData
The terminal instance is being created.
TerminalCreatedSuccessViewData
The terminal instance has been successfully created.
TerminalCreatedErrorViewData
The terminal instance was not created.
TerminalSessionCreatingViewData
The payment session is being created.
TerminalSessionCreatedSuccessViewData
The payment session has been successfully created.
TerminalSessionCreatedErrorViewData
The payment session was not created.
TerminalSessionTimeoutViewData
The payment session has expired.
TerminalPaymentStartingViewData
The transaction process has started.
TerminalPaymentProcessingViewData
The transaction is being processed.
TerminalPaymentCancelledViewData
The transaction has been canceled.
TerminalPaymentSuccessViewData
The transaction was successfully completed.
TerminalPaymentErrorViewData
The transaction was completed with an error.
TerminalPaymentFinishedViewData
The entire process has been completed.
Here, we obtain the reference to the LiveData onMessage
and start observing it:
private fun setupObserver() {
mppProviderViewModel.onMessage.observe(this, ::onMessage)
}
And we react to events as follows:
Note: In this example, we do not list all
MPPViewData
classes, but we strongly recommend implementing all classes.
Note: Some
MPPViewData
classes contain objects that help understand the message that should be displayed at a specific step.
private fun onMessage(viewData: MPPViewData?) {
viewData?.let {
when (viewData) {
MPPViewData.TerminalInitializingViewData -> {
showLoadingDialog("Inicializando terminal")
binding.tvMessage.text = "Inicializando terminal"
}
MPPViewData.TerminalInitializingErrorViewData -> {
showFeedbackDialog("Erro ao inicializar terminal")
progressDialog.dismiss()
}
MPPViewData.TerminalInitializingSuccessViewData -> {
progressDialog.dismiss()
binding.tvMessage.text = "Inicialização concluída"
}
//Mapear todos os cenários de MPPViewData
}
}
}
Next, we will explain in more detail the messages returned in the onMessage
interface, which are extensions of the MPPViewData
object.
Classes not detailed below do not have internal variables. In these cases, follow the guidelines described in Table 2 – OnMessage Return List.
TerminalPaymentProcessingViewData
uiMessage
→ Enumeration of all possible scenarios during card information processing, including:
APPROVED
NOT_AUTHORISED
PLEASE_ENTER_PIN
PROCESSING_ERROR
PRESENT_CARD
CARD_READ_OK_PLEASE_REMOVE
APPROVED_PLEASE_SIGN
AUTHORISING_PLEASE_WAIT
TRY_ANOTHER_CARD
CLEAR_DISPLAY
SEE_PHONE
PRESENT_CARD_AGAIN
HOLD_STILL
UNKNOWN
A default message is provided for display on the screen, but developers have the freedom to customize it as long as they comply with ABECS regulations.
TerminalPaymentCancelledViewData
reason
→ Enumeration of error scenarios that occur during card information reading and capture, including:
TRANSACTION_WAS_TERMINATED
USER_CANCELLED_PIN_PAD
SESSION_DEACTIVATED
DEVICE_STATE_FAILURE
TIME_CHECK_ERROR
UNKNOWN
A default message is provided for display on the screen, but developers have the freedom to customize it as long as they comply with ABECS regulations.
TerminalPaymentSuccessViewData
result
→ TransactionCompleted
object containing all payment details
Note: This does not guarantee that the transaction was successfully completed, as issues may have occurred with the acquirer. All fields will be explained in the following sections.
cardHolder
When available, it returns the card brand used for the transaction:
MASTERCARD
VISA
AMERICAN_EXPRESS
DISCOVER
EFTPOS
UNKNOWN
discretionaryTagData
Returns EMV Tags read by the SDK. Two methods are provided for better abstraction:
getDiscretionaryTagDataHashMap()
→ Returns a key-value array containingEMVTag
and its value.getDiscretionaryTagDataPrintable()
→ Same function as above, but returns a formatted String for display.
metaData
A ByteArray
of metadata returned by the backend. Two methods are available for better interpretation:
getMetaDataTranslated()
→ Returns a parsedMetadata
object with additional information.getMetaDataString()
→ Same as the above method but returns a JSON-formatted String.
processingResult
This object, as a SealedClass
, can have two abstractions:
TransactionApproved
cardScheme
→ When available, returns the card brand used in the transaction:
MASTERCARD
VISA
AMERICAN_EXPRESS
DISCOVER
EFTPOS
UNKNOWN
TransactionNotAuthorised
reason
→ Enumeration of authorization failure reasons, including:
ONLINE_DECLINED
OFFLINE_DECLINED
INVALID_AUTHORISATION_DATA
NO_CARD_APPLICATION
NO_CARD_APPLICATION_SELECTOR_MISMATCHED
PROCESSING_ERROR
CARD_ERROR
UNKNOWN
A default message is provided for display on the screen, but developers have the freedom to customize it as long as they comply with ABECS regulations.
serviceTransactionId
A unique identifier for the transaction (UUID).
uiMessage
Enumeration of all possible scenarios during card information processing:
ONLINE_DECLINED
OFFLINE_DECLINED
INVALID_AUTHORISATION_DATA
NO_CARD_APPLICATION
NO_CARD_APPLICATION_SELECTOR_MISMATCHED
PROCESSING_ERROR
CARD_ERROR
UNKNOWN
subMessage
An enumeration of sub-messages that should also be displayed when returned, following ABECS standards.
TerminalPaymentErrorViewData
Returned when a payment error is detected.
errorCause
→ Enumeration of possible failures.exception
→ Throwable object returned by the payment SDK, used for debugging only.discretionaryTagData
→ Key-value return of EMV Tags read by the SDK.
A default message is provided for display on the screen, but developers have the freedom to customize it as long as they comply with ABECS regulations.
With these instructions, we understand that there are macro guidelines for setting up the environment, downloading dependencies, and best practices for product implementation. The development team should have a more specific and comprehensive document for application creation, which is not covered here. Some excerpts have been included only to illustrate to the operations support team the steps involved in the application's development.
Device Information
To obtain the deviceID, in order to facilitate log analysis. A method has been provided within the DeviceInformationUtils class. To use it, use the following syntax
DeviceInformationUtils.getDeviceIdentifier(applicationContext)

A String value will be returned, this value can be used in some visualization on the screen, to make it easier to identify the device in any possible error analysis.
To obtain information about the device. A method has also been provided within the DeviceInformationUtils class.
binding.btnDeviceInfo.setOnClickListener {
lifecycleScope.launch {
binding.tvLog.text = DeviceInformationUtils.getDeviceInfo(applicationContext)
}
}
A JSON (below) will be returned as a String, this value can be used in some visualization on the screen or some pop-up, to facilitate the identification of any configuration made on the device that is preventing its use for some transaction.
JSON return example
{
"device" : {
"apiVersionAndroid" : 33, //Android OS API level of the device running the app
"batteryLevel" : 92, //Battery percentage
"brand" : "samsung", //Device brand
"deviceId" : "2c9496cabbdde392", //Id of the application installed on the device
"googlePlayServiceVersion" : 251633029, //Version of Google Play Service installed on the device
"isActivatedBatteryMode" : false, //Check if the battery saving mode is active
"isActivatedDeveloperMode" : true, //Check if the developer mode is active
"isEnabledAutomaticTime" : true, //Check if the time is set automatically
"isEnabledNfc" : false, //Check if the Nfc function is active
"isRooted" : false, //Check if the device is in root mode
"manufacturer" : "samsung", //Manufacturer of the device
"memoryCapacity" : "3. 45", //Device memory capacity
"memoryInUse" : "1. 51", //Total memory in use
"mobileSignal" : {
"level" : 1, //Mobile network signal level
"operatorName" : "CLARO BR", //Mobile network operator
"typeOfSignal" : "4G" //Type of signal captured
},
"model" : "SM-A326B", //Device model
"soVersionAndroid" : "13", //Trade name of A version
"wifiSignal" : 4 //Level of WI-FI signal received
},
"securityScan" : {
"appsInstalledOnDevice" : [ "com.sec.android.gallery3d", "com.android.chrome", "com.android.settings", "com.android.vending", "com.google.android.apps.maps", "com.google.android.apps.messaging", "com.google.android.apps.tachyon", "com.google.android.gm", "com.google.android.youtube", "com.samsung.android.app.contacts", "com.samsung.android.arzone", "com.samsung.android.calendar", "com.samsung.android.dialer", "com.samsung.android.messaging", "com.sec.android.app.camera", "com.google.android.apps.docs", "com.google.android.apps.photos", "com.google.android.apps.youtube.music", "com.google.android.videos", "com.microsoft.office.outlook", "com.samsung.android.oneconnect", "com.sec.android.app.sbrowser", "com.sec.android.app.shealth", "com.android.stk", "com.claroColombia.contenedor", "com.gameloft.android.gdc", "com.google.android.googlequicksearchbox", "com.samsung.android.app.spage", "com.samsung.android.game.gamehome", "com.sec.android.app.clockpackage", "com.sec.android.app.fm", "com.sec.android.app.myfiles", "com.sec.android.app.samsungapps", "com.sec.android.usermanual", "br.com.claropay.claropay", "com.claro.claromusica.br", "com.clarodrive.android", "com.dla.android", "com.edifier.edifierconnect", "com.example.testemicrophone", "com.facebook.katana", "com.facebook.orca", "com.firsttech.taponphone.app", "com.firsttech.taponphone.app.dev", "com.firsttech.taponphone.dev.app", "com.firsttech.taponphone.kt.app.dev", "com.google.android.apps.playconsole", "com.handmark.expressweather", "com.instagram.android", "com.microsoft.office.officehubrow", "com.nvt.cs", "com.rsupport.rs.activity.rsupport.aas2", "com.samsung.android.app.notes", "com.samsung.android.app.watchmanager", "com.samsung.android.spay", "com.samsung.android.voc", "com.samsung.sree", "com.sec.android.app.popupcalculator", "com.sec.android.app.voicenote", "com.sec.android.easyMover" ], //Apps installed on the device
"appsMalwareList" : [ ], //Apps found in the list of apps not recommended to run in parallel with TTP
"appsOutsidePlaystoreList" : [ ], //Not implemented
"appsRunningList" : [ ] //Not implemented
}
}
Last updated