Catalisa.Building Blocks
Catálogo/Identidade/Biometrics

Biometrics

Alpha

Prova de vida e match facial com motor próprio, no contrato dos provedores certificados

33
Endpoints
7
Entidades
2
Provedores
Tenant
Escopo
3034
Porta
2026-09
Desde

A pessoa diante da câmera está viva e é a mesma do documento? Sessão, página de captura hospedada, decisão explicável com score, limiar e versão de modelo, e evidência assinada — com um nível de garantia declarado, para que a aprovação do motor aberto nunca pareça a de um provedor certificado.

Para quem é
  • Fintechs que abrem conta ou concedem crédito e precisam de KYC com prova de vida antes de fechar contrato com FaceTec ou Unico
  • Produtos que confirmam operação de alto valor pela face de um cliente já cadastrado, como segundo fator
  • Times que precisam provar à auditoria como cada verificação foi decidida, com qual modelo, qual limiar e qual evidência
Substitui
  • O SDK do provedor colado direto no app, com a decisão tomada no front
  • A selfie comparada com o documento sem prova de vida, que uma foto impressa engana
  • O contrato com provedor fechado antes de saber quanto a própria base vai exigir
O que não é
  • Documentoscopia — lê MRZ e QR, mas não diz se o RG é verdadeiro
  • Consulta a bureau, score ou listas restritivas
  • Reconhecimento 1:N em multidão ou vigilância
  • Um cadastro de clientes — guarda o rosto e a decisão, e se liga ao Customers pelo customerId
O que dá para fazer

33 endpoints em 5 recursos.

Explorar a API →

Telas

o que o usuário vê
Convite para testar
Convite para testarA página que a pessoa recebe por link. Pede o consentimento e rotula o que vai aparecer na câmera — ela mesma, foto impressa, foto ou vídeo numa tela, máscara — nas espécies da ISO/IEC 30107-3.
Convite para testar
Convite para testarA página que a pessoa recebe por link. Pede o consentimento e rotula o que vai aparecer na câmera — ela mesma, foto impressa, foto ou vídeo numa tela, máscara — nas espécies da ISO/IEC 30107-3.
Antes de abrir a câmera
Antes de abrir a câmeraO roteiro aparece antes de começar, com o número de gestos sorteado para esta sessão. Nada é gravado até a pessoa clicar.
Preparo antes de gravar
Preparo antes de gravarO primeiro gesto aparece com uma contagem de 2,5 s antes de a gravação começar. A pessoa lê com calma e a câmera acerta a luz.
Guia ao vivo
Guia ao vivoO rosto é lido no próprio navegador e o selo confirma quando o gesto foi feito. O vídeo está escondido nesta imagem por privacidade; na captura real a pessoa se vê.
Dica durante o gesto
Dica durante o gestoQuando o gesto está incompleto, a página diz o que falta em vez de esperar a reprovação. O ícone do rosto mostra o movimento.
O próximo gesto
O próximo gestoO próximo passo é anunciado antes de a janela dele começar, para a pessoa ler com calma. Cada janela tem duração sorteada.
Nova tentativa
Nova tentativaUma falha de uso, como gesto fora do tempo, vira nova tentativa com o motivo em linguagem simples. Suspeita de fraude não ganha explicação.
Modo avaliação
Modo avaliaçãoNas organizações de avaliação, como laboratório e pré-teste, a página mostra o código da sessão e a tentativa para o avaliador registrar cada apresentação.
Resultado para o avaliador
Resultado para o avaliadorNo modo avaliação, o fim da captura mostra o resultado. Em qualquer outra organização a página encerra sem revelar a decisão.
Resultado para o avaliador
Resultado para o avaliadorNo modo avaliação, o fim da captura mostra o resultado. Em qualquer outra organização a página encerra sem revelar a decisão.
Concluída
ConcluídaA página encerra sem dizer se aprovou. O resultado vai para o sistema da empresa, por webhook ou consulta, nunca para quem está diante da câmera.
01

Resumo executivo

O Biometrics responde a duas perguntas sobre quem está diante da câmera: está vivo? e é a mesma pessoa? — do documento, na abertura de conta, ou do cadastro facial, na autenticação.

O sistema da empresa abre uma sessão, manda a pessoa para a página de captura hospedada pelo bloco e recebe de volta uma decisão explicada: cada verificação com o score, o limiar usado e a versão do modelo, mais uma evidência assinada que qualquer um confere sem depender da Catalisa.

Por trás, um motor próprio, o face-engine, montado sobre modelos de pesos abertos e rodando na nossa infraestrutura: nenhuma imagem de rosto sai para terceiro. FaceTec, Unico e Serpro Datavalid estão declarados no mesmo contrato e entram como drivers quando houver credencial.

Sessões genuínas medidas59, nenhuma reprovada pelo liveness passivo
Match contra o cadastro facial feito pelo bloco0,95
Avaliação de uma sessão de celular~8 s
Imagens de rosto enviadas a terceirosnenhuma

Segurança em seis camadas, nível de garantia ENHANCED, em conformidade com os requisitos da ISO/IEC 30107-3

CamadaContra o quê
Liveness passivoFoto impressa, foto ou vídeo exibidos numa tela
Desafio ativo sorteadoVídeo gravado e reinjetado — gestos, ordem e duração mudam a cada sessão
Continuidade de identidadeTroca de pessoa durante a captura
Integridade da capturaCâmera virtual e troca de dispositivo entre tentativas, que vão para revisão
Bloqueio por titularTentativas em série contra o mesmo CPF
Evidência assinada em Ed25519Alteração do resultado depois da decisão

O Biometrics segue os requisitos e as recomendações das normas de mercado para biometria facial — ISO/IEC 30107-1 e 30107-3 na detecção de ataque, ISO/IEC 19795-1 nas métricas de desempenho, ICAO 9303 na leitura de documento e LGPD no tratamento do dado. Não é homologado nem certificado por laboratório: a certificação iBeta está no roadmap, e até lá a conformidade é declarada pela Catalisa e demonstrada pelo relatório de avaliação no formato da ISO/IEC 30107-3.

Em teste de injeção por câmera virtual, um vídeo genuíno de uma sessão aprovada, reinjetado numa sessão nova, foi reprovado pelo desafio sorteado. Onde a operação exigir certificação de laboratório, os drivers CERTIFIED entram no mesmo contrato, sem mudar a integração.


02

O problema

negócio

Abrir conta pelo celular exige saber que a pessoa é quem diz ser. O jeito comum de resolver é comparar uma selfie com a foto do documento — e uma selfie é só uma foto. Uma foto impressa do rosto de outra pessoa passa, e uma foto na tela do celular também.

Os provedores que resolvem isso bem, como FaceTec, iProov e Unico, cobram por verificação em contrato anual, e o SDK deles decide dentro do app. Três consequências aparecem depois:

  • A decisão é caixa-preta. Quando a verificação reprova um cliente bom, o time não sabe se foi luz, câmera, limiar ou modelo. Quando aprova um fraudador, também não.
  • A auditoria não tem o que ver. A LGPD trata biometria como dado sensível, e "o fornecedor aprovou" não é evidência de como a decisão foi tomada.
  • Trocar de fornecedor é reescrever. Cada SDK tem fluxo, formato de resposta e vocabulário de erro próprios, e a integração vira dívida no dia em que o contrato muda.

03

Proposta de valor

negócio
  • Prova de vida em camadas. Passiva, por modelo que distingue pele de papel e de tela, e ativa, com gestos sorteados em quantidade, ordem e duração a cada sessão.
  • Continuidade de identidade. O rosto do começo do vídeo tem que ser o do fim: trocar de pessoa no meio reprova.
  • Decisão explicável. Nove status em vez de dois. INCONCLUSIVE vai para revisão humana (LGPD art. 20); RETRY_ALLOWED é experiência de uso, porque foto escura não é fraude.
  • Evidência assinada. Hash do vídeo, do melhor quadro, da referência, dos checks e da política, assinado com chave Ed25519 da organização.
  • Garantia declarada. O driver diz o que entrega — BASIC, ENHANCED ou CERTIFIED — e a política exige um mínimo. O motor aberto é ENHANCED.
  • Página de captura pronta, com a cor, o logo e os textos da empresa, contagem de preparo antes de gravar e guia ao vivo que diz o que falta no gesto.
  • Tudo parametrizável pela empresa: quantos gestos, quais, quanto tempo cada um, limiares, bloqueio por titular, retenção. Sem deploy.

04

Casos de uso reais

negócio

Abertura de conta com documento

[Cenário ilustrativo] Fintech de crédito pessoal abre conta pelo celular e precisa de KYC com prova de vida.

A dor. A comparação da selfie com a foto do documento, sozinha, aprova uma foto impressa, e o fornecedor certificado custa mais por verificação do que a margem da primeira operação.

A solução com o bloco. Sessão ONBOARDING com a foto do documento como referência e enrollOnApprove: true. Na criação, o bloco lê a MRZ do passaporte ou o QR da CNH digital e recusa documento vencido se a política pedir. Depois avalia liveness e match e, ao aprovar, já grava o cadastro facial da pessoa.

O resultado. Validado em staging com passaporte e rosto reais: aprovado na primeira tentativa, match 0,702 contra o documento.

Confirmação de operação de alto valor

[Cenário ilustrativo] O mesmo cliente, meses depois, pede um saque acima do limite habitual.

A dor. SMS e senha provam posse de aparelho e conhecimento, não presença.

A solução com o bloco. Sessão AUTHENTICATION com referência ENROLLED_TEMPLATE. A comparação é contra o rosto que o próprio bloco capturou, não contra a foto do documento.

O resultado. Match 0,951 contra o cadastro feito pelo próprio bloco — o desenho é "documento uma vez, cadastro facial depois". E cinco falhas seguidas do mesmo CPF em uma hora bloqueiam o titular por 30 minutos.

Guia ao vivo durante a captura, com o selo de gesto confirmado
Guia ao vivo durante a captura, com o selo de gesto confirmado

Calibrar antes de contratar

[Cenário ilustrativo] Antes de decidir qual provedor contratar, é preciso saber como a própria base se comporta: quantos genuínos o sistema reprova, e por quê.

A solução com o bloco. Link de convite (POST /invites) compartilhado com voluntários. Cada pessoa rotula o que vai mostrar à câmera — ela mesma, uma foto impressa, uma tela, uma máscara — e o relatório cruza o rótulo com a decisão.

O resultado. Na medição em staging, nenhuma das 59 sessões genuínas foi reprovada pelo liveness; os ajustes ficaram no tempo e na leitura dos gestos, cada um com teste de regressão sobre as sessões reais gravadas.

Convite para voluntários, com o rótulo do que vai aparecer na câmera
Convite para voluntários, com o rótulo do que vai aparecer na câmera


05

Mercado e diferenciais

negócio

O mercado de biometria facial tem três faixas. Os provedores certificados — FaceTec, iProov — vendem prova de vida auditada por laboratório. As redes de identidade — Unico — vendem a base compartilhada de rostos e fraudes. E a fonte primária estatal — Serpro Datavalid — compara com a foto da base oficial, sem prova de vida.

O bloco é a camada que fala com todos, com um motor próprio que atende sem contrato de terceiro.

Integração direta com o SDKCom o Biometrics
Onde a decisão aconteceNo app, dentro do SDKNo servidor, com a política da empresa
Por que reprovouCódigo do fornecedorMotivo, score, limiar e modelo por verificação
Evidência para auditoriaLog da aplicaçãoHashes assinados em Ed25519, verificáveis fora da Catalisa
Revisão humanaA empresa montaStatus INCONCLUSIVE e evento próprio
Trocar de fornecedorReescrever a captura e o parserTrocar a configuração
Custo em volume baixoMínimo contratualMotor próprio, sem custo por consulta a terceiro

Quando escolher o concorrente. Quando a regulação ou um parceiro exigir certificação de laboratório, a FaceTec ou a iProov entram como driver CERTIFIED no próprio bloco, mantendo política, evidência e trilha. Para somar o sinal de fraude compartilhado entre instituições, a Unico entra da mesma forma.


06

Modelo de cobrança e ROI

negócio

Unidade: sessão de verificação avaliada. Precificação em definição.

Drivers de custo: sessões avaliadas, tentativas por sessão (o limite padrão é 3), o fornecedor quando não for o motor próprio, e a retenção de mídia, que por padrão é de 30 dias.

Com o motor próprio não há custo por consulta a terceiro: o custo é CPU. Uma sessão de celular leva cerca de 8 segundos de avaliação num nó de 4 vCPUs, e o motor escala horizontalmente por réplica.

Com um driver externo, o custo do fornecedor fica registrado por sessão. Em ambos os casos o consumo vai ao Billing no medidor biometrics.verification, com o id da sessão como chave de idempotência.


07

Arquitetura

flowchart TB
  TENANT["Sistema da empresa<br/>backend"]
  PESSOA["Pessoa<br/>navegador ou app"]

  subgraph BIO["Building Block Biometrics"]
    SESSAO["POST /sessions<br/>política e sorteio dos gestos"]
    PAGINA["Página de captura<br/>token de uso único"]
    SUBMIT["Submissão<br/>vídeo e telemetria"]
    DECISAO["Decisão<br/>checks, limiares, status"]
    EVID["Evidência<br/>hashes assinados Ed25519"]
  end

  ENGINE["face-engine<br/>motor próprio"]
  EXT["FaceTec, Unico, Serpro<br/>drivers declarados"]
  FS["File Storage<br/>vídeo e documento"]
  EVT["Webhooks Engine<br/>biometrics.session.completed"]

  TENANT --> SESSAO
  SESSAO -- "captureUrl" --> TENANT
  TENANT -- "link ou iframe" --> PESSOA
  PESSOA --> PAGINA
  PAGINA --> SUBMIT
  SUBMIT --> ENGINE
  SUBMIT -.-> EXT
  SUBMIT --> FS
  ENGINE --> DECISAO
  DECISAO --> EVID
  EVID --> EVT
  EVT --> TENANT

O motor. O face-engine é um serviço separado, em Python, que só o bloco alcança, com bearer próprio. Ele encadeia modelos de pesos abertos, todos publicados por terceiros com licença permissiva:

EtapaModeloLicença
Detecção de rostoYuNetMIT
Liveness passivoMiniFASNetApache-2.0
Pontos do rosto e gestosMediaPipe Face LandmarkerApache-2.0
Comparação de rostosFacenet512MIT
MRZ do passaporte e QR da CNH-eTesseract e zxing-cppApache-2.0

Os pesos são fixados por hash em models.lock.json: trocar um modelo muda a versão do motor, e a versão sai em todo check.

O que o bloco não faz, e quem faz

Não fazQuem faz
Guardar o vídeo e o documentoFile Storage
Entregar o resultado por HTTP ao sistema da empresaWebhooks Engine
Consultar CPF em bureauBureaus
Extrair campos do documento para o cadastroData Extraction
Dizer se o documento é autênticoDocumentoscopia — fora do escopo

08

Conceitos e modelo de dados

Glossário

TermoSignifica
SessãoUma verificação, do pedido à decisão. Aceita até maxAttempts tentativas
FluxoONBOARDING (com documento), AUTHENTICATION (com cadastro facial), ENROLLMENT (só cadastra), LIVENESS_ONLY e DEDUP (reservado)
ReferênciaContra o que o rosto é comparado: DOCUMENT_IMAGE, FILE, ENROLLED_TEMPLATE, PROVIDER_BASE
TemplateO cadastro facial: o vetor do rosto, cifrado com chave própria. Nunca sai do bloco
captureTokenToken curto, de uso único por tentativa, que é tudo o que a página de captura recebe
CheckUma verificação: quality.capture, liveness.passive, liveness.active, identity.continuity, match.1_1, capture.integrity
GarantiaBASIC, ENHANCED ou CERTIFIED. Declarada pelo driver, exigida pela política

Modelo de dados

Modelo PrismaPropósitoCampos-chave
BiometricsProviderConfigFornecedor por organizaçãoproviderType, credencial cifrada, appearance, allowedEmbedHosts
BiometricsPolicyPolítica por organizaçãolimiares, challenge, lockout, retention, minAssurance
BiometricsSessionA verificação e a decisãoflow, status, titular em HMAC, decision, evidência
BiometricsCaptureCada tentativahashes, fileId da mídia, telemetria, checks
BiometricsTemplateCadastro facialvetor cifrado, versão do modelo, titular em HMAC
BiometricsSigningKeyChave Ed25519 da organizaçãokeyId, chave pública, privada cifrada
BiometricsUsageConsumo medidosessão, fornecedor, custo

Status de uma sessão

StatusTerminalO que fazer
SESSION_OPENnãoAguardando a captura
PROCESSINGnãoAvaliando
APPROVEDsimSeguir
REJECTEDsimRecusar. Conta para o bloqueio do titular
INCONCLUSIVEsimRevisão humana (ou recusa, se a política pedir onInconclusive: REJECT)
RETRY_ALLOWEDnãoA página oferece nova tentativa com o motivo
EXPIREDsimAbrir nova sessão
CANCELLEDsimCancelada pela empresa
ERRORnãoFalha do motor. O único que merece nova tentativa automática

Os motivos da decisão formam um vocabulário fechado, com namespace, que a esteira da empresa pode automatizar: quality.too_dark, liveness.passive.failed, liveness.active.gesture_missing, liveness.active.timeout, identity.continuity_broken, match.below_threshold, match.gray_zone, capture.injection_suspected, capture.device_changed, policy.assurance_insufficient, subject.locked, entre outros — 27 no total.


09

Referência da API

Todas as rotas ficam sob /biometrics. As de /api/v1 exigem JWT com organizationId; as de captura e convite aceitam só o próprio token.

Sessões

MétodoRotaDescriçãoPermissão
POST/biometrics/api/v1/sessionsAbre a sessão e devolve o handoffBIOMETRICS_VERIFY
GET/biometrics/api/v1/sessionsListaBIOMETRICS_READ
GET/biometrics/api/v1/sessions/:idO envelope completoBIOMETRICS_READ
GET/biometrics/api/v1/sessions/:id/evidenceHashes e assinaturaBIOMETRICS_READ
GET/biometrics/api/v1/sessions/:id/evidence/verifyConfere a assinatura no servidorBIOMETRICS_READ
POST/biometrics/api/v1/sessions/:id/cancelCancelaBIOMETRICS_VERIFY
POST/biometrics/api/v1/sessions/:id/capturesSubmissão por SDK próprio, com o captureTokentoken

POST /biometrics/api/v1/sessions

Request

json
{
  "flow": "ONBOARDING",
  "purpose": "abertura de conta",
  "subjectRef": { "type": "CPF", "value": "529.982.247-25" },
  "reference": { "source": "DOCUMENT_IMAGE", "fileId": "7c1e…" },
  "enrollOnApprove": true
}
{
  "flow": "ONBOARDING",
  "purpose": "abertura de conta",
  "subjectRef": { "type": "CPF", "value": "529.982.247-25" },
  "reference": { "source": "DOCUMENT_IMAGE", "fileId": "7c1e…" },
  "enrollOnApprove": true
}
CampoTipoObrigatórioDescrição
flowenumsimONBOARDING, AUTHENTICATION, ENROLLMENT, LIVENESS_ONLY
purposestringsimFinalidade, de 3 a 120 caracteres. Vai para a trilha
legalBasisstringnãoBase legal declarada
subjectRefobjetonãoCPF do titular. Gravado como HMAC e máscara; ativa o bloqueio por titular
referenceobjetodepende do fluxoDOCUMENT_IMAGE ou FILE com fileId; ENROLLED_TEMPLATE com templateId
customerIduuidnãoVínculo com o Customers
providerConfigIduuidnãoForça um fornecedor; senão, vale o padrão da organização
appearanceobjetonãoCores, logo, textos e modo da página, só para esta sessão
metadataobjetonãoAté 10 rótulos livres. Nunca CPF
enrollOnApprovebooleanonãoGrava o cadastro facial ao aprovar. Só ONBOARDING e ENROLLMENT

Resposta 201

json
{
  "data": {
    "sessionId": "5b0e…",
    "flow": "ONBOARDING",
    "provider": "OPENSOURCE",
    "assurance": "ENHANCED",
    "status": "SESSION_OPEN",
    "attempt": 0,
    "maxAttempts": 3,
    "subjectRef": { "type": "CPF", "hmac": "…", "masked": "***.***.247-25" },
    "reference": {
      "source": "DOCUMENT_IMAGE",
      "portraitExtracted": true,
      "document": { "authenticity": "mrz-valid", "mrz": { "…": "mascarado" }, "qr": null }
    },
    "handoff": {
      "captureUrl": "https://biometrics.bb.stg.catalisa.app/biometrics/capture/eyJ…",
      "captureToken": "eyJ…",
      "captureMode": "RAW_FRAMES",
      "challenge": { "script": ["SMILE", "TURN_LEFT", "BLINK"], "timeoutMs": 22000, "slotsMs": [5200, 6100, 4800] },
      "expiresAt": "2026-09-18T15:00:00.000Z"
    },
    "expiresAt": "2026-09-18T15:00:00.000Z"
  }
}
{
  "data": {
    "sessionId": "5b0e…",
    "flow": "ONBOARDING",
    "provider": "OPENSOURCE",
    "assurance": "ENHANCED",
    "status": "SESSION_OPEN",
    "attempt": 0,
    "maxAttempts": 3,
    "subjectRef": { "type": "CPF", "hmac": "…", "masked": "***.***.247-25" },
    "reference": {
      "source": "DOCUMENT_IMAGE",
      "portraitExtracted": true,
      "document": { "authenticity": "mrz-valid", "mrz": { "…": "mascarado" }, "qr": null }
    },
    "handoff": {
      "captureUrl": "https://biometrics.bb.stg.catalisa.app/biometrics/capture/eyJ…",
      "captureToken": "eyJ…",
      "captureMode": "RAW_FRAMES",
      "challenge": { "script": ["SMILE", "TURN_LEFT", "BLINK"], "timeoutMs": 22000, "slotsMs": [5200, 6100, 4800] },
      "expiresAt": "2026-09-18T15:00:00.000Z"
    },
    "expiresAt": "2026-09-18T15:00:00.000Z"
  }
}

Perfil avaliado. Todo envelope do motor próprio traz evaluation: o perfil de avaliação ISO/IEC 30107-3 a que a sessão se refere, se ela rodou dentro dele (conforms) e, se não, o que saiu (violations). A garantia CERTIFIED vale só para sessão conforme a um perfil com laudo emitido. GET /policy e PUT /policy devolvem a mesma conformidade em meta.evaluationProfiles, e GET /catalog lista os perfis.

json
"evaluation": {
  "profileId": "pad-l1-2026-09",
  "label": "Candidato ISO/IEC 30107-3 Nível 1",
  "standard": "ISO/IEC 30107-3",
  "conforms": true,
  "certified": false,
  "violations": []
}
"evaluation": {
  "profileId": "pad-l1-2026-09",
  "label": "Candidato ISO/IEC 30107-3 Nível 1",
  "standard": "ISO/IEC 30107-3",
  "conforms": true,
  "certified": false,
  "violations": []
}

Depois da decisão, GET /sessions/:id traz decision com outcome, reasons e reviewRequired; checks[] com status, score, threshold, reasons e o engine (nome, modelo e versão) de cada verificação; evidence com os hashes e a assinatura; e enrollment.templateId quando enrollOnApprove gravou o cadastro.

Erros

StatusCódigoQuando
400VALIDATIONFluxo sem a referência que exige, CPF inválido, documento vencido com rejectExpiredDocument, referência sem rosto utilizável
400BAD_REQUESTGarantia do driver abaixo de minAssurance, ou capacidade que o driver não tem (provider.not_supported)
403FORBIDDENSem permissão, ou titular bloqueado (subject.locked)
404NOT_FOUNDCadastro facial ou arquivo de referência inexistente ou de outra organização
503SERVICE_UNAVAILABLEMotor indisponível

Captura e convite (públicas, por token)

MétodoRotaDescriçãoPermissão
GET/biometrics/capture/:tokenA página de capturatoken
GET/biometrics/capture/:token/stateEstado da sessão, para a páginatoken
GET/biometrics/capture/:token/logoO logo da empresatoken
GET/biometrics/capture/:token/guide/:nameArquivos do guia ao vivo, com hash fixotoken
POST/biometrics/capture/:token/submitO vídeo e a telemetriatoken
POST/biometrics/api/v1/invitesCria um link de conviteBIOMETRICS_ADMIN
GET/biometrics/invite/:tokenA página do convitetoken
POST/biometrics/invite/:token/startAbre uma sessão a partir do convitetoken

Tela inicial da captura, antes de abrir a câmera
Tela inicial da captura, antes de abrir a câmera

Cadastro facial

MétodoRotaDescriçãoPermissão
POST/biometrics/api/v1/enrollmentsCria o cadastro a partir de uma sessão aprovadaBIOMETRICS_ENROLL
GET/biometrics/api/v1/enrollments/:idMetadados do cadastro, nunca o vetorBIOMETRICS_READ
DELETE/biometrics/api/v1/enrollments/:idRevogaBIOMETRICS_ENROLL
POST/biometrics/api/v1/enrollments/rekeyRecifra os cadastros com a chave novaBIOMETRICS_ADMIN

Evidência e direitos do titular

MétodoRotaDescriçãoPermissão
GET/biometrics/api/v1/evidence-keysChaves públicas Ed25519 da organizaçãoBIOMETRICS_READ
POST/biometrics/api/v1/evidence-keys/rotateGira a chave de assinaturaBIOMETRICS_ADMIN
POST/biometrics/api/v1/subjects/reportO que existe sobre um CPF (LGPD art. 18)BIOMETRICS_ADMIN
POST/biometrics/api/v1/subjects/eraseApaga os dados biométricos de um CPFBIOMETRICS_ADMIN

O CPF vai no corpo, nunca na URL, para não aparecer em log de acesso.

Fornecedores, política e consumo

MétodoRotaDescriçãoPermissão
POST/biometrics/api/v1/providersCadastra o fornecedorBIOMETRICS_ADMIN
GET/biometrics/api/v1/providersListaBIOMETRICS_READ
GET/biometrics/api/v1/providers/:idDetalheBIOMETRICS_READ
PATCH/biometrics/api/v1/providers/:idAtualiza, inclusive a aparênciaBIOMETRICS_ADMIN
DELETE/biometrics/api/v1/providers/:idRemoveBIOMETRICS_ADMIN
POST/biometrics/api/v1/providers/:id/test-connectionTesta o motor ou a credencialBIOMETRICS_ADMIN
GET/biometrics/api/v1/policyA política da organizaçãoBIOMETRICS_READ
PUT/biometrics/api/v1/policyTroca a políticaBIOMETRICS_ADMIN
GET/biometrics/api/v1/catalogDrivers, capacidades e garantia de cada umBIOMETRICS_READ
GET/biometrics/api/v1/usageConsumo por períodoBIOMETRICS_READ

10

Início rápido

1. Autenticar

bash
TOKEN=$(curl -s -X POST https://iam.bb.stg.catalisa.app/iam/api/v1/users/login \
  -H "Content-Type: application/json" \
  -d '{"email":"SEU-EMAIL","password":"SUA-SENHA","organizationId":"SUA-ORG"}' \
  | jq -r .accessToken)
BIO=https://biometrics.bb.stg.catalisa.app/biometrics/api/v1
TOKEN=$(curl -s -X POST https://iam.bb.stg.catalisa.app/iam/api/v1/users/login \
  -H "Content-Type: application/json" \
  -d '{"email":"SEU-EMAIL","password":"SUA-SENHA","organizationId":"SUA-ORG"}' \
  | jq -r .accessToken)
BIO=https://biometrics.bb.stg.catalisa.app/biometrics/api/v1

2. Cadastrar o motor próprio como padrão

bash
curl -X POST $BIO/providers \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{ "name": "motor-proprio", "providerType": "OPENSOURCE", "isDefault": true }'
curl -X POST $BIO/providers \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{ "name": "motor-proprio", "providerType": "OPENSOURCE", "isDefault": true }'

3. Abrir uma sessão de prova de vida

bash
curl -s -X POST $BIO/sessions \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{ "flow": "LIVENESS_ONLY", "purpose": "teste do inicio rapido" }' \
  | jq '.data | {sessionId, captureUrl: .handoff.captureUrl}'
curl -s -X POST $BIO/sessions \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{ "flow": "LIVENESS_ONLY", "purpose": "teste do inicio rapido" }' \
  | jq '.data | {sessionId, captureUrl: .handoff.captureUrl}'

4. Abrir o captureUrl no celular e seguir a página. Ela pede a câmera, mostra o primeiro gesto com uma contagem de 2,5 s antes de gravar, guia os gestos sorteados e envia sozinha.

Contagem de preparo, com o primeiro gesto na tela antes de gravar
Contagem de preparo, com o primeiro gesto na tela antes de gravar

5. Ler a decisão

bash
curl -s $BIO/sessions/$SESSION_ID -H "Authorization: Bearer $TOKEN" \
  | jq '.data | {status, decision, checks: [.checks[] | {kind, status, score, threshold}]}'
curl -s $BIO/sessions/$SESSION_ID -H "Authorization: Bearer $TOKEN" \
  | jq '.data | {status, decision, checks: [.checks[] | {kind, status, score, threshold}]}'
json
{
  "status": "APPROVED",
  "decision": { "outcome": "APPROVED", "reasons": [], "reviewRequired": false },
  "checks": [
    { "kind": "quality.capture", "status": "PASSED", "score": 0.91, "threshold": 0.6 },
    { "kind": "liveness.passive", "status": "PASSED", "score": 0.97, "threshold": 0.8 },
    { "kind": "liveness.active", "status": "PASSED", "score": 1, "threshold": 1 },
    { "kind": "identity.continuity", "status": "PASSED", "score": 0.95, "threshold": 0.7 }
  ]
}
{
  "status": "APPROVED",
  "decision": { "outcome": "APPROVED", "reasons": [], "reviewRequired": false },
  "checks": [
    { "kind": "quality.capture", "status": "PASSED", "score": 0.91, "threshold": 0.6 },
    { "kind": "liveness.passive", "status": "PASSED", "score": 0.97, "threshold": 0.8 },
    { "kind": "liveness.active", "status": "PASSED", "score": 1, "threshold": 1 },
    { "kind": "identity.continuity", "status": "PASSED", "score": 0.95, "threshold": 0.7 }
  ]
}

Tela de conclusão, que não revela o resultado
Tela de conclusão, que não revela o resultado


11

Receitas

Mais tempo para cada gesto. Público mais velho ou celular mais lento pedem janela maior. A política aceita o intervalo sorteado por gesto e o teto do vídeo:

bash
curl -X PUT $BIO/policy -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{ "challenge": { "gestures": 2, "gesturesMax": 3, "slotMinMs": 5500, "slotMaxMs": 7500, "timeoutMs": 24000 } }'
curl -X PUT $BIO/policy -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{ "challenge": { "gestures": 2, "gesturesMax": 3, "slotMinMs": 5500, "slotMaxMs": 7500, "timeoutMs": 24000 } }'

O vídeo inteiro não passa de 24 segundos — é o limite do motor. Menos gestos com mais tempo costumam reprovar menos gente do que mais gestos com pouco tempo.

O próximo gesto é anunciado antes de a janela começar
O próximo gesto é anunciado antes de a janela começar

Escolher os gestos. challenge.pool restringe o catálogo; o padrão tem sete (virar à esquerda e à direita, piscar, sorrir, abrir a boca, acenar com a cabeça, erguer as sobrancelhas). approachEnabled: true inclui aproximar o rosto da câmera, que funciona bem no celular e mal no notebook.

Página com a cara da empresa. appearance no fornecedor vale para todas as sessões; na sessão, só para ela. Cores, raio dos cantos, fonte de uma lista fechada, logo por fileId, modo claro, escuro ou automático, textos por idioma e redirectUrl. Nada vira CSS ou JavaScript livre.

A tela de captura no modo escuro, com a dica do gesto
A tela de captura no modo escuro, com a dica do gesto

Embutir em iframe. Liste a origem em allowedEmbedHosts do fornecedor e use allow="camera". A página avisa o andamento por postMessage — nunca o resultado:

eventQuando
readyPágina carregada, sessão capturável
capturingCâmera liberada, gravação começou
step:<GESTO>Cada passo do roteiro, com index, total e durationMs
submittedVídeo enviado
retryNova tentativa; a página recarrega sozinha
doneSessão encerrada — leia o envelope pelo servidor
expiredSessão expirada
errorCâmera negada ou motor instável, com reason
html
<iframe id="bio" src="CAPTURE_URL" allow="camera"></iframe>
<script>
  window.addEventListener('message', (e) => {
    if (e.origin !== 'https://biometrics.bb.stg.catalisa.app' || e.data?.source !== 'catalisa-biometrics') return
    if (e.data.event === 'done') consultarSessaoNoBackend()
  })
</script>
<iframe id="bio" src="CAPTURE_URL" allow="camera"></iframe>
<script>
  window.addEventListener('message', (e) => {
    if (e.origin !== 'https://biometrics.bb.stg.catalisa.app' || e.data?.source !== 'catalisa-biometrics') return
    if (e.data.event === 'done') consultarSessaoNoBackend()
  })
</script>

Verificar a evidência sem a Catalisa. Baixe a chave pública em GET /evidence-keys e confira a assinatura de GET /sessions/:id/evidence. A mensagem assinada é sessionId|attempt|bundleHash|signedAt, e o bundleHash já resume checks, artefatos, política e roteiro — basta openssl pkeyutl -verify com a chave pública.

Modo avaliação para laboratório e pré-teste. Numa organização listada em BIOMETRICS_EVALUATION_ORG_IDS, a página mostra um selo com a sessão e a tentativa e, ao fim, o resultado com os motivos, para o avaliador registrar cada apresentação. Fora dessas organizações a página nunca mostra o resultado.

Cartão de resultado do modo avaliação
Cartão de resultado do modo avaliação

Medir antes de ligar em produção. POST /invites gera um link válido por até 90 dias para voluntários. A página rotula o que a pessoa mostra à câmera — ela mesma, foto impressa, foto numa tela, vídeo numa tela ou máscara, as espécies da ISO/IEC 30107-3 — e o relatório devolve APCER por espécie, BPCER e as taxas de não resposta, no vocabulário do laudo.

Nova tentativa, com o motivo em linguagem simples
Nova tentativa, com o motivo em linguagem simples


12

Integração com outros building blocks

BlocoComo se encaixa
File StorageGuarda o vídeo do desafio, o melhor quadro e o documento de referência, pela fachada IFileStorageFacade. Falha de armazenamento não perde a verificação: o hash fica
BillingSessão avaliada vira UsageEvent no medidor biometrics.verification, pela fachada IBillingFacade
Webhooks EngineEntrega os eventos abaixo a quem assinou
CustomerscustomerId na sessão e no cadastro facial liga a verificação ao cliente
IAMEscopo por organização e as permissões BIOMETRICS_*

Eventos publicados

EventoQuando
biometrics.session.createdSessão aberta
biometrics.session.completedDecisão tomada, com o status
biometrics.session.review_requiredINCONCLUSIVE: alguém precisa olhar
biometrics.session.expiredSessão venceu sem decisão
biometrics.subject.lockedCriação recusada por excesso de falhas do titular
biometrics.subject.erasedDados de um titular apagados a pedido
biometrics.enrollment.created e .revokedCadastro facial gravado ou revogado

13

Configuração e operação

Variáveis de ambiente

VariávelObrigatóriaPadrãoDescrição
BIOMETRICS_CREDENTIAL_MASTER_KEYsim64 hex. Cifra a credencial do fornecedor e a chave de assinatura
BIOMETRICS_TEMPLATE_MASTER_KEYsim64 hex, diferente da anterior. Cifra o cadastro facial
BIOMETRICS_TEMPLATE_MASTER_KEY_PREVIOUSnãoA chave antiga durante a rotação, até o rekey terminar
BIOMETRICS_ENGINE_URLnãohttp://face-engine:8000Endereço interno do motor
BIOMETRICS_ENGINE_TOKENsim com o motorBearer compartilhado com o motor
BIOMETRICS_PUBLIC_URLsimBase pública do bloco, usada para montar o captureUrl
BIOMETRICS_EXPIRE_SCHEDULER_ENABLEDnãotrueSessão vencida vira EXPIRED a cada minuto
BIOMETRICS_RETENTION_PURGE_ENABLEDnãofalsePurga de mídia por retention.mediaDays. Desligada por padrão: apagar é irreversível
BIOMETRICS_RETENTION_PURGE_INTERVAL_HOURSnão24Cadência da purga
BIOMETRICS_USAGE_CONSUMER_ENABLEDnãofalseLiga o faturamento
BIOMETRICS_EVALUATION_ORG_IDSnãovazioOrganizações de avaliação (laboratório, pré-teste), separadas por vírgula. Só nelas a página de captura mostra o resultado

As duas master keys são separadas de propósito: a da credencial gira com o contrato do fornecedor; a do cadastro facial exige recifrar a base inteira.

Política por organização, sem deploy (PUT /policy)

ChavePadrãoPara quê
minAssuranceENHANCEDGarantia mínima do driver. O MOCK é BASIC e é recusado
thresholds.matchrecusa < 0,55, aprova ≥ 0,70Entre os dois é zona cinzenta, INCONCLUSIVE
thresholds.livenessPassiverecusa < 0,40, aprova ≥ 0,80Liveness passivo
maxAttempts3Tentativas por sessão
sessionTtlMinutes15Validade do link, até 60
challenge3 gestos, 4,5 a 6,5 s cada, até 22 sQuantidade, janelas e catálogo
documenttudo desligadoRecusar documento vencido; exigir MRZ ou QR válido
lockout5 falhas em 60 min → 30 minBloqueio por titular
retentionmídia por 30 diasE validade do cadastro facial, se houver
onInconclusiveREVIEWOu REJECT
allowedCaptureChannelsHOSTED, IFRAME, SDKPor onde a câmera pode abrir

Observabilidade. O bloco publica métricas OpenTelemetry de baixa cardinalidade: sessões por fluxo e resultado, checks por tipo, histograma de score, motivos da decisão, duração da avaliação e de cada etapa do motor, e criações recusadas. Nenhum rótulo carrega CPF, sessão ou organização.

O motor em operação. O face-engine sobe com os pesos embutidos na imagem e aquece os modelos antes de se declarar saudável. Uma sessão de celular leva ~8 s em 4 vCPUs; a análise dos pontos do rosto roda em paralelo por quadro.


14

Segurança e compliance

Biometria é dado pessoal sensível (LGPD art. 5º, II). O desenho parte disso:

TemaComo
Finalidadepurpose obrigatório em toda sessão, com legalBasis opcional, gravados na trilha
TitularCPF em HMAC e máscara, nunca em claro
Cadastro facialCifrado com chave própria, nunca devolvido pela API, com rotação por rekey
MídiaRetenção configurável; a purga apaga o vídeo e preserva o hash
Direitos do titularsubjects/report diz o que existe; subjects/erase apaga sessões, mídia e cadastros de um CPF
Decisão automatizadaINCONCLUSIVE vai para revisão humana (art. 20)

Quem está diante da câmera não carrega credencial. A página recebe um captureToken de escopo único e uso único por tentativa, e só as rotas de captura o aceitam. A página roda com CSP por nonce; os arquivos do guia ao vivo são servidos pelo próprio bloco com hash fixo, sem CDN.

A página não diz o resultado. Nem aprovado, nem reprovado: quem decide o que dizer à pessoa é a empresa, depois de ler o envelope pelo servidor. Isso impede que um fraudador use a página como oráculo para ajustar o ataque.

Contra injeção de vídeo. Os gestos são sorteados em quantidade, ordem e duração por sessão, e a janela de cada um é conferida no vídeo. Na medição, um vídeo genuíno aprovado, reinjetado por câmera virtual, passou no liveness passivo e na continuidade — é rosto real — e foi reprovado pela janela sorteada. Troca de dispositivo entre tentativas vira INCONCLUSIVE.

Contra força bruta. O mesmo CPF com 5 sessões reprovadas ou inconclusivas em 60 minutos fica bloqueado por 30. Os três números são da política.

Evidência assinada. Cada organização tem uma chave Ed25519 própria, criada no primeiro uso, com a privada cifrada. A pública é publicada para que a auditoria verifique sem depender da Catalisa.

Conformidade com normas

O bloco é desenvolvido em conformidade com os requisitos e as recomendações das normas abaixo. Conformidade declarada pela Catalisa — sem homologação nem certificação de terceiro.

NormaOnde o bloco aplica
ISO/IEC 30107-1 e 30107-3Detecção de ataque de apresentação (PAD): famílias de ataque, métricas APCER e BPCER e protocolo de avaliação
ISO/IEC 19795-1Métricas de desempenho do match, FMR e FNMR
ICAO Doc 9303Leitura da MRZ do passaporte, com validação dos dígitos verificadores
LGPD — arts. 5º II, 11, 18 e 20Dado sensível, base legal, direitos do titular e revisão de decisão automatizada
Circular BCB nº 3.978/2020Apoia a identificação e a qualificação de clientes da política de PLD/FT
RFC 8032 — Ed25519Assinatura da evidência
NIST SP 800-38D — AES-256-GCMCifra do cadastro facial e das credenciais
RFC 7519 — JWTToken de captura de uso único
W3C CSP Level 3 e Permissions PolicyIsolamento da página de captura e acesso à câmera
OpenTelemetryMétricas de operação

Certificações no roadmap (nenhuma emitida até aqui)

CertificaçãoEscopo
iBeta ISO/IEC 30107-3 Nível 1Ataques com foto impressa, tela, vídeo e máscara de papel
iBeta ISO/IEC 30107-3 Nível 2Máscaras 3D de látex, silicone e resina
FIDO Alliance Face VerificationDesempenho do match, PAD e injeção, com laboratório credenciado
CEN/TS 18099Detecção de injeção de dados biométricos, como câmera virtual e vídeo sintético

15

Limitações conhecidas

EscopoComo o bloco trata
Autenticidade física do documentoFora do escopo. O bloco lê MRZ e QR para validade e consistência; documentoscopia é de provedor especializado
Reconhecimento 1:NFora do escopo. O fluxo DEDUP está reservado no contrato
FaceTec, Unico e Serpro DatavalidDeclarados no catálogo; ativados com a credencial do contrato de cada um
Certificação de laboratórioEntregue pelos drivers CERTIFIED
Duração do vídeoAté 24 segundos por tentativa
Dispositivo recomendadoCelular, pela câmera e pela luz. O gesto de aproximar o rosto (APPROACH) é indicado só para celular
Atestação de dispositivoRoadmap: SDK nativo com atestação na origem da captura

16

Perguntas frequentes

Usa inteligência artificial de terceiros?

Usa modelos de pesos abertos publicados por terceiros — YuNet, MiniFASNet, MediaPipe, Facenet512 —, rodando na nossa infraestrutura. Nenhuma imagem sai para serviço externo. Os pesos são fixados por hash e a versão aparece em cada check.

Substitui a FaceTec?

O motor próprio atende sem contrato de terceiro nos fluxos em que o nível ENHANCED basta. Onde a certificação for exigida, a FaceTec entra como driver e a integração não muda.

Por que a página não mostra se aprovou?

Porque a página está nas mãos de quem está diante da câmera, que pode ser um fraudador. Mostrar o resultado transforma a página num oráculo para ajustar o ataque. A empresa lê o envelope pelo servidor e decide o que dizer.

A empresa pode configurar quanto tempo cada gesto dura?

Pode, pela política da organização, sem deploy: quantidade de gestos, janela mínima e máxima de cada um, o tempo total até 24 segundos e quais gestos entram no sorteio.

Qual a diferença entre REJECTED e INCONCLUSIVE?

REJECTED é o sistema seguro de que não deve aprovar. INCONCLUSIVE é zona cinzenta — match entre os limiares, sinal heurístico de câmera virtual, troca de dispositivo — e vai para revisão humana, como pede a LGPD para decisão automatizada com efeito relevante.

Precisa pedir o documento em toda verificação?

Não. O documento entra uma vez, no ONBOARDING com enrollOnApprove. Depois, a autenticação compara com o cadastro facial, que chega a 0,95 de match.

Funciona no navegador ou precisa de app?

No navegador, sem instalar nada. Antes de gravar, a página mostra o primeiro gesto com uma contagem de 2,5 s. O guia ao vivo roda no próprio navegador e se desliga sozinho em conexão lenta ou com economia de dados; a captura funciona sem ele. Para app nativo, a rota POST /sessions/:id/captures aceita a submissão de um SDK próprio com o mesmo captureToken.