Skip to main content

Android

The Tap on Phone Application (ToPP) is expected to be used as described in the Data Flow diagram using an SDK provided by Geopagos with its own documentation.

Transaction flow

  1. Initialize the SDK with the application ID provided by Geopagos
  2. Request application data from the ToPP app — returns the device and app metadata required to create the session
  3. Create a session intent from your backend with that metadata — the API returns the encrypted session payload
  4. Start the transaction by passing the encrypted session to the SDK — the SDK launches the ToPP app to handle the payment
  5. Upload the cardholder signature from your backend, only when the transaction requires it
  6. Verify the transaction from your backend before showing a success message to the user
  7. Release the SDK when you no longer need it

Prerequisites

Before getting started, ensure the following requirements are met:

  • A physical device that meets the general device requirements
  • The ToPP application installed on the device. It is provisioned by Geopagos for each tenant — contact the Geopagos team to obtain it and the distribution instructions for your target devices
  • An application ID provided by Geopagos, used to initialize the SDK
  • A valid authorization token for the Geopagos API — see Authentication for details on how to generate it

Setup

Add the Geopagos Maven repository to your buildScript repositories declaration:

repositories {
maven { url 'https://nexus.devops.geopagos.com/repository/android-geopagos_public/' }
}

And the SDK to your module dependencies:

dependencies {
implementation "com.geopagos.payments.taponphoneinvocation:topInvocationSdk:$topInvocationSdkVersion"
}

Where topInvocationSdkVersion is the SDK version you want to integrate. The latest version is 3.0.3.

Download the Invocation SDK API documentation

Initialization

First of all, SDK initialization is required:

TapOnPhoneInvocationSdk.init({CONTEXT}, {APPLICATION_ID})

Where:

  • CONTEXT is the ApplicationContext.
  • APPLICATION_ID is the application ID provided by Geopagos, which may include a suffix to identify different build types.
caution

init throws SDKAlreadyInitializedException if the SDK is already initialized and release() was not called in between. If your integration may reach this call more than once, catch the exception to make it idempotent.

Installation verification

Installation verification lets the merchant confirm that the ToPP installation on their device is the genuine one, and not a phishing or otherwise malicious app impersonating it. It is independent of the transaction flow: the merchant can trigger it at any time, without a session intent.

Mandatory

This flow must be implemented by the integrating application. Expose it as an action the merchant can reach on demand — it is required for compliance.

Create an Activity Result Launcher with the function getInstallationVerificationContract()

val verifyInstallationActivity = registerForActivityResult(
TapOnPhoneInvocationSdk.getInstallationVerificationContract()) { result ->
handleVerificationResult(result)
}

Then launch it. SdkInstallationVerificationIntent takes no arguments:

verifyInstallationActivity.launch(SdkInstallationVerificationIntent())

The ToPP app takes over from here: it asks the merchant for the verification code and displays the outcome of the verification on its own screens. The contract returns an InstallationVerificationSdkResult, which is either Success or Error and carries no additional data.

Request application data

To get Tap On Phone with PIN Application information you simply have to call:

TapOnPhoneInvocationSdk.requestApplicationData({CALLBACK}, {AUTH_TOKEN})

Where:

  • CALLBACK is a function that receives ApplicationDataSdkResult object as a parameter. This object represents the outcome of the request and can be either:
    • Success: contains the necessary data to create a Session Intent.
    • Error: contains a specific error type that needs to be handled appropriately.
  • AUTH_TOKEN is an Authorization token required to interact with custom services by the ToPP. To generate this token, please refer to Authentication.

ApplicationDataSdkResult.Success

PropertyTypeDescription
deviceIdStringUnique identifier for the device. Used as the client fingerprint when creating the session intent
versionNameStringVersion of the installed ToPP app
applicationNameStringName of the installed ToPP app
sdkVersionString?Version of the Transaction SDK embedded in the ToPP app. Send it only when present
operatingSystemString?Operating system of the device. Send it only when present

These are the values your backend needs to build the client_id of the session intent request. See Get session intent.

ApplicationDataSdkResult.Error

Besides the error type, Error also exposes deviceId, which may be null. Log it — it is the identifier the Geopagos support team needs when the request fails before a session exists.

The error property is an ApplicationDataSdkError:

ErrorDescription
ConnectionThe connection could not be established, possibly due to a poor network connection
DeveloperSettingsOnThe device has developer settings enabled
DeviceIsBlockedThe device has been blocked
InaccessibleThe ToPP service is unreachable, either because the app is not installed or because binding to the service failed
InternalAn internal SDK error occurred
KeyStoreThe Android Keystore could not be accessed or used
MessageNotSupportedThe message sent to the ToPP app is unknown or not supported
SecurityErrorA security check failed
TimeoutThe ToPP app took too long to respond
UnknownThe cause of the failure could not be determined
UpdateRequiredThe ToPP app must be updated before proceeding

SecurityError, DeviceIsBlocked, Internal, Connection and KeyStore also carry an errorCode with more detail about the failure. The remaining types carry no extra data.

Handling the Result

Both variants are delivered to the callback you pass to requestApplicationData:

TapOnPhoneInvocationSdk.requestApplicationData({ result ->
when (result) {
is ApplicationDataSdkResult.Success -> createSessionIntent(result)
is ApplicationDataSdkResult.Error ->
Log.e(TAG, "Application data request failed: ${result.error} - deviceId = ${result.deviceId}")
}
}, AUTH_TOKEN)
important

On first usage if ToPP application is not loaded in memory this callback may have a delay around 5 seconds because of the security checks that are performed on first usage. You may receive a timeout on first usage, if this happen we recommend you to retry the request at least once.

tip

To ensure a smooth transaction flow, it is recommended to initialize the SDK (TapOnPhoneInvocationSdk.init) and request the application data (TapOnPhoneInvocationSdk.requestApplicationData) as early as possible. You can pass null for the AUTH_TOKEN in requestApplicationData if the user is not logged in yet.

This approach helps to reduce any delays or interruptions during the transaction process.

You still need to request the application data (passing the AUTH_TOKEN) when starting the transaction in case the app data has changed (e.g. the ToPP app was updated). In case the app data hasn't changed, the response will be immediate.

Get session intent

Once you have the ApplicationDataSdkResult you should use it to get the Session Intent.

The session intent is generated with a request to https://[API_ENDPOINT]/api/v4/payments/tap-to-phone, built from the ApplicationDataSdkResult.Success values plus the billing details of the transaction.

This request MUST be performed by a Third Party Backend when a Third Party App requests it.

This request must have a header Authorization with a valid token provided to the Tenant. To generate this token, please refer to Authentication.

The most important part of the request is:

{
"client_id": {
"application_name": "geopagos",
"application_version": "1.0.0",
"fingerprint_id": "61:A2:0B:70:70:D2:DB:43:52:61:CB:75:E5:04:53:40:A8:38:7C",
"sdk_version": "1.2.3",
"operating_system": "Android"
}
}

Every value comes from ApplicationDataSdkResult.Success: applicationName, versionName and deviceId map to application_name, application_version and fingerprint_id respectively. Send sdk_version and operating_system only when the SDK returns them, since both are nullable.

If all provided data are valid the endpoint will answer a JSON object with the created session id and the encrypted session intent.

The values encrypted_data, hash and encrypted_key are required to start a transaction, and reference_number is required to verify it afterwards.

important

Any support needed to track issues will require the sessionId linked to the session that causes the issue. Please save this value for further assistance.

For the full request and response schema see the API reference.

Start transaction

Once you have the Session Intent to start the transaction, you need to create an Activity Result Launcher with the function getTransactionContractWithToken()

val transactionActivity = registerForActivityResult(
TapOnPhoneInvocationSdk.getTransactionContractWithToken()) { result ->
handleResult(result)
}

Then launch the transaction passing the session intent

transactionActivity.launch(
SdkSessionWithTokenIntent(SESSION_INTENT, AUTH_TOKEN)
)

Where:

  • SESSION_INTENT is an instance of SdkEncryptedSessionIntent, which wraps the encrypted data, the hash and the encrypted key.
  • AUTH_TOKEN is an Authorization token required to interact with custom services by the ToPP. To generate this token, please refer to Authentication.

Both types map directly to the values returned by the session intent request:

SdkSessionWithTokenIntent(
SdkEncryptedSessionIntent(
sessionIntent = session.encryptedData,
hash = session.hash,
encryptedKey = session.encryptedKey
),
jwtToken = AUTH_TOKEN
)

TapOnPhoneInvocationSdkResult.Success

It exposes a data property of type TapOnPhoneInvocationSdkSuccessData:

PropertyTypeDescription
cvmResultTapOnPhoneInvocationSdkCvmResultHow the cardholder was verified during the transaction
authorizationCodeString?Authorization code returned by the Online Processor. Required to verify the transaction

cvmResult can take the following values:

ValueDescription
NO_CVMNo cardholder verification was needed
SIGNATUREThe cardholder must be requested to sign. See Upload the signature
PINA PIN was requested and entered
CONFIRMATION_CODE_VERIFIEDA confirmation code was verified

TapOnPhoneInvocationSdkResult.Error

It exposes an error property. Every TapOnPhoneInvocationSdkError carries an errorCode and an errorDescription, and TransactionAborted additionally carries errorHistory with the errors that occurred before the transaction was aborted. Log these values — they are what the Geopagos support team needs to trace the transaction.

ErrorDescription
InvalidTransactionIntentThe session intent was malformed or expired
TransactionDeniedThe transaction was declined
TransactionAbortedThe transaction was interrupted or timed out. errorHistory holds the sequence of events
ConfigurationErrorThe ToPP app configuration is invalid
SecurityError.UpdateRequiredThe ToPP app must be updated before proceeding
SecurityError.OtherA security check failed (e.g. device integrity)
InternalErrorAn unexpected internal error occurred
NfcNotAvailableNFC is not enabled or not available on the device
EULANotAcceptedThe user has not accepted the end user license agreement in the ToPP app

Handling the Result

errorCode and errorDescription are available on every error, so you only need to narrow the type for the cases your integration treats differently:

fun handleResult(result: TapOnPhoneInvocationSdkResult) {
when (result) {
is TapOnPhoneInvocationSdkResult.Success -> {
if (result.data.cvmResult == TapOnPhoneInvocationSdkCvmResult.SIGNATURE) {
uploadSignature()
}
// Verify the transaction before showing an approved message to the user
confirmTransaction(result.data.authorizationCode)
}
is TapOnPhoneInvocationSdkResult.Error -> {
val error = result.error
Log.e(TAG, "Transaction failed: ${error.errorDescription} (${error.errorCode})")
if (error is TapOnPhoneInvocationSdkError.TransactionAborted) {
Log.e(TAG, "Error history: ${error.errorHistory}")
}
}
}
}

Upload the signature

When cvmResult is SIGNATURE, the cardholder must be requested to sign. Capture the signature in your app and upload it before verifying the transaction.

Call https://[API_ENDPOINT]/api/v4/payments/:ref_number/signature sending the signature as a Base64-encoded image.

The ref_number param refers to the transaction reference number. And it is obtained when you Get a session intent.

For the full request and response schema see the API reference.

Transaction verification

When a transaction result is Success, it is a requirement to verify the transaction status via API prior to show the "approved" message to your user. This is to ensure the transaction state and avoid fraud attempts.

Call https://[API_ENDPOINT]/api/v4/payments/:ref_number/confirm sending the authorizationCode obtained from TapOnPhoneInvocationSdkResult.Success.

The ref_number param refers to the transaction reference number. And it is obtained when you Get a session intent.

For the full request and response schema see the API reference.

Release

When you no longer need to use the SDK, you must call

TapOnPhoneInvocationSdk.release()

This will release all resources used by the SDK. All objects retained after release() was called will no longer be valid. You can always init the SDK (as seen previously in this setup guide) to use it again after it was released.