# Verificação de idade

<https://unifokal.com/docs/modulos/idade>

## Verificação de idade

O módulo `idade` responde **uma** pergunta, e não a que a maioria espera: ele **não diz a idade do titular**, ele diz se o titular **aparenta ter pelo menos** a idade que o seu flow exige. A estimativa sai pela selfie, sem documento e sem captura nova, e existe para o caso em que pedir documento é desproporcional (barreira de conteúdo adulto, por exemplo). Ele depende da **prova de vida**: sem ela não há rosto ao vivo para estimar, e o módulo recusa antes de estimar qualquer coisa.

**Disponível desde 11 de setembro de 2026.** Ele aparece na tabela de preços e no `GET /v1/capabilities` com preço e status `available`, e pode ser ligado num flow. Até essa data a venda estava pausada, por licença do modelo que estima a idade: o peso anterior tinha origem restrita a pesquisa e foi retirado do produto. O que roda hoje tem cadeia de licença aberta, declarada na página de segurança.

**Dois campos numéricos, e o que decide é o segundo.** `minimum` é a idade que o seu caso de uso **exige** (o requisito legal, 18 por exemplo). `challenge` é o **corte efetivo** que aplicamos, sempre maior ou igual ao `minimum`, e é contra ele que a estimativa é comparada. A margem entre os dois é deliberada: estimativa de idade por imagem erra para os dois lados, e exigir aparentar um pouco mais é o que impede que um menor de idade passe por ruído do modelo. Hoje o corte padrão é **19** para o mínimo de 18, ou seja **um ano** de margem. Quem comparar `estimated_age` com `minimum` chega a uma conclusão diferente da nossa.

```
// idade: aparenta ter a idade exigida. O score sobe com a folga sobre o corte.
{ "module": "idade", "passed": true, "outcome": "approved", "score": 92,
  "data": { "decision": "YES",        // YES | NO | INCONCLUSIVE | NO_LIVENESS
            "estimated_age": 31.2,    // anos, uma casa decimal
            "minimum": 18,            // o que o seu caso EXIGE
            "challenge": 19 } }       // o corte que de fato aplicamos (>= minimum)

// zona cinzenta: nem confirma nem nega -> pending, e vai a revisão
{ "module": "idade", "passed": null, "outcome": "pending", "score": 50,
  "data": { "decision": "INCONCLUSIVE", "estimated_age": 17.6,
            "minimum": 18, "challenge": 19 } }

// a prova de vida não sustentou a estimativa: recusamos ANTES de estimar
{ "module": "idade", "passed": false, "outcome": "failed", "score": 5,
  "data": { "decision": "NO_LIVENESS", "estimated_age": null,
            "minimum": null, "challenge": null } }
```

Os quatro campos podem vir `null` juntos quando a selfie não teve qualidade para nenhuma medida. E os quatro vereditos têm significados distintos que vale separar: `YES` é "aparenta ter", `NO` é "aparenta não ter", `INCONCLUSIVE` é a faixa em que não afirmamos nem uma coisa nem outra (e a verificação vai a revisão, em vez de barrar alguém legítimo), e `NO_LIVENESS` é o caso em que nem chegamos a estimar. **No sandbox só existem `YES` e `NO`**: o ambiente de testes não produz `INCONCLUSIVE` nem `NO_LIVENESS`, e chega a emitir o par `outcome: "pending"` com `decision: "NO"`, que a produção nunca emite (lá `NO` é sempre `failed`). Trate esses dois vereditos como caminhos a implementar às cegas, e teste-os com o seu próprio duplo.
