Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.smartcomply.com/llms.txt

Use this file to discover all available pages before exploring further.

Adhere Android SDK

The Adhere Android SDK is a Kotlin Multiplatform library that delivers a drop-in identity verification and liveness detection flow for Android apps. It provides a fully self-contained Jetpack Compose screen that orchestrates ID collection, onboarding verification, and camera-based liveness challenges — no UI code required on your side.

Features

  • Drop-in Compose UISmartcomplyFlowScreen handles the entire verification flow
  • Automatic session management — creates and manages sessions internally
  • Dynamic ID types — fetches available document types from your Dashboard configuration
  • Identity onboarding — BVN, NIN, Passport, National IDs, and more
  • Camera liveness detection — MediaPipe-powered face challenge system (blink, turn head, open mouth)
  • Face-to-ID matching — optionally compares the liveness selfie against the submitted document
  • One-time verification policy — sessions are single-use and expire after 30 minutes

Installation

Step 1 — Add Maven Central (usually already present)

In your project-level settings.gradle.kts:
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
    }
}

Step 2 — Add the dependency

In your app-level build.gradle.kts:
dependencies {
    implementation("io.github.386konsult:sdk:1.0.0")
}

Step 3 — Enable Compose in your module

android {
    buildFeatures {
        compose = true
    }
    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.14"
    }
}

Platform Setup

Permissions

In AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

Minimum SDK

android {
    defaultConfig {
        minSdk = 24
    }
}

Quick Start (Drop-in UI)

The simplest integration is SmartComplyFlowScreen — a self-contained Compose screen that handles everything automatically.
import com.smartcomply.sdk.SmartComply
import com.smartcomply.sdk.client.Environment
import com.smartcomply.sdk.client.SDKConfig
import com.smartcomply.sdk.ui.SmartComplyFlowScreen
import com.smartcomply.sdk.ui.FlowResult

// 1. Create the SDK instance
val sdk = SmartComply(
    SDKConfig(
        apiKey   = "your_live_api_key",
        clientId = "unique-client-id-per-user",       // one-time use UUID per verification
        environment = Environment.PRODUCTION           // use Environment.SANDBOX for testing
    )
)

// 2. Mount the flow screen in your Compose hierarchy
@Composable
fun VerificationScreen() {
    SmartComplyFlowScreen(
        sdk = sdk,
        onComplete = { result: FlowResult ->
            // Verification submitted successfully
            println("Entry ID: ${result.entryId}")
            println("Status: ${result.status}")
            println("Submitted at: ${result.submittedAt}")
        },
        onError = { message: String ->
            println("Verification failed: $message")
        }
    )
}
The SDK handles the entire flow automatically:
  1. Creates a secure session with your API key
  2. Fetches available ID types from your Dashboard configuration
  3. Displays a welcome screen with your brand name
  4. Guides the user through country selection (if multi-country is configured)
  5. Collects the required ID fields or captures a document photo
  6. Verifies the identity against the national database
  7. Opens the camera and runs liveness face challenges
  8. Uploads the video and submits the result
  9. Returns a FlowResult to your onComplete callback

SDK Configuration

data class SDKConfig(
    val apiKey: String,                         // Required — your Adhere API key
    val clientId: String,                       // Required — unique ID per user verification
    val environment: Environment = SANDBOX,     // SANDBOX | EMULATOR | PRODUCTION
    val requestTimeoutMs: Long = 30_000L,       // Default 30s for API calls
    val uploadTimeoutMs: Long = 60_000L,        // Default 60s for video upload
    val maxUploadRetries: Int = 3               // Retry attempts for failed uploads
)
EnvironmentBase URL
SANDBOXhttp://192.168.1.5:8000 (local dev server)
EMULATORhttp://10.0.2.2:8000 (Android emulator → host machine)
PRODUCTIONhttps://adhere-api.smartcomply.com

FlowResult

The onComplete callback receives a FlowResult:
data class FlowResult(
    val entryId: Int,                                   // Liveness entry ID from backend
    val status: String,                                 // "submitted", "verified", "failed"
    val submittedAt: String?,                           // ISO 8601 timestamp
    val verificationResult: VerifyIdentityResponse?     // Identity check result (name, DOB, etc.)
)

Identity result fields

data class VerifyIdentityResponse(
    val status: String,             // "verified" | "pending"
    val onboardingType: String?,    // e.g. "bvn", "nin"
    val identityCheckId: Int?,      // used internally for face-to-ID matching
    val providerResult: ProviderResult?
)

data class ProviderResult(
    val firstName: String?,
    val lastName: String?,
    val middleName: String?,
    val dob: String?,
    val gender: String?,
    val phone: String?
)

Advanced Usage (Headless)

If you are building your own UI, call the SDK methods directly:
val sdk = SmartComply(SDKConfig(apiKey = "...", clientId = "..."))

// 1. Create a session
val session = sdk.createSession()

// 2. Fetch available ID channels
val config = sdk.initialize()
val channels = config.channels["nigeria"] ?: emptyList()
val bvnChannel = channels.first { it.name == "BVN" }

// 3. Verify identity
val identity = sdk.onboarding.verify(
    channelId = bvnChannel.id,
    fields = mapOf("bvn" to "12345678912")
)

// 4. Start liveness check
val params = LivenessStartParams(
    identifier     = "12345678912",
    identifierType = "bvn",
    country        = "NG",
    identityCheckId = identity.identityCheckId   // enables face-to-ID match
)

// Mount LivenessScreen in your Compose tree
LivenessScreen(
    livenessModule = sdk.liveness,
    params = params,
    onResult = { state ->
        when (state) {
            is LivenessState.Success -> println("Done: ${state.response.id}")
            is LivenessState.Failed  -> println("Error: ${state.error.message}")
            else -> { /* update progress UI */ }
        }
    }
)

Liveness States

Observe LivenessState to update a custom progress UI:
StateDescription
InitializingCameraCamera and MediaPipe are starting up
CameraReadyCamera open, session being created
DetectingFace(instruction)No face detected; shows positioning guidance
WaitingForAction(action, instruction, confidence, completedCount, totalCount)Active challenge in progress
CapturingSnapshotAll actions complete, grabbing final frame
UploadingVideo being uploaded to backend
VerifyingBackend processing the submission
Success(response)Liveness passed — contains LivenessSubmitResponse
Failed(error, canRetry)Liveness failed — show error and optionally retry

Supported Liveness Actions

ActionEnumDescription
BlinkChallengeAction.BLINKClose and open both eyes
Turn leftChallengeAction.TURN_LEFTRotate head to the left
Turn rightChallengeAction.TURN_RIGHTRotate head to the right
Turn headChallengeAction.TURN_HEADAny horizontal head rotation
Open mouthChallengeAction.OPEN_MOUTHOpen jaw wide
Challenge actions are configured in your Adhere Dashboard. The SDK fetches them automatically.

Error Handling

SmartComplyFlowScreen(
    sdk = sdk,
    onComplete = { result -> /* ... */ },
    onError = { message ->
        when {
            message.contains("401") -> // Invalid or expired API key
            message.contains("session") -> // Session expired — create a new clientId
            else -> // Show message to user
        }
    }
)
Common error scenarios:
ErrorCauseResolution
401 UnauthorizedInvalid API keyVerify your key in the Adhere Dashboard
Session expired30-minute session timeoutGenerate a new clientId per attempt
Failed to create liveness entryNetwork error or invalid payloadRetry with a new session
No face detectedPoor lighting or camera anglePrompt user to adjust position

ProGuard / R8

Add to your proguard-rules.pro:
-keep class com.smartcomply.sdk.** { *; }
-keepattributes *Annotation*
-dontwarn com.google.mediapipe.**