> For the complete documentation index, see [llms.txt](https://ftcoders.first-tech.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ftcoders.first-tech.com/first-tech-ttp-sdk/developer-zone/sdk-calls-and-integration-guide.md).

# 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:

{% stepper %}
{% step %}

### Locate the `build.gradle` file:

Access the `build.gradle` file at the project level (project root).
{% endstep %}

{% step %}

### Add the Nexus repository to the project's `build.gradle`:

It is recommended to add the Nexus repository in the root `build.gradle` file. This ensures that the repository is globally available for all modules, avoiding unnecessary repetitions.
{% endstep %}

{% step %}

### Configure the Nexus repository with credentials:

In the `repositories` block, add the Nexus configuration with the provided credentials.
{% endstep %}
{% endstepper %}

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.

<figure><img src="/files/PXXfg0YcutUB71lmhJL9" alt=""><figcaption></figcaption></figure>

### Configure the SDK in the `build.gradle` file of the app module

* Open 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)
```

<figure><img src="/files/faR2xpM1GvOPz6ikKouJ" alt=""><figcaption></figcaption></figure>

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

<figure><img src="/files/DR2HMipqcNb4xSzeq9Fw" alt=""><figcaption></figcaption></figure>

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`.

<figure><img src="/files/3liq5Oddn4Dyh7sm1Lq5" alt=""><figcaption></figcaption></figure>

### 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 SDK
* `sdkClientId` -> Client ID for SDK, given by FirstTech team, but, submitted by the consummer of this SDK
* `sdkClientSecret`  -> Client Secret for SDK, given by FirstTech team, but, submitted by the consummer of this SDK
* `appVersion`   -> Version number of the client application.
* `packageName`   -> Name of the package where the client application is running
* `sdkOrganization`   -> 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) }
```

<figure><img src="/files/irlcnziLgaKzN9aMp8Yt" alt=""><figcaption></figcaption></figure>

### 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 the `PaymentType` ENUM, which can be either `PaymentType.DEBIT` or `PaymentType.CREDIT`.
* `amount`: The total transaction amount, expressed as a `Long`.

| Value R$ | Long |
| -------- | ---- |
| 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.

{% hint style="info" %}
It is important to observe `onMessage` within the correct lifecycle, ensuring that there are no memory leaks or unexpected reactions.
{% endhint %}

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.

| Class                                   | Description                                                          |
| --------------------------------------- | -------------------------------------------------------------------- |
| `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.

{% stepper %}
{% step %}

#### TerminalCreatedErrorViewData | TerminalSessionCreatedErrorViewData

* `cause` → Throwable object returned by the payment SDK, used for debugging only.
* `logMessage` → Conversion of `cause` to a String.
  {% endstep %}

{% step %}

#### 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.*
{% endstep %}

{% step %}

#### 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.*
{% endstep %}

{% step %}

#### 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.

1. **cardHolder**

When available, it returns the card brand used for the transaction:

* MASTERCARD
* VISA
* AMERICAN\_EXPRESS
* DISCOVER
* EFTPOS
* UNKNOWN

2. **discretionaryTagData**

Returns EMV Tags read by the SDK. Two methods are provided for better abstraction:

* `getDiscretionaryTagDataHashMap()` → Returns a key-value array containing `EMVTag` and its value.
* `getDiscretionaryTagDataPrintable()` → Same function as above, but returns a formatted String for display.

3. **metaData**

A `ByteArray` of metadata returned by the backend. Two methods are available for better interpretation:

* `getMetaDataTranslated()` → Returns a parsed `Metadata` object with additional information.
* `getMetaDataString()` → Same as the above method but returns a JSON-formatted String.

4. **processingResult**

This object, as a `SealedClass`, can have two abstractions:

5. **TransactionApproved**

`cardScheme` → When available, returns the card brand used in the transaction:

* MASTERCARD
* VISA
* AMERICAN\_EXPRESS
* DISCOVER
* EFTPOS
* UNKNOWN

6. **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.*

7. **serviceTransactionId**

A unique identifier for the transaction (UUID).

8. **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

9. **subMessage**

An enumeration of sub-messages that should also be displayed when returned, following ABECS standards.
{% endstep %}

{% step %}

#### 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.*
{% endstep %}
{% endstepper %}

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)
```

<figure><img src="/files/i1LBhkw0PaR0aBk4P1Cl" alt=""><figcaption></figcaption></figure>

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.

{% hint style="info" %}
Note: this method must be used within a coroutine, as it is a suspend method
{% endhint %}

{% hint style="info" %}
To obtain this information, use the following syntax
{% endhint %}

```
  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
  }
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://ftcoders.first-tech.com/first-tech-ttp-sdk/developer-zone/sdk-calls-and-integration-guide.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
