> ## 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 no iOS

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

## API pública

A fachada do SDK fica em `LivenessIdentySDKClient.shared`:

```swift theme={"theme":"catppuccin-latte"}
@MainActor
public final class LivenessIdentySDKClient {
    public static let shared: LivenessIdentySDKClient

    public var isInitialized: Bool

    public func initialize(config: LivenessIdentySDKConfig) async throws

    public func getSessionData() async -> LivenessIdentySDKSessionData

    public func startLivenessCheck(
        viewController: UIViewController,
        sessionToken: String,
        options: LivenessIdentySDKCaptureOptions? = nil
    ) -> AsyncStream<LivenessIdentySDKLivenessState>

    public func stop()
}
```

* `initialize` é **assíncrona** e **lança** (`throws`) `LivenessIdentySDKInitError` em caso de falha. Chame uma única vez, preferencialmente no `AppDelegate`.
* `getSessionData` coleta a assinatura de dispositivo (biblioteca de fingerprint) de forma **best-effort** e **nunca falha** — nem quando chamada antes de `initialize`.
* `startLivenessCheck` requer uma `UIViewController` 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. Não chamar enquanto uma captura estiver em progresso.
* `isInitialized` indica se `initialize` foi concluído com sucesso.

> [!NOTE]
>
> A classe inteira é isolada ao `@MainActor` — todos os membros (`initialize`, `getSessionData`, `startLivenessCheck`, `stop`, `isInitialized`) devem ser acessados a partir do main actor. Nenhuma chave de API precisa ser fornecida pelo app consumidor: as credenciais do vendor, da biblioteca de fingerprint e do Sentry já estão embutidas e criptografadas dentro do XCFramework.

## Configuração

```swift theme={"theme":"catppuccin-latte"}
public struct LivenessIdentySDKConfig {
    public let customization: LivenessIdentySDKCustomization?

    public init(customization: LivenessIdentySDKCustomization? = nil)
}
```

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

## Dados de sessão (`ssid`)

`getSessionData()` coleta a assinatura de dispositivo via biblioteca de fingerprint **100% internamente** — não há protocolo para implementar nem parâmetro a fornecer — e retorna `LivenessIdentySDKSessionData` diretamente (não é `Result` nem `throws`). Sem a dependência opcional `shield-ptr-spm` (veja [Instalação](https://docs-platform.services-valid.com.br/plataforma/liveness/identy/sdk/ios/instalacao.md#dependência-opcional-ssid-real-via-biblioteca-de-fingerprint)), se a coleta falhar, ou se a função for chamada antes de `initialize`, `ssid` vem vazio — **isso não é um erro**. Nesse caso, **omita o campo `ssid`** ao criar a sessão.

```swift theme={"theme":"catppuccin-latte"}
let sessionData = await LivenessIdentySDKClient.shared.getSessionData()
let ssid: String? = sessionData.ssid.isEmpty ? nil : sessionData.ssid // omita se vazio
```

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

O SDK não cria a sessão sozinho. Depois de obter `ssid`, seu app pede ao **seu backend** para criar a sessão; o seu backend chama `POST /api/v1/sessions` na Plataforma ID com a sua `x-api-key`:

| Campo | Tipo | Obrigatório | Descrição |
| - | - | - | - |
| `clientRequestId` | `String` (UUID) | Sim | Identificador único da requisição, gerado pelo cliente |
| `ssid` | `String?` | Não | Assinatura de dispositivo coletada pela biblioteca de fingerprint — omita se vier vazio |
| `platform` | `String?` | Não | `"WEB"` ou `"APP"` |

A resposta fornece o `sessionToken` usado em `startLivenessCheck`. Veja [Serviços](https://docs-platform.services-valid.com.br/plataforma/liveness/identy/servico.md) para a referência completa do endpoint.

## Estados do `AsyncStream`

`startLivenessCheck` retorna um `AsyncStream<LivenessIdentySDKLivenessState>` que emite um único caminho `loading → success` ou `loading → error` antes de completar:

```swift theme={"theme":"catppuccin-latte"}
public enum LivenessIdentySDKLivenessState {
    case loading
    case success(LivenessIdentySDKResultData)
    case error(LivenessIdentySDKError)
}
```

> [!NOTE]
>
> O XCFramework é compilado com *library evolution* e os enums públicos do SDK não são `@frozen`. Por isso os exemplos usam `@unknown default:` nos `switch` — sem ele, o compilador emite avisos de exaustividade.

## Fluxo de uso

**1. Inicializar o SDK**

Chame `LivenessIdentySDKClient.shared.initialize` uma única vez no início do ciclo de vida do app:

```swift theme={"theme":"catppuccin-latte"}
import LivenessIdentySDK

func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions ...) -> Bool {
    Task {
        do {
            let config = LivenessIdentySDKConfig()
            try await LivenessIdentySDKClient.shared.initialize(config: config)
        } catch let error as LivenessIdentySDKInitError {
            switch error {
            case .alreadyInitialized:
                break
            case .provisioningFailed(let msg):
                print("SDK provisioning failed: \(msg)")
            case .identyInitializationFailed(let msg):
                print("Identy adapter init failed: \(msg)")
            @unknown default:
                print("SDK init failed: \(error.localizedDescription)")
            }
        } catch {
            print("SDK init unexpected error: \(error)")
        }
    }
    return true
}
```

**2. Obter ssid e criar a sessão no backend**

Chame `getSessionData()` para obter o `ssid` e envie-o ao seu backend (omitindo-o se vier vazio) para criar a sessão (seção anterior), obtendo o `sessionToken`.

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

Passe o `sessionToken` obtido no passo anterior:

```swift theme={"theme":"catppuccin-latte"}
import LivenessIdentySDK

final class VerificacaoViewController: UIViewController {

    func iniciarLiveness(sessionToken: String) {
        Task {
            let stream = LivenessIdentySDKClient.shared.startLivenessCheck(
                viewController: self,
                sessionToken: sessionToken
            )

            for await state in stream {
                switch state {
                case .loading:
                    break
                case .success(let result):
                    print("status: \(result.status), failureReason: \(String(describing: result.failureReason))")
                case .error(let error):
                    print("Erro: \(error.localizedDescription)")
                @unknown default:
                    break
                }
            }
        }
    }
}
```

A UI de captura é apresentada pelo próprio IDENTY Face AI SDK sobre o `viewController` passado.

**4. Tratar o resultado**

Em `.success`, verifique `status` (`.passed`/`.failed`) — **sucesso no stream não significa aprovação biométrica**. Em `.error`, mapeie cada caso de `LivenessIdentySDKError` — veja [Solução de problemas](https://docs-platform.services-valid.com.br/plataforma/liveness/identy/sdk/ios/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:

```swift theme={"theme":"catppuccin-latte"}
let stream = LivenessIdentySDKClient.shared.startLivenessCheck(
    viewController: self,
    sessionToken: sessionToken,
    options: LivenessIdentySDKCaptureOptions(
        secLevel: .high,
        deepfakeLevel: .highest,
        requiredTemplates: [.png]
    )
)
```

| Campo | Tipo | Valores | Padrão (`nil`) |
| - | - | - | - |
| `secLevel` | `LivenessIdentySDKSecLevel?` | `.none`, `.low`, `.medium`, `.moderate`, `.balancedHigh`, `.high`, `.balancedVeryHigh`, `.veryHigh`, `.highest` | `.veryHigh` |
| `deepfakeLevel` | `LivenessIdentySDKDeepfakeLevel?` | Mesmos 9 valores de `secLevel` | `.highest` |
| `requiredTemplates` | `[LivenessIdentySDKTemplateFormat]?` | `.png`, `.jpeg2k`, `.nistItl1_2015`, `.jpeg`, `.iso19794_5`, `.iso39794_5Der`, `.identyType1`, `.jpegCustomCompressed` | `[.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.

## Parar e reinicializar o SDK

```swift theme={"theme":"catppuccin-latte"}
let config = LivenessIdentySDKConfig()
print(LivenessIdentySDKClient.shared.isInitialized) // true após initialize com sucesso
LivenessIdentySDKClient.shared.stop()
print(LivenessIdentySDKClient.shared.isInitialized) // false
try await LivenessIdentySDKClient.shared.initialize(config: config)
```

> [!WARNING]
>
> Não chame `stop()` enquanto uma captura estiver em progresso. Aguarde o stream de `startLivenessCheck` encerrar (`.success` ou `.error`) antes de chamar.

## Campos de `LivenessIdentySDKSessionData`

| Campo | Tipo | Descrição |
| - | - | - |
| `ssid` | `String` | Assinatura de dispositivo coletada automaticamente via biblioteca de fingerprint (vazia se `shield-ptr-spm` não foi adicionado ao app, se a coleta falhar ou se `initialize` ainda não foi chamado — best-effort, nunca bloqueante) |

## Campos de `LivenessIdentySDKResultData`

| Campo | Tipo | Descrição |
| - | - | - |
| `sessionId` | `String` | ID da sessão, ecoado pelo backend na resposta da captura |
| `id` | `String` | ID da captura registrada |
| `status` | `CaptureStatus` | `.passed` ou `.failed` |
| `failureReason` | `CaptureFailureReason?` | `.spoof`, `.insecure`, `.deepfake`, `.quality`, `.expired` ou `.vendorError`; `nil` quando `status == .passed` |
| `image` | `String?` | Base64 JPEG da captura processada, quando o backend retorna |
| `templates` | `[String: String]?` | Formatos adicionais pedidos em `requiredTemplates`, base64, quando o backend os retorna — retornados apenas, nunca persistidos |
| `createdAt` | `String` | Timestamp ISO 8601 de criação do registro no backend |

> [!NOTE]
>
> `status == .passed` **não** é opcional de checar — é a única forma de saber se a verificação biométrica foi aprovada. O stream chegar a `.success` apenas significa que o fluxo técnico terminou sem erro.

## Erros possíveis

### `LivenessIdentySDKInitError`

Lançados por `initialize(config:)`:

| Caso | Causa |
| - | - |
| `identyInitializationFailed(String)` | O adapter do Identy SDK rejeitou a inicialização (ex.: licença `.lic` ausente, duplicada ou inválida para o bundle ID atual) |
| `alreadyInitialized` | `initialize()` foi chamado enquanto o SDK já estava inicializado; chame `stop()` primeiro |
| `provisioningFailed(String)` | Falha na decifração das chaves internas — blob corrompido ou chaves inválidas no build |

### `LivenessIdentySDKError`

Emitido como `.error(LivenessIdentySDKError)` pelo `AsyncStream`:

| Caso | Causa |
| - | - |
| `captureError(String)` | Erro durante a captura reportado pelo IDENTY Face AI SDK. Na versão atual, **também** é como chegam o fechamento da tela de captura pelo usuário e a permissão de câmera negada |
| `submitError(String)` | Falha ao enviar os dados de captura para o backend, incluindo respostas HTTP 4xx/5xx |
| `networkError(String)` | Erro de rede no envio (timeout, sem conectividade, autenticação rejeitada) |
| `cancelled` | Reservado para cancelamento pelo usuário — **não é emitido na versão atual** |
| `unknown(String)` | `startLivenessCheck` chamado antes de `initialize`, resposta inesperada do backend, ou erro inesperado |

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

## Próximos passos

> **[Customização](https://docs-platform.services-valid.com.br/plataforma/liveness/identy/sdk/ios/customizacao.md)**
>
> Personalize o estilo da tela de captura

> **[Solução de problemas](https://docs-platform.services-valid.com.br/plataforma/liveness/identy/sdk/ios/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.