Developer Docs

Developer Docs

  • Overview
  • SDK
  • SoftPOS API
  • APOLLO API
  • Release Note
  • Languages iconEnglish
    • 繁體中文

›Module

Introduction

  • SDK overview
  • Getting started

Module

  • Transaction module
  • Configuration module
  • Printer module
  • Misc module

Transaction module

Call flow

To develop app using the transactionFlowController, it is recommended that you have knowledge or experience in EMV transaction flow.


Setup

Before starting a transaction, you should create an instance and connect the app to the terminal by getControllerInstance() and connectController().

The app shall be notified by onError if there's any errors occurred.

abstract class ApolloTransactionFlow(private val context: Context) : TransactionFlowDelegate {

    private var transactionFlowController: TransactionFlowController? = null

    fun connect(): Boolean {
        try {
            if (transactionFlowController == null) {
                // get instance
                transactionFlowController = getControllerInstance(context, this)

                // enable debug log display in console
                SPDeviceController.enableDebugLog(true)
            }
            // establish the communication channel with secure module
            transactionFlowController?.connectController()
        } catch (ex: Exception) {
            return false
        }
        return true
    }

    fun disconnect() {
        transactionFlowController?.disconnectController()
        transactionFlowController?.releaseControllerInstance()
    }

    override fun onError(errorType: ControllerError.Error?, message: String?) {
        // app handle error here
    }
}

EMV transaction flow

Start transaction


The app should put the amount, currency, check card mode and transaction sequence number (in case of refund or void) in the Hashtable and call the startTransactionFlow to start the EMV transaction.

fun startTransactionFlow(mode: BaseCardController.CheckCardMode, amount: String, amountCashback: String?, transactionSequenceNumber: String?, currency: Currency) {
    val data = Hashtable<String, Any>()

    // eg. BaseCardController.CheckCardMode.SWIPE_OR_INSERT_OR_TAP
    data["checkCardMode"] = mode

    // ISO 4217 currency code eg. 344 for HKD
    data["currencyCode"] = currency.numericCode.toString()

    // decimal string, eg. 2.00 for $2.00
    data["amount"] = amount

    data["transactionType"] = TransactionType.GOODS

    // indicate the transaction sequence number for refund or void
    if (transactionSequenceNumber != null) {
        data["transactionNo"] = transactionSequenceNumber
    }

    transactionFlowController?.startTransactionFlow(data)
}

The card reader shall be turned on and start detecting any card in the selected CheckCardMode. If no card interaction (tap, insert or swipe) is detected, the app shall receives onCardInteractionDetecting.

override fun onCardInteractionDetecting(p0: BaseCardController.CheckCardMode?) {
    // app handle the UI here
}

During the card detection phase, you can send abortDetection to terminate the transaction. onTransactionStatusReceived shall be returned with transaction status to the app.

fun abortDetection() {
    transactionFlowController?.abortDetection()
}

override fun onTransactionStatusReceived(p0: TransactionResult?) {
    // display transaction result
}

Application selection & read application data


If the card has more than one payment application, the app shall receive the onSelectAIDRequested with an array of AIDs. The app should select one of the AID by selectAID().

override fun onSelectAIDRequested(p0: ArrayList<String>?) {
    p0?.let {
        val items = it.toTypedArray()

        // display a dialog for user to select AID
        MaterialAlertDialogBuilder(context)
            .setTitle("Select Application")
            .setItems(items) { dialog, item ->
                transactionFlowController?.selectAID(item)
                dialog.dismiss()
            }
            .setCancelable(false)
            .show()
    }
}

After selecting the AID, the terminal reads necessary data from the card.


Data authentication & processing restrictions

The terminal then proceeds to data authentication and restriction processing with the card. If either one failed or declined, the app shall receives onTransactionStatusReceived with the status.

override fun onTransactionStatusReceived(p0: TransactionResult?) {
    // display transaction result
}

Confirmation

After the previous step, the app shall receive onConfirmationRequested. The app should prompt the user for confirmation and send back sendConfirmation(true) to the terminal.

override fun onConfirmationRequested() {
    transactionFlowController?.sendConfirmation(true)
}

Cardholder verification (PIN)

There are different cardholder verification method (CVM) in an EMV transaction, PIN is one of them.

If the transaction requires PIN entry, the app shall receives onPinEntryRequested.

override fun onPinEntryRequested(p0: PinEntrySource?) {
    // app display UI to prompt user to enter PIN
}

Terminal risk management

After cardholder verification, the transaction proceeds to the terminal risk management. This process takes place between the terminal and the card, if it fails, the app shall receive onTransactionStatusReceived.


Terminal & card action analysis

During this phase, the terminal shall determine the next action based on the result of the previous processing steps.


Online processing & script processing


If the card decided to go online for authentication, the app shall receive onOnlineProcessingRequested with the transaction data in a tag-length-value (TLV) format. The app should format the data in the acquirer/processor specified format e.g ISO8583, XML or JSON, and send to the acquirer/processor for authentication and wait for the response.

override fun onOnlineProcessRequested(p0: String?) {
    // app handle online processing here and get the online reply TLV data
}

Once getting the response from the acquirer/processor, the app should send the response data back to the terminal by sendOnlineProcessingData(data).

var replyTlv: String = ""

// app return the online processing data to the terminal
transactionFlowController?.sendOnlineProcessingData(replyTlv)

In normal circumstances, the app shall receive the following response(s) from the acquirer/processor.

TagParameter
8AAuthorization response code
91Issuer authentication data
71Issuer script template 1
72Issuer script template 2

Script processing

If there's any tag 71 or 72 in the responses from acquirer/processor, the terminal shall execute the script automatically once it receive the sendOnlineProcessingData() from the app.

No response from processor

If the app cannot get any responses from the acquirer/processor due to any abnormal situation, the app SHOULD send a null or an empty string to the terminal by sendOnlineProcessingData("") to complete EMV transaction flow.

Refer to the EMV Book 3 - Application Specification, Annex A: Data Elements Dictionary for the details of the tags


Completion


After the previous steps, the app shall receive onBatchDataReceived and onTransactionStatusReceived with the final transaction result from the card.

The app should store the batch data and upload to the processor later for settlement if required.

override fun onBatchDataReceived(p0: String?) {
    // store the batch data and upload to the processor later for settlement
}
override fun onTransactionStatusReceived(p0: TransactionResult?) {
    // App handle UI display
}

Last updated on 10/22/2020 by Jeff Kwok
← Getting startedConfiguration module →
  • Call flow
  • Setup
  • EMV transaction flow
    • Start transaction
    • Application selection & read application data
    • Data authentication & processing restrictions
    • Confirmation
    • Cardholder verification (PIN)
    • Terminal risk management
    • Terminal & card action analysis
    • Online processing & script processing
    • Completion
Developer Docs
About
APOLLO ecosystemProducts and servicesHardware spec
Development
Development with APOLLOSDK overviewAPI overview
Support
Spectra TechnologiesContact us
Copyright © 2022 Spectra Technologies.
Site by Docusaurus