# Impedidos de apostar

<https://unifokal.com/docs/modulos/impedidos-apostar>

## Impedidos de apostar

O módulo `impedidos_apostar` confere o **CPF e o nome lidos do documento** contra as listas públicas de pessoas vedadas de apostar pela **Lei 14.790/2023 (Art. 26)**, a obrigação legal do operador de apostas de quota fixa perante a SPA/MF. Ele exige **Verificação de Identidade + Face Match + Liveness** no mesmo flow: o dado consultado vem do documento apresentado por quem está vivo na frente da câmera, nunca de um CPF digitado. O widget não ganha nenhum passo novo.

**Cobertura deste módulo**, fonte a fonte, e nada além dela: **agentes públicos** dos órgãos de regulação e fiscalização do setor de apostas (download de servidores do Portal da Transparência, filtrado por lotação). A base é **mensal** e o órgão publica com até dois meses de defasagem, então o competente que entrou no cargo no mês passado ainda não está nela: `dataset_versions` devolve a data em que nós ingerimos, não a data de referência do arquivo do órgão. **Não** estão incluídos, e não os anunciamos: cônjuge e parentes (o vínculo familiar do Art. 26 exige bureau e entra como produto separado), dirigentes de clube, agentes do próprio operador, intermediários e outros esportes. E este módulo **não substitui o SIGAP**: a consulta ao bloco de proteção (menores, beneficiários de programas sociais e autoexcluídos) é uma API do Serpro liberada só para o operador licenciado, que a sua operação já é obrigada a consultar diretamente.

! **Atleta e árbitro NÃO entram, e preferimos dizer isso a listar sem consultar.** A CBF não publica base para conferência automática: o Boletim Informativo Diário é uma página de consulta um a um e os quadros de arbitragem não têm arquivo. Ler aquilo por raspagem de página produziria um "nada consta" falso no dia em que a página mudasse de formato, que é justamente o resultado que gera multa para o operador. As duas fontes aparecem na resposta como `disabled` em `dataset_versions`: você vê, por fonte, o que foi consultado e o que não foi.

! **Este módulo nunca reprova sozinho.** O casamento é por **CPF parcial** (o Portal publica `***.NNN.NNN-**`) mais o nome, ou seja, homônimo continua sendo possível. Um sinal leva a verificação para `review` com a evidência no webhook, para a sua análise decidir. Nunca a `denied` automático.

Cada resposta carimba as fontes que a sustentaram em `coverage` e a idade de cada base em `dataset_versions`: é a sua **prova de diligência** ("na data do cadastro checamos estas bases nestas versões"). Se uma fonte que entraria na resposta estiver vencida, ou ainda sem carga, o módulo devolve `pending` com `dataset_stale` e a verificação vai para `review`: nós não afirmamos "nada consta" sobre base que não conseguimos atualizar, e esse caso **não é cobrado**.

A política **"impedimento reprova?"** é sua: por padrão a restrição **não reprova**, sai como sinalização com evidência e você decide no seu backoffice. Para que a restrição derrube o check, desligue no flow ou por sessão ao criar com `sk_` mandando `{ "policy": { "allow_betting_ban": false } }`. Chave de política desconhecida é 400 `unknown_policy_key`. Flows com este módulo não permitem renovação de sessão pelo widget: a renovação é sempre pelo seu servidor.

**A lista de restrições tem teto de 20, e o corte vem declarado.** O casamento por CPF parcial mais nome produz homônimo em volume, e um payload sem limite viraria incidente de custo e de leitura do seu lado. Passando de 20, `restrictions` sai cortado e `restrictions_truncated` vem `true`. O que continua verdadeiro no corte: `restrictions_total` declara o número **real**, `aggregates` é calculado sobre o conjunto **completo** (então `is_restricted` e `strongest_match` nunca mentem por causa do corte), e a ordenação é determinística **antes** dele: documento, depois documento parcial, depois nome, e maior similaridade primeiro.

**Coincidência de CPF parcial sem o nome confirmar tem resposta própria.** Parte das listas publica o CPF **mascarado**. Quando a máscara do titular coincide com uma linha da lista e o nome do documento **não** confirma, o módulo não devolve `clear`: o `reason` vem `mask_unconfirmed` (ou `mask_unconfirmed_allowed`, se a sua política aceita impedido), `flagged` vem `true` e `mask_unconfirmed_total` diz quantas linhas coincidiram. `restrictions` continua **vazio** e `is_restricted` continua `false`: não há restrição provada, e a linha da pessoa não confirmada nunca viaja. No resumo da verificação esse caso aparece como `inconclusive`, que é diferente de `restricted` e de `clear`. Os quatro valores possíveis em `checks.impedidos_apostar` são `clear`, `restricted`, `inconclusive` e `pending`.

```
// impedidos_apostar: nada consta (fonte fresca)
{ "module": "impedidos_apostar", "passed": true, "outcome": "approved", "score": 95,
  "data": { "is_restricted": false, "flagged": false, "matched_by": "none", "reason": "clear",
            "restrictions": [], "restrictions_total": 0, "restrictions_truncated": false,
            "mask_unconfirmed_total": 0,
            "aggregates": { "is_restricted": false, "restriction_types": [], "strongest_match": null },
            "policy": { "allow_betting_ban": true, "source": "flow" },
            "coverage": ["ptransp_servidores_reg"],
            "coverage_degraded": [],
            // as fontes da CBF viajam SEMPRE, marcadas como nao consultadas
            "dataset_versions": { "ptransp_servidores_reg": { "ingested_at": "2026-08-29T05:41:24Z",
                                                              "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" } }

// impedidos_apostar: agente publico casado por CPF PARCIAL + nome, com a politica reprovando -> review
{ "module": "impedidos_apostar", "passed": false, "outcome": "failed", "score": 20,
  "data": { "is_restricted": true, "flagged": true, "matched_by": "document_partial",
            "reason": "restricted_document_partial",
            "restrictions": [ { "type": "agente_publico", "link_level": 0, "sport": null,
                                "entity": "MINISTERIO DA FAZENDA",
                                "source": "ptransp_servidores_reg",
                                "matched_by": "document_partial", "similarity": 100,
                                "birth_date_mismatch": false,
                                "entry_ref": "ptransp_servidores_reg:e_a8954835",
                                "details": { "orgao": "MINISTERIO DA FAZENDA",
                                             "cargo": "ANALISTA TRIBUTARIO REC FEDERAL BRASIL" } } ],
            "restrictions_total": 1,
            "aggregates": { "is_restricted": true, "restriction_types": ["agente_publico"],
                            "strongest_match": "document_partial" },
            "policy": { "allow_betting_ban": false, "source": "session" } } }

// impedidos_apostar: a mascara publicada coincidiu e o nome NAO confirmou -> review, sem restricao
{ "module": "impedidos_apostar", "passed": false, "outcome": "failed", "score": 45,
  "data": { "is_restricted": false, "flagged": true, "matched_by": "none",
            "reason": "mask_unconfirmed",
            "restrictions": [], "restrictions_total": 0, "mask_unconfirmed_total": 1,
            "policy": { "allow_betting_ban": false, "source": "session" } } }

// impedidos_apostar: fonte vencida -> pending, review, e NAO cobrado
{ "module": "impedidos_apostar", "passed": null, "outcome": "pending", "score": 0,
  "data": { "reason": "dataset_stale", "coverage": [],
            "coverage_degraded": ["ptransp_servidores_reg"] } }
```

Em sandbox nada é consultado: o desfecho vem do sufixo do documento. `02` devolve um agente público casado por CPF parcial, `01` o caminho de fonte vencida (pendente, não cobrado) e `33` um homônimo abaixo do corte, que aprova.
