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

# Vínculos, antecedentes e processos

> Cinco módulos de compliance que aprofundam o screening além do titular: parentes de PEP, vínculos com impedidos, antecedentes estaduais, processos e SCR.

## Vínculos, antecedentes e processos

Cinco módulos de **compliance** aprofundam o screening além do titular: `pep_relatives` (parentes de pessoa exposta politicamente), `betting_barred_relatives` (vínculo familiar com impedido de apostar, a fase 2 da Lei 14.790/2023, Art. 26), `criminal_records_state`, `lawsuits` e `scr_bacen` (retrato de endividamento no SCR). Todos partem do **CPF lido do documento**, e exigem Documento, Face Match e Liveness no mesmo flow pela mesma razão do `pep_sanctions`: nada aqui é consultado a partir de um número digitado. A consulta à fonte é **pelo CPF**; o **nome** só entra no `betting_barred_relatives`, e ainda assim como nome do **parente**, dentro do nosso motor local de vedação.

**Venda pausada hoje, os cinco.** Eles aparecem na tabela de preços e no `GET /v1/capabilities` com preço e status `coming_soon`, e não podem ser ligados num flow enquanto a credencial do fornecedor não existir na conta. O estado vem do catálogo vivo, e esta página acompanha. O payload abaixo é o contrato que já está implementado e que passa a valer no dia da abertura.

> [!WARNING]
>
> **Nunca leia só `flagged` nestes módulos.** Quando a fonte não é chamada (credencial ausente, portão de identidade fechado, consulta adiada), o check sai `pending` **e ainda assim traz `data`**, preenchido com os valores neutros: `flagged: false`, `matched_by: "none"`, `aggregates: null` e o bloco da fonte `null`. Isso é "não perguntamos", e é indistinguível de "nada consta" se você olhar só a flag. Ramifique por `outcome` primeiro, sempre.

**O portão de identidade.** A fonte só é consultada quando a verificação comprova que a pessoa presente é a dona do documento: Face Match, Liveness e leitura do documento aprovados, sem indício de ataque. Sem essa prova a fonte não é consultada, o módulo sai `pending` e **não é cobrado**. No `pep_relatives` e no `betting_barred_relatives`, o `reason` vem `identity_not_proven`. A aprovação manual da verificação no painel não chama estas fontes: o módulo continua `pending`.

**Outro campo que promete mais do que entrega:** nestes módulos `matched_by: "document"` é **derivado de `flagged`**, não é a prova de que o casamento se deu por CPF. Ele diz "houve resultado", e não "casou pelo documento". A única exceção é o `betting_barred_relatives`, onde ele é medido de verdade e distingue `document`, `document_partial` e `name`. E ele **nem existe** em dois dos cinco: `criminal_records_state` e `scr_bacen` não emitem a chave. No `lawsuits`, `document` diz que o titular é réu num processo casado pelo CPF, e um dossiê truncado sinaliza com `none`. Nos demais, trate-a como sinônimo de `flagged`.

```
// pep_relatives: parente PEP encontrado. "relatives" é o dossiê da fonte passando por nós.
{ "module": "pep_relatives", "passed": false, "outcome": "failed", "score": 40,
  "data": { "flagged": true,
            "matched_by": "document",   // derivado de flagged, NÃO é prova de match por CPF
            "reason": null,
            "relatives": { "parentescosPEP": [
              { "nome": "MARIA SILVA", "cpf": "***456789**", "grauParentesco": "MAE",
                "pep": { "nome": "JOSE SILVA", "funcao": "DEPUTADO FEDERAL",
                         "orgao": "CAMARA MOCK", "nivel": "FEDERAL" } } ] } } }

// criminal_records_state: repare no tri-estado de "clear_record" e na cobertura FIXA de UFs.
{ "module": "criminal_records_state", "passed": false, "outcome": "failed", "score": 40,
  "data": { "clear_record": false,      // true | false | null. null = a fonte NÃO afirmou nada.
            "flagged": true,
            "uf_coverage": ["CE", "MG", "MT", "RS"],   // as UFs cobertas hoje, e só elas
            "criminal_records": { "nadaConsta": false,
                              "ocorrencias": [ { "uf": "MG", "tribunal": "TJMG",
                                                 "classe": "Acao Penal", "ano": 2024 } ] } } }

// lawsuits: o titular como RÉU (polo passivo, casado pelo CPF) sinaliza; como autor,
// não. "found_count" e "total_delivered" contam o que foi entregue, já sem processo trabalhista,
// criminal encerrado ou em que o titular é vítima. "truncated": true também pede revisão.
{ "module": "lawsuits", "passed": false, "outcome": "failed", "score": 40,
  "data": { "flagged": true, "matched_by": "document", "found_count": 1,
            "lawsuits": { "total_delivered": 1, "truncated": false,
                           "Lawsuits": [ { "Number": "0001234-56.2024.8.13.0000",
                                           "CourtName": "TJMG", "CourtType": "CIVEL",
                                           "Type": "EXECUCAO DE TITULO EXTRAJUDICIAL",
                                           "Status": "ATIVO", "LawsuitMatchType": "DOC",
                                           "Parties": [ { "Polarity": "PASSIVE", "Type": "DEFENDANT",
                                                          "Name": "TIT****MOCK" } ] } ] } } }

// scr_bacen: INFORMACIONAL. O dossiê é o produto, e "flagged" é sempre false.
{ "module": "scr_bacen", "passed": true, "outcome": "approved", "score": 100,
  "data": { "flagged": false,
            "scr": { "dataBase": "2026-07", "quantidadeInstituicoes": 1,
                     "quantidadeOperacoes": 2,
                     "carteira": { "vencido": 0, "aVencer": 8765.43 } } } }
```

Duas leituras que evitam conclusão errada. `clear_record`, no `criminal_records_state`, tem **três** estados e não dois: `false` quando há ocorrência, `true` só quando a fonte **afirma** que nada consta, e `null` quando não houve ocorrência e a fonte também não afirmou nada. Campo ausente na resposta **nunca** vira atestado nosso. E `scr_bacen.flagged` é **sempre `false`**, por construção: o módulo é informacional, o produto dele é o retrato de endividamento, e não existe caminho no código que o marque. Não escreva alerta em cima dessa flag.

O `betting_barred_relatives` é o mais denso dos cinco, porque ele precisa provar **duas** coberturas ao mesmo tempo: de onde veio o **grafo familiar** (`graph_coverage`, hoje sempre `"pep_relatives"`, ou seja a fonte de parentesco de PEP e mais nada) e quais **bases de vedação** sustentaram a triagem de cada parente (`coverage` e `dataset_versions`, as mesmas do módulo [Impedidos de apostar](https://docs.unifokal.com/modulos/impedidos-apostar.md#modulo-impedidos-apostar)). E ele conta os parentes de forma auditável: `relatives_total` é quanto a fonte devolveu, `relatives_screened` é quanto o motor de fato respondeu, e `relatives_unscreened` agrupa **por motivo** quem ficou de fora. Essa lista tem vocabulário fechado de seis valores: `degree_unknown`, `degree_out_of_scope`, `document_missing`, `name_missing`, `screening_indeterminate` e `over_cap`. Repare que `relatives_total` menos `relatives_screened` **não** é o tamanho dessa lista: ela é agrupada, e cada item traz o próprio `count`.

```
// betting_barred_relatives: parente de 1o grau na base de impedidos -> review COM evidência
{ "module": "betting_barred_relatives", "passed": false, "outcome": "failed", "score": 40,
  "data": { "is_restricted": true, "flagged": true,
            "matched_by": "name",            // aqui ele é MEDIDO: document | document_partial | name
            "reason": "family_link_restricted",
            "restrictions": [ { "type": "vinculo_familiar_1g", "link_level": 1, "sport": null,
                                "entity": null, "source": "ptransp_servidores_reg",
                                "matched_by": "name",
                                "similarity": 91,       // 0..100, NÃO 0..1
                                "listed_at": null, "left_at": null,
                                "birth_date_mismatch": false,
                                "entry_ref": "ptransp_servidores_reg:e_a8954835" } ],
            "restrictions_total": 1, "restrictions_truncated": false,
            "aggregates": { "is_restricted": true,
                            "restriction_types": ["vinculo_familiar_1g"],
                            "strongest_match": "name" },
            "graph_coverage": "pep_relatives",
            "relatives_total": 2, "relatives_screened": 2, "relatives_unscreened": [],
            "coverage": ["ptransp_servidores_reg"], "coverage_degraded": [],
            "dataset_versions": { "ptransp_servidores_reg": { "ingested_at": "2026-09-01T03:00:00Z",
                                                              "age_hours": 4, "stale": false,
                                                              "disabled": false },
                                  "cbf_bid":      { "ingested_at": null, "age_hours": null,
                                                    "stale": false, "disabled": true },
                                  "cbf_arbitros": { "ingested_at": null, "age_hours": null,
                                                    "stale": false, "disabled": true } },
            "name_source": "ocr" } }

// identidade não comprovada: a fonte NÃO foi chamada, pending, sem cobrança.
{ "module": "pep_relatives", "passed": null, "outcome": "pending", "score": 0,
  "data": { "flagged": false, "matched_by": "none", "reason": "identity_not_proven",
            "relatives": null } }

// o caminho que MAIS importa: o parente existe e NÃO foi rastreável.
// Não é "nada consta": é "não deu para perguntar", e a contagem diz por quê.
{ "module": "betting_barred_relatives", "passed": null, "outcome": "pending", "score": 0,
  "data": { "is_restricted": false, "flagged": false, "matched_by": "none",
            "reason": "relatives_unscreenable",
            "restrictions": [], "restrictions_total": 0, "restrictions_truncated": false,
            "aggregates": null,
            "graph_coverage": "pep_relatives",
            "relatives_total": 1, "relatives_screened": 0,
            "relatives_unscreened": [ { "reason": "degree_unknown", "count": 1 } ],
            // vazios porque o motor local NEM FOI CHAMADO: sem grau de parentesco não há o
            // que triar, então não há cobertura a declarar. Não confunda com base vencida.
            "coverage": [], "coverage_degraded": [], "dataset_versions": null,
            "name_source": null } }   // null porque nem chegamos a usar um nome
```

**Nenhum dos cinco reprova sozinho**, pela mesma regra do `pep_sanctions`: um resultado é candidato, vai para `review` com a evidência no webhook, e a sua análise decide. E vale a mesma minimização: o que sai do `betting_barred_relatives` sobre o parente é **contagem e restrição minimizada**, nunca nome, CPF ou datas de terceiro. O nome e o documento do parente entram na consulta e morrem lá.

> [!WARNING]
>
> **No sandbox, o desfecho destes módulos não acompanha o resultado, e isso é deliberado do ambiente de testes.** Os sufixos `88` (hit) e `77` (indeterminado, só no `betting_barred_relatives`) escolhem o **dado**, mas o `outcome` continua vindo da tabela universal do sandbox, onde só `00`, `01` e `02` mudam o desfecho. Ou seja: em sandbox você vê `outcome: "approved"` com `flagged: true`. Em produção o mesmo hit sai `failed` e a verificação vai a revisão. Use os sufixos para exercitar o **parser**, e `02` para exercitar o desfecho.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.