# Fluxo de Biometria

Guie o cliente pela verificação de identidade, acompanhe o progresso e saiba como reagir a cada resultado.

## Visão Geral

Após [cadastrar o cliente](/guides/customer-registration), dois processos acontecem em paralelo:

1. **Análise de crédito** — a Dinie começa automaticamente a avaliar o perfil de crédito da empresa.
2. **Verificação KYC** — o cliente precisa enviar documentos e completar a biometria no seu próprio ritmo.


Você não precisa esperar a análise de crédito terminar para iniciar a verificação. Assim que o cliente atingir o status `pending_kyc`, apresente a opção de iniciar a biometria.

## 1. Apresentar a Verificação ao Cliente

Quando o webhook `customer.created` chegar (ou quando o status mudar para `pending_kyc`), apresente ao cliente a opção de iniciar a verificação. Você pode mostrar um botão explícito ou iniciar automaticamente.

![Fluxo de cadastro até a sessão de biometria](/assets/flow-start-verification.93dfa08d0b6edfe2a811752438ba1f4a979bb096586f099406a0fc32e0c6ee76.53e9d79f.svg)

O importante é comunicar ao cliente que ele precisa completar a verificação de identidade para receber ofertas de crédito.

## 2. Criar a Sessão de Biometria

Quando o cliente confirmar que quer iniciar, crie uma sessão de biometria:


```typescript Node.js
const session = await client.customers.createBiometricsSession(customer.id);

// Abra esta URL em um webview ou redirecione o cliente
console.log(session.session_url);
console.log(session.expires_at); // Expira em 30 minutos
```


```ruby Ruby
session = client.customers.create_biometrics_session(customer.id)

# Abra esta URL em um webview ou redirecione o cliente
puts session.session_url
puts session.expires_at # Expira em 30 minutos
```


```python Python
session = client.customers.create_biometrics_session(customer.id)

# Abra esta URL em um webview ou redirecione o cliente
print(session.session_url)
print(session.expires_at)  # Expira em 30 minutos
```


```bash cURL
curl -X POST "https://sandbox.api.dinie.com.br/v3/customers/${CUSTOMER_ID}/biometrics" \
  -H "Authorization: Bearer dinie_at_..."
```

Abra a `session_url` em um **webview** (mobile) ou **redirecione** o navegador (web). A sessão expira em 30 minutos — se expirar, gere uma nova.

> **Tip:** Se o parceiro já possui documentos do cliente, pode enviá-los via API antes de gerar a sessão. Documentos enviados antecipadamente já aparecerão como completos na sessão, acelerando o processo para o cliente. Veja [Envio Antecipado via API](/guides/kyc-requirements#envio-antecipado-via-api).


## 3. O que o Cliente Verá

Na sessão de biometria, o cliente verá a lista de documentos necessários. Documentos já enviados via API aparecem como completos. O cliente precisa completar os itens pendentes.

![Sessão de biometria: documentos, selfie e revisão](/assets/flow-biometrics-session.cd7f9cfac3175708f025b890fc2bcf288b5666847cdde7ce2efcdfa99bb4cfd7.53e9d79f.svg)

O fluxo na sessão inclui:

- **Envio de documentos** — fotos de identidade (CNH ou RG), comprovante de endereço, documentos da empresa
- **Selfie** — captura pelo próprio cliente via câmera do dispositivo
- **Revisão** — visualizar tudo que foi enviado antes de confirmar


Ao final, o cliente terá duas opções:

- **Salvar para depois** — o progresso é mantido, mas a análise não é disparada
- **Enviar para análise** — dispara a verificação de todos os documentos


## 4. Salvar para Depois

Se o cliente escolher "Salvar para depois", ele retornará ao seu ambiente. Nenhuma análise é disparada nesse momento — o cliente pode voltar a qualquer momento para continuar.

Você pode acompanhar o progresso de duas formas:

**Via webhook:** receba o `customer.kyc_updated` sempre que um documento for enviado. O payload inclui o array `kyc` atualizado.

**Via API:** consulte o cliente e verifique o campo `kyc`:


```typescript Node.js
const customer = await client.customers.get(customerId);

for (const req of customer.kyc) {
  const status = req.submitted ? "Enviado" : "Pendente";
  console.log(`${req.label}: ${status}`);
}
```


```ruby Ruby
customer = client.customers.get(customer_id)

customer.kyc.each do |req|
  status = req["submitted"] ? "Enviado" : "Pendente"
  puts "#{req["label"]}: #{status}"
end
```


```python Python
customer = client.customers.get(customer_id)

for req in customer.kyc:
    status = "Enviado" if req["submitted"] else "Pendente"
    print(f"{req['label']}: {status}")
```


```bash cURL
curl "https://sandbox.api.dinie.com.br/v3/customers/${CUSTOMER_ID}" \
  -H "Authorization: Bearer dinie_at_..."

# Verifique customer.kyc[].submitted para cada requisito
```

Mostre ao cliente o progresso da verificação — quais documentos já foram enviados e quais ainda faltam. Para retomar, basta gerar uma nova sessão de biometria. O progresso anterior é preservado.

![Fluxo de salvar, acompanhar e retomar](/assets/flow-save-resume.c73f4727390691c7993309c7d57f43b851ceb09e8449e2fa60680e5377a4143c.53e9d79f.svg)

## 5. Enviar para Análise

Quando o cliente clicar "Enviar para análise" na sessão de biometria, a Dinie inicia a verificação de todos os documentos. Você receberá o webhook `customer.under_review`, e o status do cliente mudará para `under_review`.


```typescript Node.js
app.post("/webhooks/dinie", express.raw({ type: "application/json" }), (req, res) => {
  const event = client.webhooks.unwrap(req.body.toString(), req.headers);

  if (event.type === "customer.under_review") {
    updateCustomerScreen(event.data.external_id, "Em análise");
  }

  res.sendStatus(200);
});
```


```ruby Ruby
post "/webhooks/dinie" do
  event = client.webhooks.unwrap(request.body.read, request.env)

  if event["type"] == "customer.under_review"
    update_customer_screen(event.dig("data", "external_id"), "Em análise")
  end

  status 200
end
```


```python Python
@app.post("/webhooks/dinie")
async def handle_webhook(request: Request):
    event = client.webhooks.unwrap(await request.body(), request.headers)

    if event["type"] == "customer.under_review":
        update_customer_screen(event["data"]["external_id"], "Em análise")

    return Response(status_code=200)
```


```bash cURL
# Webhook recebido no seu endpoint:
# {
#   "type": "customer.under_review",
#   "data": {
#     "id": "cust_550e8400...",
#     "external_id": "partner-ref-123",
#     "status": "under_review"
#   }
# }
```

A partir daqui, a Dinie pode aprovar, negar ou solicitar correções em documentos específicos.

## 6. Resultado: Aprovado

Se todos os documentos forem aprovados, o cliente recebe o status `active` e você recebe o webhook `customer.active`.

Isso **não significa** que já existem ofertas de crédito. A análise de crédito acontece em paralelo e pode levar mais tempo. A partir do momento que o cliente é `active`, a Dinie continua processando a análise de crédito.

Quando uma oferta estiver disponível, você receberá o webhook `credit_offer.available`:


```typescript Node.js
app.post("/webhooks/dinie", express.raw({ type: "application/json" }), (req, res) => {
  const event = client.webhooks.unwrap(req.body.toString(), req.headers);

  if (event.type === "customer.active") {
    updateCustomerScreen(event.data.external_id, "Verificado");
  }

  if (event.type === "credit_offer.available") {
    const offers = await client.creditOffers.list(event.data.customer_id);
    notifyCustomer(event.data.external_id, offers);
  }

  res.sendStatus(200);
});
```


```ruby Ruby
post "/webhooks/dinie" do
  event = client.webhooks.unwrap(request.body.read, request.env)

  case event["type"]
  when "customer.active"
    update_customer_screen(event.dig("data", "external_id"), "Verificado")
  when "credit_offer.available"
    offers = client.credit_offers.list(event.dig("data", "customer_id"))
    notify_customer(event.dig("data", "external_id"), offers)
  end

  status 200
end
```


```python Python
@app.post("/webhooks/dinie")
async def handle_webhook(request: Request):
    event = client.webhooks.unwrap(await request.body(), request.headers)

    if event["type"] == "customer.active":
        update_customer_screen(event["data"]["external_id"], "Verificado")

    if event["type"] == "credit_offer.available":
        offers = client.credit_offers.list(event["data"]["customer_id"])
        notify_customer(event["data"]["external_id"], offers)

    return Response(status_code=200)
```


```bash cURL
# Webhook customer.active:
# { "type": "customer.active", "data": { "status": "active", ... } }

# Webhook credit_offer.available:
# { "type": "credit_offer.available", "data": { "approved_amount": 50000.00, ... } }

# Listar ofertas:
curl "https://sandbox.api.dinie.com.br/v3/customers/${CUSTOMER_ID}/credit-offers" \
  -H "Authorization: Bearer dinie_at_..."
```

![Aguardando ofertas e oferta disponível](/assets/flow-approved-offers.9fd27113db4f3474b82c79b298486fe36c7f3dc7c6eace4b9e03e2407894a4db.53e9d79f.svg)

> **Info:** Entre o `customer.active` e o `credit_offer.available`, mostre ao cliente uma mensagem como "Verificação concluída, estamos buscando as melhores ofertas para você". Isso transmite que o processo está avançando.


## 7. Resultado: Documentos Pendentes

Se a Dinie identificar problemas em algum documento, você receberá o webhook `customer.kyc_updated` com os detalhes. Consulte o campo `kyc` para verificar quais documentos foram rejeitados:


```typescript Node.js
const customer = await client.customers.get(customerId);

for (const req of customer.kyc) {
  if (req.submitted?.review_status === "rejected") {
    console.log(`${req.label}: Rejeitado — ${req.submitted.review_reason}`);
  }
}
```


```ruby Ruby
customer = client.customers.get(customer_id)

customer.kyc.each do |req|
  submitted = req["submitted"]
  if submitted && submitted["review_status"] == "rejected"
    puts "#{req["label"]}: Rejeitado — #{submitted["review_reason"]}"
  end
end
```


```python Python
customer = client.customers.get(customer_id)

for req in customer.kyc:
    submitted = req.get("submitted")
    if submitted and submitted.get("review_status") == "rejected":
        print(f"{req['label']}: Rejeitado — {submitted['review_reason']}")
```


```bash cURL
curl "https://sandbox.api.dinie.com.br/v3/customers/${CUSTOMER_ID}" \
  -H "Authorization: Bearer dinie_at_..."

# Verifique customer.kyc[].submitted.review_status e review_reason
```

Mostre ao cliente quais documentos precisam de correção e o motivo da rejeição. Você não precisa fazer nada diretamente na API — apenas apresente um botão para o cliente abrir a sessão de biometria novamente:


```typescript Node.js
// Gere uma nova sessão para o cliente corrigir os documentos
const session = await client.customers.createBiometricsSession(customer.id);
redirectCustomer(session.session_url);
```


```ruby Ruby
# Gere uma nova sessão para o cliente corrigir os documentos
session = client.customers.create_biometrics_session(customer.id)
redirect_customer(session.session_url)
```


```python Python
# Gere uma nova sessão para o cliente corrigir os documentos
session = client.customers.create_biometrics_session(customer.id)
redirect_customer(session.session_url)
```


```bash cURL
# Gere uma nova sessão
curl -X POST "https://sandbox.api.dinie.com.br/v3/customers/${CUSTOMER_ID}/biometrics" \
  -H "Authorization: Bearer dinie_at_..."
```

Na sessão, os documentos rejeitados aparecerão destacados com o motivo da rejeição. O cliente corrige, reenvia, e o ciclo se repete até que todos sejam aprovados.

![Fluxo de correção de documentos](/assets/flow-documents-pending.4b5ca813494ad2787378318755dc7ea2480f228b1b4823246f4b15ace1167ca3.53e9d79f.svg)

## 8. Resultado: Negado

Se o cliente for negado permanentemente, você receberá o webhook `customer.denied`. Isso indica que a Dinie não conseguiu aprovar o cliente na análise de KYC (por exemplo, fraude detectada ou empresa encerrada).

Neste caso, informe ao cliente que **não é possível oferecer crédito neste momento**. Diferente do cenário de aprovação sem ofertas (onde o cliente pode receber ofertas no futuro), o status `denied` é definitivo.

![Avaliação e resultado negado](/assets/flow-denied.556e249c1276b85997fb898bb42584f0246b1b1027270bdd28395c32fd42f1be.53e9d79f.svg)

> **Warning:** Não comunique ao cliente o motivo específico da negação. Informe apenas que não foi possível prosseguir com a análise neste momento.


## Resumo do Fluxo

| Etapa | Ação do parceiro | API / Webhook |
|  --- | --- | --- |
| Cliente cadastrado | Apresentar botão de verificação | `customer.created` webhook |
| Cliente inicia | Criar sessão de biometria | `POST biometrics` |
| Cliente na sessão | Aguardar | — |
| Salvar para depois | Mostrar progresso | `customer.kyc_updated` webhook ou `GET customer` |
| Enviar para análise | Mostrar "em análise" | `customer.under_review` webhook |
| Aprovado | Aguardar ofertas | `customer.active` + `credit_offer.available` webhooks |
| Documento rejeitado | Mostrar motivo + botão para corrigir | `customer.kyc_updated` webhook |
| Negado | Informar cliente | `customer.denied` webhook |


## Guias Relacionados

- [Cadastro e Ofertas](/guides/customer-registration) para o fluxo completo de criação do cliente
- [Requisitos de KYC](/guides/kyc-requirements) para detalhes sobre tipos de documentos
- [Simulação e Contratação](/guides/credit-workflow) para o passo seguinte após receber ofertas
- [Webhooks](/apis/concepts/webhooks) para configurar os endpoints de notificação