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

> Como implementar a verificação de liveness na sua aplicação web

## APIs Disponíveis

O SDK oferece duas formas de utilização: **API Simples** (recomendada) e **API Avançada**.

## API Simples (Recomendada)

Use o método `run()` para executar todo o fluxo de verificação com uma única chamada. O método gerencia automaticamente a inicialização, captura e limpeza de recursos.

```javascript theme={"theme":"catppuccin-latte"}
// Criar instância do Hub
const hub = ValidHub.createHub();

// Configuração do SDK
const config = {
  apiKey: 'sua-api-key',
  cek: 'sua-cek-base64',
  mount: '#camera-container',
  env: 'production',
  appName: 'minha-aplicacao',
  risk: 'LIVENESS_RISK_HIGH',

  // Callbacks
  onSuccess: (result) => {
    console.log('Verificação bem sucedida:', result);
  },
  onFailure: (error) => {
    console.error('Verificação falhou:', error);
  },
  onProgress: (state) => {
    console.log('Progresso:', state);
  },
};

// Executar verificação
try {
  const result = await hub.run(config);
  console.log('Resultado:', result);
} catch (error) {
  console.error('Erro:', error);
}
```

<Info>
  O método `run()` gerencia o ciclo de vida completo, incluindo o teardown automático
  ao final. Você **não precisa** chamar `teardown()` ao usar a API Simples.
</Info>

## API Avançada (Controle Granular)

Para cenários que requerem maior controle sobre o fluxo:

```javascript theme={"theme":"catppuccin-latte"}
const hub = ValidHub.createHub();

try {
  // Passo 1: Inicializar o SDK
  await hub.init(config);

  // Passo 2: Executar a verificação quando necessário
  const result = await hub.startLivenessCheck();

  // Processar resultado
  console.log('Resultado:', result);
} finally {
  // Passo 3: Limpar recursos (obrigatório na API Avançada)
  await hub.teardown();
}
```

<Warning>
  Na API Avançada, é **obrigatório** chamar `teardown()` para liberar recursos
  (câmera, memória, listeners). Use um bloco `finally` para garantir a limpeza
  mesmo em caso de erro.
</Warning>

## Estrutura de Configuração

```typescript theme={"theme":"catppuccin-latte"}
interface HubConfig {
  // Obrigatórios
  apiKey: string;                              // Chave de API
  cek: string | ArrayBufferView | CEKData;     // CEK (ver formatos aceitos na página de Instalação)
  mount: HTMLElement | string;                 // Elemento ou seletor CSS do container

  // Opcionais
  appName?: string;                            // Nome da aplicação
  risk?: string;                               // Nível de risco (ver tabela abaixo)
  debug?: boolean;                             // Modo debug (logs detalhados no console)
  env?: 'production' | 'development' | 'homolog'; // Ambiente de execução e URL do backend
  hubOptions?: HubOptions;                     // Opções de personalização (idioma, tema, UI)

  // Callbacks
  onSuccess?: (result: LivenessResult) => void;
  onFailure?: (error: LivenessFailureError) => void;
  onProgress?: (state: HubState) => void;
}
```

### Parâmetros Detalhados

| Parâmetro | Tipo                                         | Descrição                                                                                                                                                          |
| --------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `cek`     | `string \| ArrayBufferView \| CEKData`       | Aceita string Base64, JSON string, ou objeto `CEKData` diretamente. Veja os [formatos aceitos](/plataforma/liveness/hub/sdk/web/installation#configuração-do-cek). |
| `env`     | `'production' \| 'development' \| 'homolog'` | Define o ambiente de execução e a URL do backend automaticamente. Padrão: `'production'`.                                                                          |

## Níveis de Risco

O nível de risco determina qual motor biométrico o backend seleciona automaticamente:

| Valor                  | Motor Padrão | Descrição                                       |
| ---------------------- | ------------ | ----------------------------------------------- |
| `LIVENESS_RISK_HIGH`   | FaceTec      | Verificação mais rigorosa com liveness 3D ativo |
| `LIVENESS_RISK_MEDIUM` | FaceSDK      | Verificação moderada com detecção de vivacidade |
| `LIVENESS_RISK_LOW`    | FaceSDK      | Verificação básica                              |

<Info>
  A seleção do motor biométrico é feita automaticamente pelo backend com base no nível
  de risco. Não é possível sobrescrever essa seleção no client-side.
</Info>

## Sessões

Cada chamada ao SDK cria uma sessão no backend com os seguintes parâmetros padrão:

| Parâmetro | Valor Padrão         | Faixa Permitida | Descrição                      |
| --------- | -------------------- | --------------- | ------------------------------ |
| **TTL**   | 300 segundos (5 min) | 60 – 600 s      | Tempo máximo de vida da sessão |

<Info>
  Cada sessão permite uma única tentativa de captura. Se a sessão expirar ou a
  captura falhar, o SDK retornará um erro do tipo `SESSION_FAILED` e uma nova
  chamada deve ser realizada para criar uma sessão nova.
</Info>

## Estados do SDK

O SDK passa por diferentes estados durante o processo de verificação:

```typescript theme={"theme":"catppuccin-latte"}
enum HubState {
  Uninitialized = 'uninitialized', // SDK não inicializado
  Initializing = 'initializing',   // Em processo de inicialização
  Ready = 'ready',                 // Pronto para verificação
  Capturing = 'capturing',         // Capturando biometria
  Closing = 'closing',             // Encerrando sessão
  Error = 'error',                 // Estado de erro
}
```

### Monitorando Estados

```javascript theme={"theme":"catppuccin-latte"}
const config = {
  // ... outras configurações

  onProgress: (state) => {
    switch (state) {
      case 'uninitialized':
        console.log('SDK ainda não foi inicializado');
        break;
      case 'initializing':
        mostrarLoader('Preparando sistema...');
        break;
      case 'ready':
        esconderLoader();
        console.log('Pronto para iniciar verificação');
        break;
      case 'capturing':
        console.log('Captura em andamento...');
        break;
      case 'closing':
        mostrarLoader('Finalizando...');
        break;
      case 'error':
        esconderLoader();
        console.error('Ocorreu um erro');
        break;
    }
  },
};
```

## Modelo de Resposta

### Resposta de Sucesso (LivenessResult)

Quando a verificação é concluída com sucesso:

```typescript theme={"theme":"catppuccin-latte"}
interface LivenessResult {
  sessionId: string;      // ID único da sessão
  captureId: string;      // ID único da captura
  verified: boolean;      // Indica se a verificação foi bem sucedida
  status: 'completed' | 'failed' | 'expired'; // Status da verificação
  processingTime: number; // Tempo de processamento em milissegundos
  base64Data?: string;    // Imagem capturada em Base64 (não disponível para todos os motores)
  failureReason?: string; // Motivo da falha (quando aplicável)
}
```

### Exemplo de Resposta

```json theme={"theme":"catppuccin-latte"}
{
  "sessionId": "sess_abc123xyz",
  "captureId": "cap_def456uvw",
  "verified": true,
  "status": "completed",
  "processingTime": 2340,
  "base64Data": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
}
```

### Utilizando a Resposta

```javascript theme={"theme":"catppuccin-latte"}
hub
  .run(config)
  .then((result) => {
    if (result.verified && result.status === 'completed') {
      // Verificação bem sucedida
      console.log('Sessão:', result.sessionId);
      console.log('Captura:', result.captureId);
      console.log('Tempo de processamento:', result.processingTime, 'ms');

      // Usar a imagem capturada (se disponível)
      if (result.base64Data) {
        const img = document.createElement('img');
        img.src = result.base64Data;
        document.body.appendChild(img);
      }

      // Enviar resultado para seu backend
      enviarParaBackend(result);
    }
  })
  .catch((error) => {
    console.error('Falha na verificação:', error);
  });
```

## Exemplo Completo

```html theme={"theme":"catppuccin-latte"}
<!DOCTYPE html>
<html lang="pt-BR">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Verificação Liveness</title>
    <script src="https://storage.googleapis.com/hub-sdk-cdn/v1.4.3/prod/valid-hub-sdk.js"></script>
    <style>
      .container {
        max-width: 500px;
        margin: 50px auto;
        padding: 20px;
        text-align: center;
      }
      #camera-container {
        width: 100%;
        max-width: 400px;
        aspect-ratio: 9/19.5;
        margin: 20px auto;
        border-radius: 24px;
        background: #f0f0f0;
      }
      .btn {
        padding: 15px 30px;
        font-size: 16px;
        background: #667eea;
        color: white;
        border: none;
        border-radius: 8px;
        cursor: pointer;
      }
      .btn:disabled {
        background: #ccc;
        cursor: not-allowed;
      }
      .message {
        margin-top: 20px;
        padding: 15px;
        border-radius: 8px;
      }
      .success {
        background: #d4edda;
        color: #155724;
      }
      .error {
        background: #f8d7da;
        color: #721c24;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <h1>Verificação de Identidade</h1>
      <div id="camera-container"></div>
      <button id="btn-verificar" class="btn">Iniciar Verificação</button>
      <div id="mensagem"></div>
    </div>

    <script>
      const btnVerificar = document.getElementById('btn-verificar');
      const mensagemDiv = document.getElementById('mensagem');

      // CEK fornecido como string Base64
      const cek = 'sua-cek-base64';

      btnVerificar.addEventListener('click', async () => {
        btnVerificar.disabled = true;
        mensagemDiv.innerHTML = '';

        const hub = ValidHub.createHub();

        try {
          const result = await hub.run({
            apiKey: 'sua-api-key',
            cek: cek,
            mount: '#camera-container',
            env: 'production',
            risk: 'LIVENESS_RISK_HIGH',
          });

          mostrarMensagem(
            `Verificação concluída! ID: ${result.captureId}`,
            'success',
          );
        } catch (error) {
          mostrarMensagem(`Erro: ${error.type || error.message}`, 'error');
        } finally {
          btnVerificar.disabled = false;
        }
      });

      function mostrarMensagem(texto, tipo) {
        mensagemDiv.innerHTML = `<div class="message ${tipo}">${texto}</div>`;
      }
    </script>
  </body>
</html>
```

## Próximos Passos

<CardGroup cols={2}>
  <Card title="Customização" icon="palette" href="/plataforma/liveness/hub/sdk/web/customization">
    Personalize idiomas, textos e cores
  </Card>

  <Card title="Troubleshooting" icon="wrench" href="/plataforma/liveness/hub/sdk/web/troubleshooting">
    Tratamento de erros e boas práticas
  </Card>
</CardGroup>
