KYCIS SDK Docs
Examples

Example - With Navigation Tracking

Complete multi-step KYC flow example

Scenario

Multi-step KYC flow with navigation tracking:

  1. Phone entry
  2. OTP verification
  3. PAN entry
  4. Document upload

Architecture

App (Jetpack Navigation)

NavGraph with KYC steps

Each screen emits context

SDK tracks progress

Backend evaluates triggers

Assistant offers help when needed

Implementation

1. Application Setup

class KycApplication : Application() {
  override fun onCreate() {
    super.onCreate()
    
    // Register schemas before init
    AI.registerScreenSchemas(listOf(
      ScreenSchema(
        screenId = "phone_entry",
        title = "Enter Phone Number",
        components = listOf(
          ComponentSpec(
            id = "phone_field",
            type = "text_input",
            label = "Phone Number",
            validationRules = listOf(
              ValidationRule(
                ruleId = "phone_format",
                pattern = "^[6-9]\\d{9}$",
                errorMessage = "Invalid phone number"
              )
            )
          )
        )
      ),
      ScreenSchema(
        screenId = "otp_verify",
        title = "Verify OTP",
        components = listOf(
          ComponentSpec(
            id = "otp_field",
            type = "text_input",
            label = "6-digit OTP",
            validationRules = listOf(
              ValidationRule(
                ruleId = "otp_format",
                pattern = "^\\d{6}$",
                errorMessage = "Invalid OTP"
              )
            )
          )
        )
      ),
      ScreenSchema(
        screenId = "pan_entry",
        title = "Enter PAN Details",
        components = listOf(
          ComponentSpec(
            id = "pan_field",
            type = "text_input",
            label = "PAN Number",
            validationRules = listOf(
              ValidationRule(
                ruleId = "pan_format",
                pattern = "^[A-Z]{5}[0-9]{4}[A-Z]$",
                errorMessage = "Invalid PAN format"
              )
            )
          )
        )
      )
    ))
    
    // Initialize SDK
    AI.init(
      application = this,
      apiKey = "your-api-key",
      userId = "runtime-user-id",
      policy = RuntimePolicy(
        backendBaseUrl = "https://kycis.zynnex.in/v1",
        clientId = "kyc-app-v1",
        mappingVersion = "v1",
        triggerStartMode = TriggerStartMode.CONFIRM_UI,
        passiveEvalEnabled = true,
        passiveEvalIntervalSeconds = 10
      )
    )
    
    AI.attach(this)
  }
}

2. Navigation Graph

@Composable
fun KycNavGraph() {
  val navController = rememberNavController()
  
  NavHost(navController, startDestination = "phone_entry") {
    composable("phone_entry") {
      LaunchedEffect(Unit) { AI.setKycStep("phone_entry") }
      PhoneEntryScreen(
        onPhoneSubmitted = { navController.navigate("otp_verify") }
      )
    }
    composable("otp_verify") {
      LaunchedEffect(Unit) { AI.setKycStep("otp_verify") }
      OtpVerifyScreen(
        onOtpVerified = { navController.navigate("pan_entry") }
      )
    }
    composable("pan_entry") {
      LaunchedEffect(Unit) { AI.setKycStep("pan_entry") }
      PanEntryScreen(
        onPanSubmitted = { navController.navigate("document_upload") }
      )
    }
    composable("document_upload") {
      LaunchedEffect(Unit) { AI.setKycStep("document_upload") }
      DocumentUploadScreen()
    }
  }
}

3. Screen Implementation

@Composable
fun PhoneEntryScreen(
  onPhoneSubmitted: (String) -> Unit
) {
  var phone by remember { mutableStateOf("") }
  var error by remember { mutableStateOf<String?>(null) }
  
  Column {
    Text("Enter your phone number")
    
    TextField(
      value = phone,
      onValueChange = { 
        phone = it
        error = null
        // Report redacted input
        AI.reportComponentInput(
          componentId = "phone_field",
          hint = maskPhone(it),
          masked = true
        )
      }
    )
    
    error?.let { Text(it, color = Color.Red) }
    
    Button(onClick = {
      if (isValidPhone(phone)) {
        onPhoneSubmitted(phone)
      } else {
        error = "Invalid phone number"
        AI.trackValidationFailure(
          failureReasonCode = "phone_invalid",
          componentId = "phone_field",
          hint = maskPhone(phone),
          masked = true
        )
      }
    }) {
      Text("Continue")
    }
  }
}

fun maskPhone(phone: String): String {
  return if (phone.length >= 4) {
    "${phone.take(2)}****${phone.takeLast(2)}"
  } else phone
}

4. Voice Integration

class MainActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    
    AI.setVoiceSessionListener { result ->
      if (result.isValid) {
        // Show voice UI
        startVoiceCall(result)
      }
    }
    
    setContent {
      Column {
        // Help FAB
        FloatingActionButton(
          onClick = { AI.startAssistant() }
        ) {
          Icon(Icons.Default.Call, "Get help")
        }
        
        // Your nav graph
        KycNavGraph()
      }
    }
  }
  
  private fun startVoiceCall(result: VoiceSessionResult) {
    // Connect to LiveKit with credentials
    // Show call UI
  }
}

Event Sequence

Activity stream shows:

  1. identity — user set
  2. screen_schema — schemas registered
  3. screen_schema_lazyscreen_schema — phone entry
  4. component_input — phone typing
  5. validation_failed — if invalid
  6. trigger — if user struggling
  7. screen_schema — otp verify
  8. session_start — if voice started
  9. voice_conversation_turn — conversation
  10. session_stop + reengagement

Key Points

  • Schemas registered before init
  • setKycStep called on every navigation
  • component_input reports redacted values
  • Validation failures tracked immediately
  • Voice available via FAB and triggers

On this page