> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gu1.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Face Match (Documento + Selfie)

> Verificar se uma selfie e a foto do documento correspondem à mesma pessoa em uma única chamada à API. Consulte o esquema do request, códigos de resposta.

## Resumo

Face Match é um **serviço de verificação da Gu1** que compara duas imagens: uma **selfie** (foto atual da pessoa) e uma **imagem de referência do documento** (por exemplo a foto do documento de identidade). A API retorna se as faces coincidem (mesma pessoa) e uma pontuação de similaridade. Não há sessão hospedada nem detecção de vida em tempo real: você envia as imagens e recebe o resultado em uma única chamada.

<Note>
  **Quando usar cada um**

  * **KYC por sessão** (`POST /api/kyc/validations`): Fluxo completo com URL hospedada, selfie ao vivo, liveness e captura de documento. Ideal para onboarding e fluxos regulados.
  * **Face Match** (`POST /api/kyc/face-match`): Você envia duas imagens (como arquivos ou base64) e recebe correspondência + pontuação. Ideal quando você já tem documento e selfie (por exemplo da sua própria aplicação).
</Note>

## Pré-requisitos

Antes de usar o Face Match:

1. **Integração Face Match ativada**: Sua organização deve ter a integração KYC Face Match ativada (por exemplo no Marketplace / Integrações).
2. **Credenciais configuradas**: A API key e o webhook secret da integração Face Match devem estar configurados nas configurações KYC da organização (definido pelo administrador da Gu1).
3. **Limiar (opcional)**: A pontuação mínima para aprovar (0–100) é configurada em **Configurações da organização → KYC** (card Face Match). Se não for definido, o padrão é 30. Apenas os administradores da organização podem alterar esse valor.

<Info>
  Face Match é um serviço da Gu1. Toda a verificação é feita na infraestrutura da Gu1.
</Info>

## Solicitação

### Endpoint

```
POST https://api.gu1.ai/api/kyc/face-match
```

### Content-Type

**Apenas `multipart/form-data`** é aceito. Você pode enviar as imagens de duas formas (ou misturar):

1. **Como arquivos**: anexar arquivos de imagem nos campos do form `documentImage` e `selfieImage`.
2. **Como strings base64**: enviar os mesmos nomes de campo com a imagem em base64 (com ou sem prefixo `data:image/...;base64,`).

Se uma imagem **obrigatória** estiver faltando (nem arquivo nem base64 para esse campo), a API retorna **400**. Para cada imagem, se você enviar arquivo e base64, o arquivo tem prioridade.

### Headers

```
Authorization: Bearer SUA_API_KEY
Content-Type: multipart/form-data; boundary=----...
```

Não defina `Content-Type` manualmente ao usar FormData; o cliente define com o boundary correto.

Se sua conta usa escopo por organização, inclua:

```
X-Organization-Id: SEU_ORGANIZATION_ID
```

### Campos do form

<ParamField body="documentImage" type="file | string" required>
  Imagem de referência (por exemplo a foto do documento). Enviar como **arquivo** (recomendado) ou como **string** (base64, com ou sem prefixo `data:image/...;base64,`). Formatos: JPEG, PNG, WebP, TIFF. Máx. 5MB.
</ParamField>

<ParamField body="selfieImage" type="file | string" required>
  Imagem da selfie. Mesmo que `documentImage`: arquivo ou base64. Obrigatório.
</ParamField>

<ParamField body="entityId" type="string">
  UUID opcional da entidade pessoa a associar a esta verificação. Usado para auditoria e para listar verificações por entidade.
</ParamField>

<ParamField body="scoreThreshold" type="number">
  Opcional. Limiar 0–100; resultados abaixo são recusados. Se omitido, usa o limiar configurado na organização (ou 30 por padrão).
</ParamField>

<ParamField body="vendorData" type="string">
  Referência opcional (por exemplo seu ID de usuário) para rastreamento. Armazenada no registro de auditoria.
</ParamField>

<ParamField query="doubleCheckRenaper" type="boolean">
  Com `true`, após aprovação do face match Gu1 executa RENAPER **biométrico** (`validate-dni` com selfie) e **dados** (`renaper/data`: DNI + trâmite). Requer credenciais RENAPER da org **e** integrações Marketplace ativas: `ar_renaper_data_enrichment` e `ar_renaper_validate_dni_enrichment`. Query prevalece sobre o body.
</ParamField>

<ParamField body="doubleCheckRenaper" type="boolean">
  Igual ao query param `doubleCheckRenaper`.
</ParamField>

<ParamField body="documentNumber" type="string">
  DNI para RENAPER quando `doubleCheckRenaper=true`. Opcional se `entityId` resolver `taxId` ou `person.idNumber`.
</ParamField>

<ParamField body="gender" type="string">
  Gênero para RENAPER (`M`, `F`, `male`, `female`). Obrigatório salvo resolução pela entidade vinculada.
</ParamField>

<ParamField body="personalNumber" type="string" required>
  Número de trâmite para chequeo RENAPER. **Obrigatório** com `doubleCheckRenaper=true`.
</ParamField>

O **limiar mínimo (threshold)** pode ser enviado no form; se não for enviado, é lido da configuração KYC da organização. A resposta inclui o limiar usado na chamada.

## Resposta

### Resposta de sucesso (200 OK)

| Campo                   | Tipo                 | Descrição                                                                                                                                                                                                           |
| ----------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `match`                 | boolean              | Se as faces foram consideradas coincidentes (pontuação ≥ limiar).                                                                                                                                                   |
| `score`                 | number               | Pontuação de similaridade 0–100.                                                                                                                                                                                    |
| `status`                | string               | `"approved"` \| `"declined"` \| `"in_review"`.                                                                                                                                                                      |
| `verificationId`        | string               | ID do registro de auditoria em `face_match_verifications` (suporte e listagem).                                                                                                                                     |
| `scoreDeclineThreshold` | number               | Limiar (0–100) usado nesta verificação (configuração da org).                                                                                                                                                       |
| `requestId`             | string (opcional)    | ID interno da solicitação (suporte).                                                                                                                                                                                |
| `warnings`              | string\[] (opcional) | Array de **códigos de risco** da verificação (ex.: `LOW_FACE_MATCH_SIMILARITY`, `NO_REFERENCE_IMAGE`). Veja [Códigos de risco em avisos](/pt/use-cases/kyc/warning-risk-codes) para todos os valores.               |
| `doubleCheckRenaper`    | boolean (opcional)   | `true` se dupla verificação RENAPER foi solicitada.                                                                                                                                                                 |
| `responseDoubleChecks`  | object (opcional)    | Com `doubleCheckRenaper=true`: `renaper` com dados/trâmite e `renaper.renaperBiometric` (ABIS). Mesma forma que [KYC validations RENAPER](/pt/use-cases/kyc/create-validation#dupla-verificação-renaper-argentina). |

Se RENAPER falhar após aprovação do provedor, `match` vira `false`, `status` vira `"declined"` e códigos RENAPER entram em `warnings`. Use timeout HTTP ≥ 60 s com double-check.

**Exemplo:**

```json theme={null}
{
  "match": true,
  "score": 85.5,
  "status": "approved",
  "verificationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "scoreDeclineThreshold": 30,
  "requestId": "req_xyz",
  "warnings": []
}
```

## Exemplo de solicitação

<CodeGroup>
  ```javascript Node.js (arquivos) theme={null}
  const form = new FormData();
  form.append('documentImage', documentFile); // File object
  form.append('selfieImage', selfieFile);
  form.append('entityId', '123e4567-e89b-12d3-a456-426614174000');

  const response = await fetch('https://api.gu1.ai/api/kyc/face-match', {
    method: 'POST',
    headers: { 'Authorization': 'Bearer SUA_API_KEY' },
    body: form,
  });
  const result = await response.json();
  console.log('Match:', result.match, 'Score:', result.score);
  ```

  ```javascript Node.js (base64 nos campos) theme={null}
  const form = new FormData();
  form.append('documentImage', 'data:image/jpeg;base64,/9j/4AAQ...');
  form.append('selfieImage', 'data:image/jpeg;base64,/9j/4AAQ...');
  form.append('entityId', '123e4567-e89b-12d3-a456-426614174000');

  const response = await fetch('https://api.gu1.ai/api/kyc/face-match', {
    method: 'POST',
    headers: { 'Authorization': 'Bearer SUA_API_KEY' },
    body: form,
  });
  const result = await response.json();
  ```

  ```python Python (arquivos) theme={null}
  import requests

  with open('documento.jpg', 'rb') as doc, open('selfie.jpg', 'rb') as selfie:
      files = {
          'documentImage': ('documento.jpg', doc, 'image/jpeg'),
          'selfieImage': ('selfie.jpg', selfie, 'image/jpeg'),
      }
      data = {'entityId': '123e4567-e89b-12d3-a456-426614174000'}
      response = requests.post(
          'https://api.gu1.ai/api/kyc/face-match',
          headers={'Authorization': 'Bearer SUA_API_KEY'},
          files=files,
          data=data,
      )
  result = response.json()
  print('Match:', result['match'], 'Score:', result['score'])
  ```

  ```python Python (base64 nos campos) theme={null}
  import requests
  import base64

  with open('documento.jpg', 'rb') as f:
      doc_b64 = 'data:image/jpeg;base64,' + base64.b64encode(f.read()).decode()
  with open('selfie.jpg', 'rb') as f:
      selfie_b64 = 'data:image/jpeg;base64,' + base64.b64encode(f.read()).decode()

  response = requests.post(
      'https://api.gu1.ai/api/kyc/face-match',
      headers={'Authorization': 'Bearer SUA_API_KEY'},
      data={
          'documentImage': doc_b64,
          'selfieImage': selfie_b64,
          'entityId': '123e4567-e89b-12d3-a456-426614174000',
      },
  )
  result = response.json()
  ```

  ```curl cURL (arquivos) theme={null}
  curl -X POST https://api.gu1.ai/api/kyc/face-match \
    -H "Authorization: Bearer SUA_API_KEY" \
    -F "documentImage=@documento.jpg" \
    -F "selfieImage=@selfie.jpg" \
    -F "entityId=123e4567-e89b-12d3-a456-426614174000"
  ```

  ```curl cURL (base64) theme={null}
  curl -X POST https://api.gu1.ai/api/kyc/face-match \
    -H "Authorization: Bearer SUA_API_KEY" \
    -F "documentImage=data:image/jpeg;base64,/9j/4AAQ..." \
    -F "selfieImage=data:image/jpeg;base64,/9j/4AAQ..." \
    -F "entityId=123e4567-e89b-12d3-a456-426614174000"
  ```
</CodeGroup>

## Respostas de erro

Códigos de erro comuns:

| Código                | HTTP | Significado                                                                                                                                  |
| --------------------- | ---- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `NOT_CONFIGURED`      | 403  | Credenciais Face Match não configuradas na organização.                                                                                      |
| `NOT_ENABLED`         | 403  | Integração Face Match não ativada para esta organização.                                                                                     |
| `INVALID_REQUEST`     | 400  | Content-Type não é multipart/form-data, ou imagens faltando/inválidas (ex.: sem arquivo nem base64 para campo obrigatório, formato/tamanho). |
| `UNAUTHORIZED`        | 401  | Credenciais de API/verificação inválidas ou faltando.                                                                                        |
| `QUOTA_EXCEEDED`      | 403  | Não foi possível concluir a verificação (ex.: cota/créditos).                                                                                |
| `SERVICE_UNAVAILABLE` | 503  | Serviço de verificação temporariamente indisponível.                                                                                         |
| `VERIFICATION_FAILED` | 500  | Não foi possível concluir a verificação; tentar novamente ou outras imagens.                                                                 |

## Auditoria e listagem de verificações

Cada solicitação de Face Match (sucesso ou falha) é armazenada em **`face_match_verifications`** para auditoria e conformidade. A resposta inclui **`verificationId`** (ID do registro de auditoria). Cada registro salvo também armazena o **limiar** usado no momento da chamada (para exibir no histórico mesmo que o limiar da org mude depois).

### Listar registros de auditoria

```
GET https://api.gu1.ai/api/kyc/face-match/verifications?entityId={entityId}&limit=50&offset=0
```

**Parâmetros de query:**

| Parâmetro  | Tipo          | Descrição                                                                     |
| ---------- | ------------- | ----------------------------------------------------------------------------- |
| `entityId` | string (UUID) | Opcional. Filtrar por entidade pessoa.                                        |
| `status`   | string        | Opcional. Filtrar por status (`approved`, `declined`, `in_review`, `failed`). |
| `limit`    | number        | Máximo de itens (padrão 50, máx. 100).                                        |
| `offset`   | number        | Deslocamento da paginação.                                                    |

**Resposta:** `{ "verifications": [ ... ], "scoreDeclineThreshold": 30, "pagination": { "limit", "offset", "total" } }`. Cada verificação inclui `id`, `entityId`, `status`, `match`, `score`, `threshold` (valor usado naquela execução), `createdAt` e caminhos de imagem opcionais para auditoria.

### Obter verificação por ID

Obtém um registro de auditoria de Face Match pelo `verificationId` (retornado na resposta do POST ou na listagem).

```
GET https://api.gu1.ai/api/kyc/face-match/verifications/:id
```

**Parâmetro de path:** `id` — UUID da verificação (igual ao `verificationId` do POST ou da listagem).

**Resposta (200):** Um objeto de verificação com os mesmos campos de cada item da listagem: `id`, `organizationId`, `entityId`, `status`, `match`, `score`, `requestId`, `vendorData`, `errorMessage`, `triggeredByUserId`, `createdAt`, `documentStoragePath`, `selfieStoragePath`, `storageProvider`, `threshold`.

**Erros:** `404 NOT_FOUND` se o ID não existir ou pertencer a outra organização; `401 UNAUTHORIZED` se não estiver autenticado.

## Convivência com KYC por sessão

* **Fluxo por sessão** cria um registro em `kyc_validations`, envia o usuário a uma URL hospedada e atualiza o status via webhooks. A decisão armazenada inclui documento, liveness e face match da sessão ao vivo.
* **Face Match** cria um registro de auditoria em `face_match_verifications` e retorna o resultado na mesma solicitação. **Não** cria registro em `kyc_validations`. Use quando precisar de uma verificação pontual (ex.: «estas duas imagens são a mesma pessoa?») sem sessão hospedada.
* Ambos usam a mesma configuração KYC da organização. O limiar do Face Match é definido em Configurações da organização → KYC (card Face Match).

## Próximos passos

<CardGroup cols={2}>
  <Card title="Criar validação KYC" icon="play" href="/pt/use-cases/kyc/create-validation">
    Verificação por sessão com URL hospedada
  </Card>

  <Card title="Listar validações" icon="list" href="/pt/use-cases/kyc/list-validations">
    Listar validações KYC por entidade
  </Card>
</CardGroup>
