POS Integration
Launch Mode
Quickstart (App to App)

Integration via App to App call

For app-to-app launch mode, the MineSec SoftPOS App (MSA) accept android Intent for various requests.

We provide a wrapper library - poslib that wraps the essential APIs and data classes for the ease of integration.


Prerequisite

Before start integrating with the MSA app, you'll need:


Gradle setup

In your machine/ environment, set up the credential for downloading the sdk package:

~/.gradle/gradle.properties
# minesec client registry
MINESEC_REGISTRY_LOGIN=minesec-product-support
MINESEC_REGISTRY_TOKEN={token-value}

Please seek our customer support for the token.

In your project, (usually) the settings.gradle or settings.gradle.kts, setup the maven registry like the following:

settings.gradle.kts
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
 
        // MineSec's maven registry
        maven {
            val MINESEC_REGISTRY_LOGIN: String? by settings
            val MINESEC_REGISTRY_TOKEN: String? by settings
 
            requireNotNull(MINESEC_REGISTRY_LOGIN) {
                """
                    Please set your MineSec Github credential in `gradle.properties`.
                    On local machine,
                    ** DO NOT **
                    ** DO NOT **
                    ** DO NOT **
                    Do not put it in the project's file. (and accidentally commit and push)
                    ** DO **
                    Do set it in your machine's global (~/.gradle/gradle.properties)
                """.trimIndent()
            }
            requireNotNull(MINESEC_REGISTRY_TOKEN)
 
            name = "MineSecMavenClientRegistry"
            url = uri("https://maven.pkg.github.com/theminesec/ms-registry-client")
            credentials {
                username = MINESEC_REGISTRY_LOGIN
                password = MINESEC_REGISTRY_TOKEN
            }
        }
    }
}
app/build.gradle.kts
dependencies {
    // ... other deps
    implementation("com.theminesec.app:poslib:1.2.4")
}

PosLib Setups

Create POS API

Passing along your white label app's package name to the MsaPosApi from the poslib:

private val msaPosApi = MsaPosApi(YOUR_MSA_PACKAGE_NAME)

Check App Install Status

Started from android 11 (API level 30) or higher, you'll need to include the <query> in the manifest to query package info.

→ More on Android dev doc (opens in a new tab)

app/src/main/AndroidManifest.xml
<queries>
  <!--e.g.-->
  <!--<package android:name="com.minesec.msa" />-->
  <package android:name="{YOUR_MSA_PACKAGE_NAME}" />
</queries>

Then you can check if the MSA app is installed on the device:

// require context for packageManager
// can pass in activity or compose view localContext
msaPosApi.isSoftPosInstalled(context)

Call gesture

The POS lib currently provides the ActivityResultContract (opens in a new tab) for the following MSA operations:

  • Activation: to activate the app and load configs from the backend
  • WarmUp: to warm up the SoftPOS app, perform the runtime checking on device and application
  • Transaction: to perform a transaction like sale, void, or refund
  • Enquiry: to check the previous transaction status
  • Settlement: to settle all the batch under the merchant

Generally you'll want to register for the activity result in either your activity or in compose scope with:

// [Activity] Register with the contract first
val someOperationLauncher = registerForActivityResult(operationContract) { result ->
  // handle the activity result here
  when (warmUpResult) {
    is PosResponse.Failed -> {
        /* handle failed */
    }
    is PosResponse.Success -> {
        /* handle success */
    }
  }
}
 
// [Compose Scope] Remember the launcher to avoid redundant instantiation during re-composition
val someOperationLauncher =
  rememberLauncherForActivityResult(operationContract) { result ->
    // handle the activity result here
    when (warmUpResult) {
      is PosResponse.Failed -> { /* handle failed */
      }
      is PosResponse.Success -> { /* handle success */
      }
    }
  }
 
// in call site
fun triggerOperation() {
  // optional data required for specific operation like the transaction amount
  someOperationLauncher.launch(requiredData)
}

Warm Up

The WarmUp calls the MSA to perform a series of runtime checking. It takes no argument.

// activity
private val warmUpLauncher = registerForActivityResult(msaPosApi.warmUpContract()) {
  // handle the activity result here
}
 
// compose scope
val warmUpLauncher = rememberLauncherForActivityResult(msaPosApi.warmUpContract()) {
  // handle the activity result here
}
 
// call site
fun triggerWarmUp() {
  warmUpLauncher.launch()
}

Activation

The Activation calls the MSA to activate the app, loads the necessary configs, like store information and EMV configs for later transaction.

Required the activationCode

// activity
private val activationLauncher = registerForActivityResult(msaPosApi.activationContract()) {
  // handle the activity result here
}
 
// compose scope
val activationLauncher = rememberLauncherForActivityResult(msaPosApi.activationContract()) {
  // handle the activity result here
}
 
// call site
fun triggerActivation(code: String) {
  activationLauncher.launch(PosRequest.Activation(activationCode = code))
}

Transaction

Initiate a transaction request, including the SALE, VOID, or REFUND.

For new transaction SALE, requires amount field.

For void & refund request, requires the orgTranId.

// activity
private val transactionLauncher = registerForActivityResult(msaPosApi.transactionContract()) {
  // handle the activity result here
}
 
// compose scope
val transactionLauncher = rememberLauncherForActivityResult(msaPosApi.transactionContract()) {
  // handle the activity result here
}
 
// call site
// sale request
fun triggerSaleTransaction(amount: BigDecimal, posMessageId: String) {
  transactionLauncher.launch(
    PosRequest.Transaction.Sale(
      amount = amount,
      // posMessageId - a reference from POS system, that will pass to MineSec backend for later query
      posMessageId = posMessageId,
      // auto dismiss the SoftPOS transaction result screen and return to Business App
      autoDismissResult = true
    )
  )
}
 
// void request
fun triggerVoidTransaction(originalTransactionId: String, passcode: String, posMessageId: String) {
  transactionLauncher.launch(
    PosRequest.Transaction.Void(
      orgTranId = originalTransactionId,
      // posMessageId - a reference from POS system, that will pass to MineSec backend for later query
      posMessageId = posMessageId,
      // merchant admin passcode for void/ refund
      adminPwd = passcode
    )
  )
}
 

Enquiry Transaction Status

To enquiry previous transaction by the transaction ID

// activity
private val enquiryTranLauncher = registerForActivityResult(msaPosApi.enquiryTranStatusContract()) {
  // handle the activity result here
}
 
// compose scope
val enquiryTranLauncher = rememberLauncherForActivityResult(msaPosApi.enquiryTranStatusContract()) {
  // handle the activity result here
}
 
// call site
fun triggerEnquiryTranStatus(orignalTranId: String) {
  enquiryTranLauncher.launch(PosRequest.EnquiryTranStatus(orgTranId = orignalTranId))
}

Reload configuration

Force to reload EMV configurations and payment keys

// activity
private val reloadConfigurationLauncher = registerForActivityResult(msaPosApi.reloadConfigurationContract()) {
  // handle the activity result here
}
 
// compose scope
val reloadConfigurationLauncher = rememberLauncherForActivityResult(msaPosApi.reloadConfigurationContract()) {
  // handle the activity result here
}
 
// call site
fun reloadConfiguration() {
  reloadConfigurationLauncher.launch()
}

Enquiry Bluetooth Connection Status

Obtain the Bluetooth connection status between phone and MPOS D177 device

// activity
private val enquiryBTConnectStatusLauncher = registerForActivityResult(msaPosApi.enquiryBTConnectStatusContract()) {
  // handle the activity result here
}
 
// compose scope
val enquiryBTConnectStatusLauncher = rememberLauncherForActivityResult(msaPosApi.enquiryBTConnectStatusContract()) {
  // handle the activity result here
}
 
// call site
fun enquiryBTConnectStatus() {
  enquiryBTConnectStatusLauncher.launch()
}

Settlement

To settle all available batches:

// activity
private val settlementLauncher = registerForActivityResult(msaPosApi.settlementContract()) {
  // handle the activity result here
}
 
// compose scope
val settlementLauncher = rememberLauncherForActivityResult(msaPosApi.settlementContract()) {
  // handle the activity result here
}
 
// call site
fun triggerSettlement(posMessageId: String) {
  settlementLauncher.launch(PosRequest.Settlement(posMessageId = posMessageId))
}

Response Code & Data Model

Refer to Response code for more details

Refer to Data Model for more details