> ## Documentation Index
> Fetch the complete documentation index at: https://docs-platform.services-valid.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Implementação

> Inicialize o LivenessIdentySDK e dispare uma verificação de liveness com IDENTY Face AI

Este guia mostra a API pública do `LivenessIdentySDK` e o fluxo completo de uma verificação de vivacidade.

## API pública

A fachada do SDK fica em `com.vcc.vendor.identy.sdk.LivenessIdentySDK`:

```kotlin theme={"theme":"catppuccin-latte"}
object LivenessIdentySDK {
    suspend fun init(
        applicationContext: Context,
        config: LivenessIdentySDKConfig
    ): Result<Unit>

    suspend fun getSessionData(): LivenessIdentySDKSessionData

    fun startLivenessCheck(
        activity: Activity,
        sessionToken: String,
        options: LivenessIdentySDKCaptureOptions? = null
    ): Flow<LivenessIdentySDKLivenessState>

    fun stop()

    val isInitialized: Boolean
}
```

* `init` é uma `suspend fun` que retorna `Result<Unit>`. **Não é idempotente**: chamá-la de novo sem antes chamar `stop()` falha com `LivenessIdentySDKInitError.AlreadyInitialized`.
* `getSessionData` coleta a assinatura de dispositivo (biblioteca de fingerprint) e **nunca falha** — veja [Dados de sessão](#dados-de-sessão).
* `startLivenessCheck` requer a `Activity` chamadora e o `sessionToken` criado pelo seu backend. `options` é opcional — veja [Opções de captura](#opções-de-captura).
* `stop()` libera o estado interno do SDK.
* `isInitialized` indica se `init` foi concluído com sucesso e `stop()` ainda não foi chamado.

> [!NOTE]
>
> As credenciais internas do SDK (biblioteca de fingerprint, Sentry) são embutidas e cifradas no AAR. Nenhuma chave precisa ser fornecida pelo app consumidor.

## Configuração

```kotlin theme={"theme":"catppuccin-latte"}
data class LivenessIdentySDKConfig(
    val customization: LivenessIdentySDKCustomization? = null,
)
```

| Parâmetro | Tipo | Obrigatório | Descrição |
| - | - | - | - |
| `customization` | `LivenessIdentySDKCustomization?` | Não | Personalização visual da UI do vendor Identy. Veja [Customização](https://docs-platform.services-valid.com.br/plataforma/liveness/identy/sdk/android/customizacao.md) |

### Erros de inicialização — `LivenessIdentySDKInitError`

Em caso de falha, o `Result` de `init()` traz um `LivenessIdentySDKInitError`:

| Subtipo | Causa |
| - | - |
| `AlreadyInitialized` | `init()` foi chamado com o SDK já inicializado. Chame `stop()` antes de reinicializar, ou cheque `isInitialized` |
| `ProvisioningFailed` | Falha ao preparar as credenciais internas do SDK |
| `IdentyInitializationFailed` | Reservado para falha do adapter do IDENTY Face AI na inicialização. Na versão atual não ocorre na prática — problemas de licença aparecem só em `startLivenessCheck()`, como `LivenessIdentySDKError.Unknown` |

## Dados de sessão

Depois de `init()`, colete a assinatura de dispositivo da biblioteca de fingerprint com `getSessionData()`:

```kotlin theme={"theme":"catppuccin-latte"}
data class LivenessIdentySDKSessionData(
    val ssid: String
)
```

| Campo | Tipo | Descrição |
| - | - | - |
| `ssid` | `String` | Assinatura de dispositivo (device signature) coletada pela biblioteca de fingerprint |

> [!NOTE]
>
> `getSessionData()` **nunca falha** — não retorna `Result`. A coleta de `ssid` é best-effort: se a biblioteca de fingerprint falhar internamente, ou se a função for chamada antes de `init()`, o `ssid` vem vazio (`""`). Quando isso acontecer, **omita o campo `ssid`** ao criar a sessão — a sessão é criada normalmente, apenas sem os metadados de dispositivo.

## Criação de sessão — responsabilidade do consumer app

O SDK **não cria sessões** nem se comunica diretamente com o backend de autenticação. Após `init()`, o consumer app deve:

1. Chamar `getSessionData()` para obter o `ssid`.
2. Enviar `ssid` (quando não vazio) e um `clientRequestId` (UUID gerado pelo seu app) ao seu próprio backend.
3. O seu backend chama `POST /api/v1/sessions` com a sua `x-api-key`, e o serviço devolve o `sessionToken`.
4. Passar o `sessionToken` para `startLivenessCheck()`.

> [!NOTE]
>
> Veja [Serviços](https://docs-platform.services-valid.com.br/plataforma/liveness/identy/servico.md) para o contrato do `POST /api/v1/sessions`.

## Estados do Flow

`startLivenessCheck` retorna um `Flow<LivenessIdentySDKLivenessState>`:

```kotlin theme={"theme":"catppuccin-latte"}
sealed class LivenessIdentySDKLivenessState {
    object Loading : LivenessIdentySDKLivenessState()
    data class Success(val data: LivenessIdentySDKResultData) : LivenessIdentySDKLivenessState()
    data class Error(val error: LivenessIdentySDKError) : LivenessIdentySDKLivenessState()
}
```

| Estado | Descrição |
| - | - |
| `Loading` | Captura do vendor Identy em andamento |
| `Success(data)` | Captura concluída e enviada com sucesso |
| `Error(error)` | Falha em alguma etapa do fluxo |

## Fluxo de uso

**1. Inicializar o SDK**

Chame `LivenessIdentySDK.init` uma única vez, preferencialmente no `onCreate()` da `Application`:

```kotlin theme={"theme":"catppuccin-latte"}
class MyApplication : Application() {

    private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)

    override fun onCreate() {
        super.onCreate()

        scope.launch {
            if (LivenessIdentySDK.isInitialized) return@launch

            val result = LivenessIdentySDK.init(
                applicationContext = this@MyApplication,
                config = LivenessIdentySDKConfig() // customization é opcional
            )

            result.onFailure { error ->
                when (error) {
                    is LivenessIdentySDKInitError.AlreadyInitialized -> Unit
                    is LivenessIdentySDKInitError.ProvisioningFailed ->
                        Log.e("SDK", "Falha ao preparar o SDK: ${error.message}")
                    is LivenessIdentySDKInitError.IdentyInitializationFailed ->
                        Log.e("SDK", "Falha no IDENTY Face AI: ${error.message}")
                    else -> Log.e("SDK", "Falha inesperada na inicialização", error)
                }
            }
        }
    }
}
```

**2. Coletar dados de sessão e criar sessão no backend**

```kotlin theme={"theme":"catppuccin-latte"}
scope.launch {
    val sessionData = LivenessIdentySDK.getSessionData()

    val session = myBackend.createSession(
        clientRequestId = UUID.randomUUID().toString(),
        ssid = sessionData.ssid.ifEmpty { null }, // omita o campo se vier vazio
        platform = "APP"
    )
    // session.sessionToken
}
```

**3. Iniciar a verificação**

O SDK solicita a permissão de câmera em runtime antes de abrir a captura. Se o usuário recusar, o fluxo termina com `CameraPermissionDenied` ou `CameraPermissionPermanentlyDenied`.

```kotlin theme={"theme":"catppuccin-latte"}
class VerificationActivity : AppCompatActivity() {

    private fun startVerification(sessionToken: String) {
        lifecycleScope.launch {
            LivenessIdentySDK.startLivenessCheck(
                activity = this@VerificationActivity,
                sessionToken = sessionToken
            )
                .catch { e ->
                    showError("Erro inesperado: ${e.message}")
                }
                .collect { state ->
                    when (state) {
                        is LivenessIdentySDKLivenessState.Loading ->
                            showLoading()

                        is LivenessIdentySDKLivenessState.Success ->
                            onSuccess(state.data)

                        is LivenessIdentySDKLivenessState.Error ->
                            onError(state.error)
                    }
                }
        }
    }
}
```

**4. Tratar o resultado**

No caso de sucesso, verifique sempre `status == CaptureStatus.PASSED` para confirmar aprovação biométrica. No caso de erro, mapeie cada subtipo de `LivenessIdentySDKError` para uma mensagem ou ação adequada — veja [Solução de problemas](https://docs-platform.services-valid.com.br/plataforma/liveness/identy/sdk/android/troubleshooting.md).

## Opções de captura

`startLivenessCheck()` aceita o parâmetro opcional `options` para ajustar, por captura, o nível de segurança do anti-spoofing, o nível de detecção de deepfake e os formatos de template retornados:

```kotlin theme={"theme":"catppuccin-latte"}
LivenessIdentySDK.startLivenessCheck(
    activity = this@VerificationActivity,
    sessionToken = sessionToken,
    options = LivenessIdentySDKCaptureOptions(
        securityLevel = LivenessIdentySDKSecurityLevel.HIGH,
        deepfakeLevel = LivenessIdentySDKDeepfakeLevel.HIGHEST,
        requiredTemplates = listOf(LivenessIdentySDKFaceTemplate.PNG)
    )
)
```

| Campo | Tipo | Valores | Padrão (`null`) |
| - | - | - | - |
| `securityLevel` | `LivenessIdentySDKSecurityLevel?` | `NONE`, `LOW`, `MEDIUM`, `MODERATE`, `BALANCED_HIGH`, `BALANCED_VERY_HIGH`, `HIGH`, `VERY_HIGH`, `HIGHEST` | `VERY_HIGH` |
| `deepfakeLevel` | `LivenessIdentySDKDeepfakeLevel?` | Mesmos 9 valores de `securityLevel` | `HIGHEST` |
| `requiredTemplates` | `List<LivenessIdentySDKFaceTemplate>?` | `PNG`, `ISO_19794_5`, `ISO_39794_5`, `JPEG`, `BITMAP`, `JP2K`, `NIST_ITL_1_2015`, `JPEG_CUSTOM_COMPRESSED`, `IDENTY_TYPE_1` | Só `JPEG` |

> [!NOTE]
>
> `requiredTemplates` sempre inclui `JPEG` — mesmo que você não o liste, o SDK o coloca em primeiro lugar e remove duplicatas. Os formatos adicionais aparecem em `LivenessIdentySDKResultData.templates`, quando o backend os retorna. As opções valem só para a chamada em que foram passadas: uma captura sem `options` volta aos padrões.

## Campos de `LivenessIdentySDKResultData`

| Campo | Tipo | Descrição |
| - | - | - |
| `sessionId` | `String` | Identificador da sessão, ecoado pelo backend na resposta da captura (`startLivenessCheck()` não recebe `sessionId` como parâmetro, só `sessionToken`) |
| `id` | `String` | Identificador único da captura enviada |
| `status` | `CaptureStatus` | `PASSED` ou `FAILED` |
| `failureReason` | `CaptureFailureReason?` | Motivo da falha quando `status == FAILED`: `SPOOF`, `INSECURE`, `DEEPFAKE`, `QUALITY`, `EXPIRED` ou `VENDOR_ERROR`; `null` quando `status == PASSED` |
| `image` | `String?` | Base64 JPEG da captura processada, quando o backend retorna |
| `templates` | `Map<String, String>?` | Formatos adicionais pedidos em `requiredTemplates` (ex.: PNG, ISO\_19794\_5), base64, quando o backend os retorna — o conjunto exato de chaves varia por integração |
| `createdAt` | `String` | Timestamp ISO 8601 de criação do registro no backend |

> [!WARNING]
>
> `Success` não implica aprovação biométrica. Sempre verifique `status == CaptureStatus.PASSED` para confirmar que a prova de vida passou.

## Exemplo de tratamento de erro

```kotlin theme={"theme":"catppuccin-latte"}
private fun onError(error: LivenessIdentySDKError) {
    when (error) {
        is LivenessIdentySDKError.Cancelled                          -> showMessage("Captura cancelada pelo usuário")
        is LivenessIdentySDKError.CaptureError                       -> showError("Falha na captura: ${error.message}")
        is LivenessIdentySDKError.SubmitError                        -> showError("Falha ao enviar: ${error.message}")
        is LivenessIdentySDKError.NetworkError                       -> showError("Sem conexão: ${error.message}")
        is LivenessIdentySDKError.CameraPermissionDenied             -> showMessage("A câmera é necessária — tente de novo")
        is LivenessIdentySDKError.CameraPermissionPermanentlyDenied  -> openAppSettings()
        is LivenessIdentySDKError.Unknown                            -> showError("Erro desconhecido: ${error.message}")
    }
}
```

A hierarquia completa de erros, com causa e ação recomendada para cada subtipo, está em [Solução de problemas](https://docs-platform.services-valid.com.br/plataforma/liveness/identy/sdk/android/troubleshooting.md).

## Parando o SDK

`LivenessIdentySDK.stop()` libera todos os recursos internos do SDK e reseta seu estado, deixando-o exatamente como estava antes do primeiro `init()`.

```kotlin theme={"theme":"catppuccin-latte"}
LivenessIdentySDK.stop()
```

| Situação | Ação |
| - | - |
| Teardown de tela ou sessão (ex.: `onDestroy()` da Activity) | Chamar `stop()` para descartar o estado interno e as credenciais em memória |
| Entre capturas (fluxo multi-etapa) | Opcional — não é necessário chamar `stop()`/`init()` entre capturas. Lembre que `init()` não é idempotente: chamá-lo de novo sem `stop()` falha com `AlreadyInitialized` |
| Antes de encerrar o processo | `stop()` garante limpeza ordeira das credenciais em memória |

## Próximos passos

> **[Customização](https://docs-platform.services-valid.com.br/plataforma/liveness/identy/sdk/android/customizacao.md)**
>
> Personalize a UI de captura do IDENTY Face AI

> **[Solução de problemas](https://docs-platform.services-valid.com.br/plataforma/liveness/identy/sdk/android/troubleshooting.md)**
>
> Hierarquia de erros e dicas de diagnóstico


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.