TerminalSDK Library Documentation
The TerminalSDK
library provides a set of classes and methods for handling user authentication, terminal connections, and card transactions.
Part 1: Preparing the Required Assets
To use the library, you must provide specific assets and configurations.
Information to Provide to the Nearpay Team
When setting up your integration with Nearpay, ensure that you provide the following details:
-
Android Package Name
- This is the unique identifier for your Android application.
- Example:
com.yourcompany.yourapp
-
PEM Certificate
- A PEM (Privacy-Enhanced Mail) certificate is required for secure communication.
- You can generate a PEM certificate by following the steps outlined here (Replace with the actual link to instructions). here.
Ensure these details are accurate before submitting them to Nearpay for a smooth integration process.
Google Play Integrity and Huawei Safety Detect
This library uses Google Play Integrity (Mandatory) and Huawei Safety Detect (Optional) to verify the integrity of the device.
Google Play Integrity (Mandatory)
To make the library work, you need to have a Google Cloud project with Play Integrity enabled and pass the Google Cloud project number in the builder. Here are the steps to do so:
Create a Google Cloud Project:
- Go to the Google Cloud Console.
- Create a new project or use an existing one.
- Get the Project Number:
- Go to the Google Cloud Console.
- Click on the project you created.
- Go to the project settings.
- Copy the project number.
- Enable Play Integrity API:
- Go to the Google Play Console.
- Navigate to Release > App Integrity.
- Under the Play Integrity API, select Link a Cloud project.
- Choose the Cloud project you want to link to your app, which will enable Play Integrity API responses.
- This may change in the future, so please refer to the official documentation here: Google Play Integrity documentation
- Pass the Project Number in the Builder:
- Use the
googleCloudProjectNumber
method in the builder to pass the project number.
- Use the
Huawei Safety Detect (Optional)
To use Huawei Safety Detect, you need to have a Huawei Developer account and pass the Safety Detect API key in the builder. Here are the steps to do so:
- Create a Huawei Developer Account:
- Go to the Huawei Developer Console.
- Create a new account or use an existing one.
- Create an App:
- Go to AppGallery Connect.
- Create a new app or use an existing one.
- Enable Safety Detect:
- Go to the AppGallery Connect console.
- Navigate to Develop > Security Detection.
- Enable Safety Detect.
- Get the Safety Detect API Key:
- Go to the AppGallery Connect console.
- Navigate to Develop > Security Detection.
- Click on the Safety Detect tab.
- Copy the API key.
- Pass the API Key in the Builder:
- Use the
safetyDetectApiKey
method in the builder to pass the Safety Detect API key.
- Use the
Configuring the Secure Maven Repository / Dependencies
For the ReaderCore library, you can include the following configuration in your root-level settings.gradle(.kts)
file:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven(url = "https://developer.huawei.com/repo/")
maven {
url = uri("https://gitlab.com/api/v4/projects/37026421/packages/maven")
credentials(HttpHeaderCredentials::class) {
name = "Private-Token"
value = "nearpayPosGitlabReadToken"
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
}
if your project is using Groovy settings.gradle
, you can use the following configuration:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url "https://developer.huawei.com/repo/" }
maven {
url "https://gitlab.com/api/v4/projects/37026421/packages/maven"
credentials(HttpHeaderCredentials) {
name = "Private-Token"
value = "nearpayPosGitlabReadToken"
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
}
You should include the following dependencies in your Module level build.gradle
file:
implementation("io.nearpay:terminalsdk-debug:0.0.38")
implementation("com.google.android.gms:play-services-location:20.0.0")
implementation("com.huawei.hms:location:6.4.0.300")
In addition, you have to change the minSdk
version to 28 and the versionName
to 75 in your build.gradle
file:
android {
defaultConfig {
applicationId = "com.example.terminalSDK1"
minSdk = 28
targetSdk = 30
versionCode = 1
versionName = "75"
}
}
Contact Nearpay to register your applicationId
and get the necessary credentials.
AndroidManifest.xml Configuration
In your AndroidManifest.xml
file, add the following line:
<application
android:allowBackup="true"
tools:replace="android:allowBackup" // Add this line to avoid manifest merger issues
...
Part 2: Getting Started with TerminalSDK
To start using TerminalSDK
, initialize it with the necessary configurations.
// initializing the terminalSDK may throw an exception, so wrap it in a try-catch block
try {
val nearpay = TerminalSDK.Builder()
.activity(this) // Sets the activity context
.environment(SdkEnvironment.SANDBOX) // Choose SANDBOX or PRODUCTION
.googleCloudProjectNumber(12345678) // Set Google Cloud project number
.huaweiSafetyDetectApiKey("your_api_key") // Set Huawei API key
.country(Country.SA) // Set country
.build()
} catch (e: Throwable) {
Timber.e("Error initializing TerminalSDK: $e")
}
Permissions and Requirements
Check Required Permissions
The SDK provides methods to check and verify required permissions and device capabilities.
Check all required permissions and return a list of PermissionStatus objects.
// Check all required permissions
val permissionStatuses = nearpay.checkRequiredPermissions()
permissionStatuses.forEach { status ->
if (!status.isGranted) {
// Handle missing permission
Log.d("Permissions", "Missing permission: ${status.permission}")
}
}
The required permissions include:
Manifest.permission.ACCESS_FINE_LOCATION
Manifest.permission.ACCESS_NETWORK_STATE
Manifest.permission.INTERNET
Manifest.permission.READ_PHONE_STATE
Manifest.permission.NFC
The following code snippets show how to check permissions, then ask for missing permissions if needed, and also check if NFC and WiFi are enabled.
var PERMISSIONS_REQUEST_CODE = 0
// Check permissions
val missingPermissions = nearpay.checkRequiredPermissions()
.filter { !it.isGranted }
.map { it.permission }
if (missingPermissions.isNotEmpty()) {
// Request missing permissions
ActivityCompat.requestPermissions(
this,
missingPermissions.toTypedArray(),
PERMISSIONS_REQUEST_CODE //0 for example
)
}
// Check NFC
if (!nearpay.isNfcEnabled(this)) {
Log.d("MainActivity", "NFC is disabled");
}
// Check WiFi
if (!nearpay.isWifiEnabled(this)) {
Log.d("MainActivity", "WiFi is disabled");
}
Part 3: Authentication
Send OTP
The SDK supports both mobile and email OTP authentication.
Mobile Authentication
val mobileLogin = MobileLogin("+966532996473")
nearpay.sendOTP(mobileLogin, object : SendOTPMobileListener {
override fun onSendOTPMobileSuccess(otpResponse: OtpResponse) {
Log.d("Login", " onSendOTPMobileSuccess ($otpResponse)")
}
override fun onSendOTPMobileFailure(otpMobileFailure: OTPMobileFailure) {
Log.d("Login", " onSendOTPMobileFailure ($otpMobileFailure)")
}
})
Email Authentication
val emailLogin = EmailLogin("[email protected]")
nearpay.sendOTP(emailLogin, object : SendOTPEmailListener {
override fun onSendOTPEmailSuccess(otpResponse: OtpResponse) {
Log.d("Login", " onSendOTPEmailSuccess ($otpResponse)")
}
override fun onSendOTPEmailFailure(otpEmailFailure: OTPEmailFailure) {
Log.d("Login", " onSendOTPEmailFailure ($otpEmailFailure)")
}
})
Verify OTP
After sending the OTP, verify it to authenticate the user.
Mobile Verification
val loginData = LoginData(
mobile = "+966532996473",
code = "123456"
)
nearpay.verify(loginData, object : VerifyMobileListener {
override fun onVerifyMobileSuccess(user: User) {
Log.d("Login", " onVerifyMobileSuccess ($user.name)")
}
override fun onVerifyMobileFailure(verifyMobileFailure: VerifyMobileFailure) {
Log.d("Login", " onVerifyMobileFailure ($failure)")
}
})
Email Verification
val loginData = LoginData(
email = "[email protected]",
code = "123456"
)
nearpay.verify(loginData, object : VerifyEmailListener {
override fun onVerifyEmailSuccess(user: User) {
Log.d("Login", " onVerifyEmailSuccess ($user.name)")
}
override fun onVerifyEmailFailure(verifyEmailFailure: VerifyEmailFailure) {
Log.d("Login", " onVerifyEmailFailure ($verifyMobileFailure)")
}
})
JWT Verification
val loginData = JWTLoginData(
jwt = "jwt_token"
)
nearpay.jwtLogin(loginData, object : JWTLoginListener {
override fun onJWTLoginSuccess(terminal: Terminal) {
Log.d("Login", "JWT Login success + ${terminal.terminalUUID}")
}
override fun onJWTLoginFailure(jwtLoginFailure: JWTLoginFailure) {
Log.d("Login", "JWT Login failure: $jwtLoginFailure")
}
})
Get User
You can also get a User instance after calling the getUserByUUID method if the user has already been authenticated before using the SDK and you have their UUID from the previously returned User instance.
Saving the user UUID is the responsibility of the developer, not the SDK.
try{
val user = nearpay.getUserByUUID(uuid)
} catch (e: Exception) {
Log.d("UserSDK", "User connection failed: ${e}")
}
// The returned user object also becomes the active user
Logout User
To log out a user and delete its instance from memory, call the logout method.
Takes a User UUID as a parameter and logs out the user.
try {
nearpay.logout(uuid)
} catch (e: Exception) {
Log.d("UserSDK", "User logout failed: ${e}")
}
Part 4: User Operations
The User class is initialized internally by the SDK and provides methods for managing terminals.
List Terminals
Retrieves a paginated list of terminals associated with the user.
Usage
lateinit var firstTerminal: Terminal
userInstance.listTerminals(
page = 1,
pageSize = 10,
filter = null, // You can pass the terminal ID to get a specific terminal
object : GetTerminalsListener {
override fun onGetTerminalsSuccess(terminalsConnection: List<TerminalConnection>) {
// Handle success
terminalsConnection.firstOrNull()?.let { terminal ->
// Access terminal data
val terminalName = terminal.terminalConnectionData.name
// Update UI or store reference
firstTerminal = terminal
}
}
override fun onGetTerminalsFailure(getTerminalsFailure: GetTerminalsFailure) {
// Handle failure
Log.d("Terminals", "Terminals list failure: $getTerminalsFailure")
}
},
)
Part 5: Terminal Connection Operations
Connect Terminal
Establishes a connection with a terminal.
Usage
firstTerminal.connect(
activity = this,
listener = object : ConnectTerminalListener {
override fun onConnectTerminalSuccess(terminal: Terminal) {
// Terminal connected successfully
// Store terminal instance for future operations
terminalInstance = terminal
}
override fun onConnectTerminalFailure(connectTerminalFailure: ConnectTerminalFailure) {
// Handle failure
Log.d("Terminal", "Terminal connection failed: $connectTerminalFailure")
}
}
)
Part 6: Terminal Operations
Before getting into Terminal class functions, you can also get a Terminal instance after calling the getTerminal method and passing the terminal's ID instead of using a TerminalConnection instance.
Get Terminal
Retrieves a Terminal instance for a specific terminal ID.
try {
private var tid: String = "058594894-4545945-45454"
val terminalInstance = nearpay.getTerminal(
activity = this,
tid = tid
)
} catch (e: Exception) {
Log.d("TerminalSDK", "Terminal connection failed: ${e}")
}
Purchase
Initiates a purchase transaction by reading the card and sending the transaction.
var amount = 100
var transactionUUID = UUID.randomUUID().toString()
terminal.purchase(
amount = amount,
scheme = null, // eg.PaymentScheme.VISA, specifying this as null will allow all schemes to be accepted
transactionUUID = transactionUUID // the transaction UUID should be unique for each transaction and managed by the developer to communicate with the SDK
readCardListener = object : ReadCardListener {
override fun onReadCardSuccess() {
// Card read successfully
Log.d("ReadCard", "Card read successfully")
}
// Called when the card reading process fails - issues with the specific card or its interaction
// Examples: card removed too quickly, unreadable card, wrong card orientation
override fun onReadCardFailure(readCardFailure: ReadCardFailure) {
// Handle card read failure
Log.d("ReadCard", "Card read failure: $readCardFailure")
}
override fun onReaderWaiting() {
// Reader waiting for card
Log.d("ReadCard", "Reader waiting for card")
}
override fun onReaderReading() {
// Reading card in progress
Log.d("ReadCard", "Reading card in progress")
}
override fun onReaderRetry() {
// Reader retry needed
Log.d("ReadCard", "Reader retry needed")
}
override fun onPinEntering() {
// PIN entry in progress
Log.d("ReadCard", "PIN entry in progress")
}
override fun onReaderFinished() {
// Card read completed
Log.d("ReadCard", "Card read completed")
}
override fun onReadingStarted() {
// Card read started
Log.d("ReadCard", "Card read started")
}
// Called when the card reader device itself encounters an error
// Examples: hardware malfunction, connection issues, device not ready
override fun onReaderError(error: String?) {
// Handle reader error
Log.d("ReadCard", "Reader error: $error")
}
},
sendTransactionListener = object : SendTransactionListener {
override fun onSendTransactionSuccess(response: TransactionResponse) {
// Handle successful transaction
Log.d("Transaction", "Transaction success: $response")
}
override fun onSendTransactionFailure(failure: SendTransactionFailure) {
// Handle transaction failure
Log.d("Transaction", "Transaction failure: $failure")
}
}
)
Refund
Initiates a refund transaction by reading the card and sending the transaction.
var amount = 1000L
var transactionUUID = "1234567890"
var refundUUID = UUID.randomUUID().toString()
terminal.refund(
amount = amount,
scheme = null, // eg.PaymentScheme.VISA, specifying this as null will allow all schemes to be accepted
transactionUUID = transactionUUID, // the same transaction UUID used in the purchase transaction
refundUUID = refundUUID, // the refund UUID should be unique for each refund transaction and managed by the developer to communicate with the SDK
readCardListener = object : ReadCardListener {
// Card reading callbacks
// Same implementation as purchase
},
refundTransactionListener = object : RefundTransactionListener {
override fun onRefundTransactionSuccess(transactionResponse: TransactionResponse) {
// Handle successful refund
Log.d("Refund", "Refund success: $transactionResponse")
}
override fun onRefundTransactionFailure(refundTransactionFailure: RefundTransactionFailure) {
// Handle refund failure
Log.d("Refund", "Refund failure: $refundTransactionFailure")
}
}
)
Cancel Transaction
Cancels a transaction by providing the transaction ID.
var transactionUUID = "transaction-uuid"
terminal.cancelTransaction(
id = transactionUUID, // Transaction ID
cancelTransactionListener = object : CancelTransactionListener {
override fun onCancelTransactionSuccess(canceledState : CanceledState) {
Log.d("Cancel", "Transaction Cancelled: ${canceledState.canceled}")
}
override fun onCancelTransactionFailure(cancelTransactionFailure: CancelTransactionFailure) {
Log.d("Cancel", "Transaction Cancelled Failure: $cancelTransactionFailure")
}
}
)
Reverse Transaction
Reverses a transaction by providing the transaction ID.
var transactionUUID = "transaction-uuid"
terminal.reverseTransaction(
id = transactionUUID,
object : ReverseTransactionListener {
override fun onReverseTransactionSuccess(transactionResponse: TransactionResponse) {
CoroutineScope(Dispatchers.Main).launch {
Log.d("Transaction", "Transaction reversed: $transactionResponse")
}
}
override fun onReverseTransactionFailure(reverseTransactionFailure: ReverseTransactionFailure) {
Log.d("Transaction", "Transaction reverse failure: $reverseTransactionFailure")
}
}
)
Get Transaction Details
Retrieves the details of a specific transaction by providing the transaction ID.
var transactionID = "transaction-id"
terminal.getTransaction(
transactionID, // Transaction ID
getTransactionListener = object : GetTransactionListener {
override fun onGetTransactionSuccess(transaction: ReceiptsResponse) {
Log.d("Transaction", "Transaction Details: $transaction")
}
override fun onGetTransactionFailure(error: GetTransactionFailure) {
Log.d("Transaction", "Transaction Details Failure: $error")
}
}
)
Get Transactions List
Retrieves a paginated list of transactions.
terminal.getTransactionsList(
page = 1,
pageSize = 10,
isReconciled = true, // do not specify it if all transactions are needed
startDate = 1733961600000, endDate = 1735084800000, // Optional date range in timestamp format
customerReferenceNumber = "customer_reference_number", // Optional customer reference number
getTransactionsListListener = object : GetTransactionsListListener {
override fun onGetTransactionsListSuccess(transactionsList: TransactionsResponse) {
Log.d("Transactions", "Transactions List: $transactionsList")
}
override fun onGetTransactionsListFailure(error: GetTransactionsListFailure) {
Log.d("Transactions", "Transactions List Failure: $error")
}
}
)
Reconcile Transactions
Reconciles a terminal's unreconciled transactions.
terminal.reconcile(
reconcileListener = object : ReconcileTransactionListener {
override fun onReconcileTransactionSuccess(reconciliationReceiptsResponse: ReconciliationReceiptsResponse) {
// Handle success
Log.d("Reconcile", "Reconcile Success: $reconciliationReceiptsResponse")
}
override fun onReconcileTransactionFailure(reconcileTransactionFailure: ReconcileTransactionFailure) {
// Handle failure
Log.d("Reconcile", "Reconcile Failure: $reconcileTransactionFailure")
}
}
)
Get Reconciliation List
Retrieves a paginated list of reconciliations.
terminal.getReconciliationList(
page = 1,
pageSize = 10,
startDate = null, //in timestamp format
endDate = null, //in timestamp format
getReconciliationListListener = object : GetReconciliationListListener {
override fun onGetReconciliationListSuccess(reconciliationListResponse: ReconciliationListResponse) {
// Handle success
Log.d("Reconciliation", "Reconciliation List: $reconciliationListResponse")
}
override fun onGetReconciliationListFailure(error: GetReconciliationListFailure) {
// Handle failure
Log.d("Reconciliation", "Reconciliation List Failure: $error")
}
}
)
Get Reconciliation Details
Retrieves the details of a specific reconciliation by providing the reconciliation ID.
terminal.getReconciliation(
"reconciliation-id", // Reconciliation ID
getReconciliationListListener = object : GetReconciliationListener {
override fun onGetReconciliationSuccess(reconciliationReceiptsResponse: ReconciliationReceiptsResponse) {
// Handle success
Log.d("handleReadCard", "GetReconciliation success $reconciliationReceiptsResponse")
}
override fun onGetReconciliationFailure(error: GetReconciliationFailure) {
// Handle failure
Log.d("handleReadCard", "GetReconciliation failure $error")
}
}
)
Part 7: Callback Listeners
Callback Listeners
SendOTPMobileListener
-
onSendOTPMobileSuccess(OtpResponse otpResponse)
Called when OTP is successfully sent. -
onSendOTPMobileFailure(OTPMobileFailure otpMobileFailure)
Called when OTP sending fails.
SendOTPEmailListener
-
onSendOTPEmailSuccess(OtpResponse otpResponse)
Called when OTP is successfully sent to email. -
onSendOTPEmailFailure(OTPEmailFailure otpEmailFailure)
Called when OTP sending to email fails.
VerifyMobileListener
-
onVerifyMobileSuccess(User user)
Called when OTP verification and user authentication succeed. -
onVerifyMobileFailure(VerifyMobileFailure verifyMobileFailure)
Called when OTP verification fails.
VerifyEmailListener
-
onVerifyEmailSuccess(User user)
Called when email OTP verification succeeds. -
onVerifyEmailFailure(VerifyEmailFailure verifyEmailFailure)
Called when email OTP verification fails.
GetTerminalsListener
-
onGetTerminalsSuccess(List<TerminalConnection> terminalsConnection)
Called when terminals are successfully retrieved. -
onGetTerminalsFailure(GetTerminalsFailure getTerminalsFailure)
Called when fetching terminals fails.
ConnectTerminalListener
-
onConnectTerminalSuccess(Terminal terminal)
Called when terminal connection is successful. -
onConnectTerminalFailure(ConnectTerminalFailure connectTerminalFailure)
Called when terminal connection fails.
ReadCardListener
-
onReadCardSuccess()
Called when card reading is successful. -
onReadCardFailure(ReadCardFailure readCardFailure)
Called when card reading fails. -
onReaderWaiting()
Called when the reader is waiting for a card. -
onReaderReading()
Called when the reader is actively reading the card. -
onReaderRetry()
Called when the reader is retrying. -
onPinEntering()
Called when the reader prompts for PIN entry. -
onReaderFinished()
Called when the reader operation is completed. -
onReaderError(String error)
Called when an error occurs in the reader.
SendTransactionListener
-
onSendTransactionSuccess(TransactionResponse transactionResponse)
Called when the transaction is successfully processed. -
onSendTransactionFailure(SendTransactionFailure sendTransactionFailure)
Called when the transaction fails.
GetTransactionsListListener
-
onGetTransactionsListSuccess(TransactionsResponse transactionsList)
Called when the transactions list is successfully retrieved. -
onGetTransactionsListFailure(GetTransactionsListFailure error)
Called when fetching transactions list fails.
GetTransactionListener
-
onGetTransactionSuccess(ReceiptsResponse transaction)
Called when a specific transaction's details are successfully retrieved. -
onGetTransactionFailure(GetTransactionFailure error)
Called when fetching transaction details fails.
ReconcileTransactionListener
-
onReconcileTransactionSuccess(ReconciliationReceiptsResponse reconciliationReceiptsResponse)
Called when transaction reconciliation is successful. -
onReconcileTransactionFailure(ReconcileTransactionFailure reconcileTransactionFailure)
Called when transaction reconciliation fails.
GetReconciliationListListener
-
onGetReconciliationListSuccess(ReconciliationListResponse reconciliationListResponse)
Called when the reconciliation list is successfully retrieved. -
onGetReconciliationListFailure(GetReconciliationListFailure error)
Called when fetching reconciliation list fails.
GetReconciliationListener
-
onGetReconciliationSuccess(ReconciliationReceiptsResponse reconciliationReceiptsResponse)
Called when specific reconciliation details are successfully retrieved. -
onGetReconciliationFailure(GetReconciliationFailure error)
Called when fetching reconciliation details fails.
CancelTransactionListener
-
onCancelTransactionSuccess(Canceled canceled)
Called when transaction cancellation is successful. -
onCancelTransactionFailure(CancelTransactionFailure cancelTransactionFailure)
Called when transaction cancellation fails.
RefundTransactionListener
-
onRefundTransactionSuccess(TransactionResponse transactionResponse)
Called when refund transaction is successful. -
onRefundTransactionFailure(RefundTransactionFailure refundTransactionFailure)
Called when refund transaction fails.