Installing the SDK

Install the Koard Merchant SDK to enable tap-to-pay functionality in your Android application.

If you're ready to start developing, see our Android SDK implementation guide.

Get started with Koard

What you learn

In this guide, you'll learn:

  • How to add the Koard Merchant SDK to your Android project
  • How to configure Gradle dependencies
  • How to initialize the SDK in your application
  • How to verify your installation is working correctly
Prerequisites

Before you begin, ensure you have:

  • Android Studio Hedgehog or newer (required for modern Gradle support)
  • JDK 21 (required for compilation)
  • Android SDK 36 (minimum SDK 31 - Android 12)
  • Physical Android device with NFC support (Android 12+)
  • Valid Koard merchant account (configured in Koard MMS)
  • Install the Visa Kernel app on every NFC-enabled test device before running tap-to-pay flows (download from the Google Play Store)

Physical Device Required: Tap to Pay on Android requires a physical device with NFC hardware. The Android emulator does not support NFC contactless payments.

Developer Mode Workflow:

When working with Tap to Pay on Android, follow this important workflow:

  1. Enable Developer Mode - Turn on developer mode to install and test app revisions
  2. Install/Update Your App - Deploy your application updates
  3. Disable Developer Mode - You MUST turn off developer mode before running tap to pay transactions
  4. Run Transactions - Process payments with developer mode disabled

Tap to Pay transactions will NOT work if developer mode is enabled. This is a security requirement from the payment processor.

Step 1: Add the SDK Dependency

Option A: Manual AAR Installation

If you have the SDK as AAR files:

  1. Create a libs directory in your app module if it doesn't exist
  2. Copy the AAR file (e.g., koard-android-release.aar) to the libs/ directory
  3. Add the dependency in your build.gradle.kts:
dependencies {
    implementation(files("libs/koard-android-release.aar"))

    // Required dependencies
    implementation("androidx.core:core-ktx:1.12.0")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    implementation("com.squareup.retrofit2:converter-kotlinx-serialization:2.9.0")
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
}

Option B: Gradle (Coming Soon)

Add the Koard SDK to your app's build.gradle.kts:

dependencies {
    implementation("com.github.koardlabs:merchant-sdk:0.0.1")
}

Step 2: Configure Build Settings

Set Minimum SDK Version

Ensure your app's minimum SDK is set to Android 12 (API level 31):

android {
    defaultConfig {
        minSdk = 31
        targetSdk = 36
        compileSdk = 36
    }
}

Configure Java Compatibility

Set Java version to 21:

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_21
        targetCompatibility = JavaVersion.VERSION_21
    }

    kotlinOptions {
        jvmTarget = "21"
    }
}

Add Build Flavors (Optional)

For multi-environment support (dev, uat, prod):

android {
    flavorDimensions += "environment"

    productFlavors {
        create("prod") {
            dimension = "environment"
            // Production: https://api.koard.com
        }
        create("uat") {
            dimension = "environment"
            // UAT: https://api.uat.koard.com
        }
        create("dev") {
            dimension = "environment"
            // Development: https://api.dev.koard.com
        }
    }
}

Step 3: Initialize the SDK

Create Application Class

Initialize the SDK in your Application.onCreate() method on a worker thread:

import android.app.Application
import com.koardlabs.merchant.sdk.KoardMerchantSdk
import com.koardlabs.merchant.sdk.domain.KoardEnvironment
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        // Initialize SDK synchronously during app startup
        runBlocking {
            withContext(Dispatchers.IO) {
                try {
                    val environment = KoardEnvironment.PROD // or .UAT, .DEV

                    KoardMerchantSdk.initialize(
                        application = this@MyApplication,
                        apiKey = "your-api-key",
                        environment = environment
                    )

                    println("Koard SDK initialized successfully")
                } catch (e: Exception) {
                    // Handle initialization error
                    println("Failed to initialize SDK: ${e.message}")
                }
            }
        }
    }
}

Important:

  • SDK initialization must be performed on a worker thread (not the main UI thread). Always use Dispatchers.IO with coroutines.
  • The initialize() method takes application, apiKey, and environment - NOT merchantCode/merchantPin.
  • Merchant authentication is done separately using login(merchantCode, merchantPin) after initialization.

Register Application in Manifest

Add your custom Application class to AndroidManifest.xml:

<application
    android:name=".MyApplication"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/Theme.MyApp">
    <!-- Your activities here -->
</application>

Step 4: Authenticate Merchant

After SDK initialization, authenticate the merchant using their credentials:

import androidx.lifecycle.lifecycleScope
import com.koardlabs.merchant.sdk.KoardMerchantSdk
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        lifecycleScope.launch(Dispatchers.IO) {
            try {
                val sdk = KoardMerchantSdk.getInstance()

                // Login with merchant credentials
                val success = sdk.login(
                    merchantCode = "your-merchant-code",
                    merchantPin = "your-merchant-pin"
                )

                if (success) {
                    println("Merchant authenticated successfully")
                } else {
                    println("Authentication failed")
                }
            } catch (e: Exception) {
                println("Error: ${e.message}")
            }
        }
    }
}

The login() method authenticates the merchant and retrieves an access token. This must be done before processing transactions.

Test Basic Import

Add this import statement to verify the SDK is accessible:

import com.koardlabs.merchant.sdk.KoardMerchantSdk
import com.koardlabs.merchant.sdk.domain.KoardEnvironment
import com.koardlabs.merchant.sdk.domain.KoardLocation
import com.koardlabs.merchant.sdk.domain.exception.KoardException

If the imports succeed without errors, your installation is working correctly.

Step 5: Add Required Permissions

Add NFC permissions to your AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.NFC" />

<uses-feature
    android:name="android.hardware.nfc"
    android:required="true" />

Step 6: Transaction Processing

With installation complete you can now run Tap to Pay sessions. Keep these guardrails in mind:

  • sdk.sale(...) and sdk.preauth(...) are the only APIs that talk to the tap-to-pay thin client, so they return a cold Flow<KoardTransactionResponse> stream that drives the reader UI.
  • Every other payment action (capture, refund, reverse, incremental auth, receipts, tip adjustment, cancel) is a suspend function that returns a Result<T> and never emits reader events.
  • The SDK enforces readiness (sdk.readinessState.value.isReadyForTransactions) and blocks taps if the required tap-to-pay dependency is missing, developer mode is on, or no active location is set.

Rather than duplicating code here, the dedicated Running Payments guide shows:

  • How the demo’s TransactionFlowViewModel builds PaymentBreakdown, collects the Flow, and updates UI state
  • Mapping KoardReaderStatus + reader status codes to your own UX
  • Handling surcharge confirmation, canceling the reader, and orchestrating post-reader calls (capture/refund/reverse/incremental/tip adjust/receipt)

Use that guide as the canonical reference when wiring payments into your application.

Troubleshooting

Common Installation Issues

SDK Not Initialized Error

IllegalStateException: Instance is null. Did you forget to call initialize?

Solution: Ensure KoardMerchantSdk.initialize() is called in Application.onCreate() on a worker thread before accessing getInstance().

Thread Enforcement Error

Solution: All SDK operations must be called from a worker thread. Use Dispatchers.IO:

lifecycleScope.launch(Dispatchers.IO) {
    // SDK operations here
}

Dependency Conflicts

Solution: Ensure you're using compatible versions of AndroidX and Kotlin libraries. Check for dependency conflicts with:

./gradlew app:dependencies

Build Errors

Solution:

  • Verify you're using JDK 21
  • Ensure minimum SDK is set to 31 (Android 12)
  • Clean and rebuild: ./gradlew clean build

NFC Transactions Failing

Solution:

  • Disable developer mode before running transactions - This is required for security
  • Developer mode blocks tap to pay functionality
  • Workflow: Enable dev mode → Install app → Disable dev mode → Run transactions
  • Go to Settings > System > Developer Options and toggle OFF
  • Restart device after disabling developer mode

Verification Checklist

  • Android Studio Hedgehog or newer installed
  • JDK 21 configured
  • Minimum SDK set to 31 (Android 12)
  • SDK dependency added to build.gradle.kts
  • Application class created and registered
  • SDK.initialize() called on worker thread
  • NFC permissions added to manifest
  • Project builds without errors
  • Import statements work correctly
  • Tap-to-pay kernel dependency installed on test device
  • Physical device with NFC available for testing
  • Aware of developer mode workflow (enable → install → disable → run transactions)

Next Steps

Once the SDK is installed and configured:

See also

This wraps up the SDK installation. See the links below for next steps in your integration:

Best Practices

  • Idempotency: Generate a unique eventId (UUID) for every transaction mutation (sale, refund, adjust) and persist it with your POS records.
  • Threading: Always hop to Dispatchers.IO before calling any SDK method; return results to the main thread only after the call completes.
  • Environment Flavors: Mirror the demo’s prod/uat/dev flavors so each build points at the correct Koard environment and credential set.
  • Logging: Plant a Timber.DebugTree in development builds. The SDK logs enrollment/transaction events via KoardTimeEventLogger, which is invaluable when debugging device provisioning.
  • Device Re-provisioning: When wiping devices or reinstalling the tap-to-pay kernel app, call refreshDeviceCertificates() to regenerate keys and rerun enrollment.