Quick Start
This section provides a step-by-step guide for creating your first purchase transaction.
Before you begin
The NearPay team is required to create a sandbox account for you using your email and phone number, as well as your Android package name to initiate this integration process.
Additionally, you must possess an Android physical device capable of supporting NFC to test the integration and run the app on it.
Start your first transaction
- Configuring the Secure Maven Repository / Dependencies
To get the private token , you need to contact Nearpay to get the token for the private repository.
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" //will be supported from Nearpay Product Team
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
}
- Include the following dependencies in your Module level
build.gradlefile:
implementation("io.nearpay:terminalsdk-release:0.0.143")
implementation("com.google.android.gms:play-services-location:20.0.0")
implementation("com.huawei.hms:location:6.4.0.300")
-
change the
minSdkversion to 28 in yourbuild.gradlefile: -
Add the following line in your
AndroidManifest.xmlfile :
<application
android:allowBackup="true"
tools:replace="android:allowBackup" // Add this line to avoid manifest merger issues
Make sure the following tools namespace is present in your <manifest> tag:// xmlns:tools="http://schemas.android.com/tools"
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> // this tools namespace
...
- create a single instance of 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 or INTERNAL
.googleCloudProjectNumber(12345678) // Set Google Cloud project number
.huaweiSafetyDetectApiKey("your_api_key") // Set Huawei API key
.uiDockPosition(UiDockPosition.BOTTOM_CENTER) // Optional: set the location of the Tap to Pay modal
.country(Country.SA) // Set country SA, TR, USA, KEN ,
.build()
} catch (e: Throwable) {
Timber.e("Error initializing TerminalSDK: $e")
}
- Add required permissions :
Manifest.permission.ACCESS_FINE_LOCATIONManifest.permission.ACCESS_NETWORK_STATEManifest.permission.INTERNETManifest.permission.READ_PHONE_STATEManifest.permission.NFC
- Send OTP :
val mobileLogin = MobileLogin("+966500000000")
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)")
}
})
- Verify OTP :
After sending the OTP, verify it to authenticate the user.`
val loginData = LoginData(
mobile = "+966500000000",
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)")
}
})
- List Terminals
Retrieves a paginated list of terminals associated with the user.
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")
}
},
)
- Connect Terminal
Establishes a connection with a terminal.
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")
}
}
)
- Purchase transaction
var amount = 100
var intentUuid = UUID.randomUUID().toString() // the intent UUID should be unique for each transaction and managed by the developer to communicate with the SDK
var customerReferenceNumber = "" //[optional] any number you want to add as a refrence
terminal.purchase(
amount = amount,
scheme = null, // eg.PaymentScheme.VISA, specifying this as null will allow all schemes to be accepted
intentUUID = transactionUUID,
customerReferenceNumber = customerReferenceNumber,
readCardListener = object : ReadCardListener {
override fun onReaderDismissed() {
// Reader dismissed by user
Log.d("ReadCard", "Reader dismissed by user")
}
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 onReaderDisplayed() {
Log.d("ReaderCard", "Reader Displayed")
}
override fun onReaderClosed() {
Log.d("ReaderCard", "Reading Closed")
}
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 onSendTransactionCompleted(purchaseResponse: PurchaseResponse) {
// Handle completed transaction
//PurchaseResponse will return all transaction with same intent id "transactionUUID"
//purchaseResponse.status
//will return the status of last transaction of the same intent id
//If the value is "declined", that means the transaction is not completed successfully
//If it is "approved", that means the transaction is completed successfully
//Also you can get the boolean status from last receipt using
//purchaseResponse.getLastReceipt().getMadaReceipt().isApproved
//And the value will be true or false
Log.d("Transaction", "Transaction completed: $purchaseResponse")
// To get the approved receipt based on the country you can got it like :
// purchaseResponse.getLastReceipt().getMadaReceipt() for Saudi Arabia
// purchaseResponse.getLastReceipt().getEPXReceipt() for USA
// purchaseResponse.getLastReceipt().getBKMReceipt() for Turkey
}
override fun onSendTransactionFailure(failure: SendTransactionFailure) {
// Handle transaction failure
Log.d("Transaction", "Transaction failure: $failure")
}
}
)
Your setup is complete, allowing you to test the payment feature.