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

  1. 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")
            }
        }
    }
}
  1. Include the following dependencies in your Module level build.gradle file:
implementation("io.nearpay:terminalsdk-release:0.0.70")
implementation("com.google.android.gms:play-services-location:20.0.0")
implementation("com.huawei.hms:location:6.4.0.300")
  1. change the minSdk version to 28 in your build.gradle file:

  2. Add the following line in your AndroidManifest.xml file :


<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

...
  1. 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
        .country(Country.SA)  // Set country SA, TR, USA, KEN , 
        .build()
    } catch (e: Throwable) {
        Timber.e("Error initializing TerminalSDK: $e")
    }
  1. Add required permissions :
  • Manifest.permission.ACCESS_FINE_LOCATION
  • Manifest.permission.ACCESS_NETWORK_STATE
  • Manifest.permission.INTERNET
  • Manifest.permission.READ_PHONE_STATE
  • Manifest.permission.NFC
  1. 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)")
    }
})
  1. 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)")
    }
})

  1. 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")
        }
    },
    )

  1. 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")
        }
    }
)
  1. Purchase transaction
    var amount = 100
    var transactionUUID = UUID.randomUUID().toString() // the transaction 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
    transactionUUID = transactionUUID,
    customerReferenceNumber = customerReferenceNumber, 
    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
        public void onReaderDisplayed() { 
            Log.d("ReaderCard", "Reader Displayed")
        }

        @Override
        public void 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(transactionResponse: TransactionResponse) {
            // Handle completed transaction
            Log.d("Transaction", "Transaction completed: $transactionResponse")
            // To got the receipt based on the country you can got it like :
            // transactionResponse.events[0].receipt.getMadaReceipt() for Saudi Arabia
            // transactionResponse.events[0].receipt.getEPXReceipt() for USA
            // transactionResponse.events[0].receipt.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.