suspend in the library must run in a compatible CoroutineThis process is executed according to EMV rules and after passing compliant authentication in SHVA. The EMV process is executed according to a combination of various parameters, both parameters related to terminal settings and card settings. The library must provide feedback regarding the entire EMV process (passing compliant messages, providing feedback and instructions if there are errors).
If the EMV process executes “smoothly”, proceed to the transaction execution stage with the clearing company, credit companies, and SHVA. The library must provide feedback on the transaction status upon completion.
📌 Important: First, you need to integrate the library as part of the libs folder in the project.
The library contains three main objects:
This object was created to perform device initialization (initialization includes receiving parameters and “burning” them into the device).
initDeviceConfigurationThe method must receive as a parameter an object identified with user details (user details are received from Pelcard) and returns a status according to whether the process succeeded or not. It is responsible for receiving configuration files and burning them into the device.
⚠️ Note: Do not perform any transaction until terminal initialization has been completed. It is recommended to perform initialization with each application launch.
resetInitConfigurationThe method is responsible for deleting the parameters burned into the device.
private lateinit var nexgoDeviceConfig: NexgoDeviceConfig
override suspend fun initNexgoLibrary(
terminalNum: String,
shopNum: String,
username: String,
password: String
): Boolean {
nexgoDeviceConfig = NexgoDeviceConfig(context)
this.shopNum = shopNum
libraryAuthDetails = ClientDetails(username, password, terminalNum)
val res = nexgoDeviceConfig.initDeviceConfiguration(libraryAuthDetails)
Logg.df("initNexgoLibrary result = $res")
return res == InitResCode.INIT_SUCCESSFUL
}
This object was created to enable access to various components of the device such as LEDs, beeper, printer, kiosk mode (screen lock).
You should independently check which methods are exposed to the user and what parameters they receive.
💡 Note on receipt printing: The method receives a pre-defined object which essentially includes parameters received in response to a transaction and must be built independently.
override fun getSerialNumber(): String {
return nexgoDeviceController.getDeviceSerial()
}
override fun makeBeep() {
nexgoDeviceController.controlBeeper(DeviceBeepLevel.LEVEL_1)
}
override fun setKioskMode(isEnable: Boolean) {
if(isEnable)
nexgoDeviceController.enableKioskMode()
else
nexgoDeviceController.disableKioskMode()
}
The central object responsible for transaction execution. Before explaining it, we’ll cover the listener used to pass messages and events during a transaction.
A listener that you must subscribe to in order to receive feedback on various events occurring during the transaction.
For example, PIN code entry events, or receiving continuous messages (messages like insert card, remove card, wait for approval, etc.) are received through the listener.
📡 Event Handling: I take care of providing the events and messages through the listener, but the programmer using the library must find the way to pass and translate the messages and events as desired. The example uses broadcastreceiver.
init {
nexgoDeviceController = NexgoDeviceController(context)
nexgoLibraryEventListener = NexgoLibraryEventsListener(context)
}
class NexgoLibraryEventsListener(private val context: Context): NexgoEventsListener {
init {
NexgoEventManager.registerListener(eventListener: this)
}
override fun onEventReceiveTransactionsMessages(msg: String) {
Logg.df("onEventReceiveTransactionsMessages: $msg")
onNewTransactionMessage(msg)
}
override fun onEventPin(pinEvent: PinEvent) {
Logg.df("onEventPin: ${pinEvent.name}")
when(pinEvent){
PinEvent.PIN_FIRST_TIME -> onNewPin(PIN_SCREEN_NAVIGATE)
PinEvent.PIN_ENTRY_COMPLETED -> onNewPin(PIN_ENTERED_EVENT)
PinEvent.PIN_ENTRY_DIGIT -> onNewPin(PIN_DIGIT_EVENT)
PinEvent.PIN_ENTRY_CLEAR -> onNewPin(PIN_CLEAR_DIGITS_EVENT)
else -> {}
}
}
private fun onNewTransactionMessage(msg: String){
val intent = Intent(action: "common-payment-event")
intent.putExtra(name: "transaction_message", msg)
context.sendBroadcast(intent)
}
private fun onNewPin(pinEvent: String){
val intent = Intent(action: "common-payment-event")
intent.putExtra(name: "pin_event", pinEvent)
context.sendBroadcast(intent)
}
}
To perform a transaction, you need to define an object called NexgoDeviceTransaction.
The object must be defined anew for each transaction. This object must receive the activity because there are cases where the library needs to provide UI (for example, for a hybrid card).
transaction = NexgoDeviceTransaction(appContext: getActivity() ?: context)
After the object is defined, you can access the various methods related to transaction execution.
The two methods that start the transaction are:
This method is intended to start a transaction that includes a full EMV process. It receives the user’s identification details (the same details object sent for device initialization), and additionally receives an object that the user must define with transaction details (amount, transaction type, etc.)
From the moment this method is called, the readers are activated and the user can perform a transaction using a physical card (of course, following the messages and events from the listener).
⚠️ New parameter in new versions: If the device works in regular configuration, readCardWithTimeout: Boolean in startTransaction must be false
To cancel the transaction, the user can access an additional method:
cancelTransaction()
To complete a J5 transaction, use the function:
completeDebitByUid(
clientDetails: ClientDetails,
uid: String,
newAmount: String,
newParamX: String,
trxId: String
): TransactionResCode
This method is intended to perform a phone transaction (manual transaction) – it receives the user’s identification details and an additional object that the user must define with the card details parameters.
After the transaction is completed or canceled (initiated cancellation, or any cancellation by the library due to EMV process or communication issues), the user receives a response.
The returned response is an ENUM value. If the value is:
TransactionResCode.TRANSACTION_OK
This means that the transaction process with the library passed successfully (does NOT mean the transaction was approved!!!!)
If this is the returned value, you can extract using getFinishedTransactionResult() the object containing all the transaction data.
Other ENUM values are left for user handling (cancellation, general error).
override suspend fun sendTransPayment(paymentFull: PaymentFull): PaymentFullRes? {
makeBeep()
queryID = paymentFull.queryID
transaction = NexgoDeviceTransaction(appContext: getActivity() ?: context)
tranData = PaymentUtil.createNexgoTransaction(paymentFull, shopNum) ?: return null
val res = transaction?.startTransaction(tranData, libraryAuthDetails)
Logg.df("sendTransPayment result = $res , nexgo transaction $tranData")
return when (res) {
TransactionResCode.TRANSACTION_OK -> {
val tranRes = transaction?.getFinishedTransactionResult()
val intOt = createIntOt(tranRes)
receiptData = tranRes?.let { initReceiptData(it) }
Logg.d("libraryResult: $tranRes")
PaymentFullRes(
paymentFull.queryID,
intOt,
customerRecipt: "",
customerReciptDetailed: "",
merchantRecipt: ""
)
}
TransactionResCode.TRANSACTION_CANCELED -> {
PaymentFullRes(
paymentFull.queryID,
IntOt(ashdStatus = CANCELED_BY_USER),
customerRecipt: "",
customerReciptDetailed: ""
)
}
else -> {
PaymentFullRes(
paymentFull.queryID,
IntOt(ashdStatus = TRANSACTION_FAILED),
customerRecipt: "",
customerReciptDetailed: ""
)
}
}
}
The library also provides an API through which pulses can be sent from the device.
Through an instance of an object of type NexgoDeviceController, you can access the initPulse method.
The method receives a mode (digit 0 or 1, if something else is sent – there is a default value) and sends a pulse accordingly.
override fun makePulsesWithGap(startMode: Int, endMode: Int, gap: Long) {
Logg.d("makePulsesWithGap startMode:$startMode endMode:$endMode gap:$gap")
nexgoDeviceController.initPulse(startMode)
try {
Thread.sleep(gap)
} catch (e: InterruptedException) {
throw RuntimeException(e)
}
nexgoDeviceController.initPulse(endMode)
}
Track2Reader is designed to read magnetic card data (2 Track) without performing a full EMV transaction.
💡 Important: In any regular payment transaction through startTransaction there is no need to use Track2Reader – the SDK will provide the data automatically.
class Track2Reader(appContext: Context) : OnCardInfoListener {
suspend fun startReadMag(): MagReadInfo
fun cancelMagRead()
}
Calling startReadMag() returns an object of type MagReadInfo containing:
MAG_READ_SUCCESS – Read succeededTIMEOUT_MAG – Card not passed in timeERROR_READ_MAG – Read error (incorrect swipe / multiple cards)CANCELED_MAG – Canceled by userstartReadMag() from Coroutine (it’s a suspend function)cancelMagRead() to cancelThis table includes the field name, whether it’s mandatory, its type, default value (if any), and a short description.
| Field | Mandatory | Type | Default | Description |
|---|---|---|---|---|
trxID |
Yes | String | – | Unique transaction ID – mandatory. 10-digit value |
shopNumber |
Yes | String | – | Shop number – identifier for the store |
amount |
Yes | Long | – | Transaction amount in minor currency units (e.g., agorot for ILS) |
cashbackAmount |
No | Long | 0 | Amount to be returned as cashback. Optional |
tranType |
Yes | TranType | – | Transaction type: 1 – Regular Debit 53 – Refund |
isPreAuth |
Yes | Boolean | – | Indicates if the transaction is pre-authorization (J5) |
creditTerms |
Yes | Int | – | Number of credit terms: 1 – Regular 3 – Direct Debit 6 – Credit 8 – Installments |
paymentsNumber |
No | Int | 0 | Number of installments. Optional |
firstPayment |
No | Long | 0 | First payment amount. Optional. Sent in Cents/Agorot |
fixedPayment |
No | Long | 0 | Fixed payment amount. Optional. Sent in Cents/Agorot |
countryCode |
No | String | “376” | Country code (default is ‘376’) |
currencyCode |
No | String | “376” | Currency code: 376 – Shekel 840 – Dollar 978 – Euro |
merchentId |
No | String? | “” | Merchant ID (nullable). Optional |
id |
No | String? | “” | Optional. Customer ID for manual transaction |
notes |
No | String | “” | Free-text notes for manual transaction. Optional |
sapakNum |
No | String | “” | Supplier number. Optional |
tranDate |
No | String? | today | Transaction date formatted as ‘MMdd’ (default is today) |
tranTime |
No | String? | now | Transaction time formatted as ‘hhmmss’ (default is now) |
This SDK provides a comprehensive solution for integrating Nexgo POS terminals into Android applications. It handles EMV processing, transaction management, and device control, allowing developers to focus on building their business logic and user interface.