Pular para o conteúdo principal

Integração ponta a ponta

Tudo o que segue é código completo, com tratamento de erro, para copiar e rodar. Em três formas: a chamada HTTP crua (serve para qualquer stack), TypeScript/JavaScript e Python. Escolha a sua e ignore as outras duas: elas fazem exatamente a mesma coisa. Antes de começar, confira os passos 01 a 05 da tabela do início: eles acontecem no painel, uma vez, e nenhum deles é opcional. Sem o e-mail confirmado a criação de sessão responde 403; sem a origem registrada o widget não sobe. Prefere tipos a copiar exemplo? O contrato inteiro existe como spec OpenAPI 3.1 e vira tipos TypeScript com uma linha de npx openapi-typescript. PASSO 06 · CRIE A SESSÃO NO SEU BACKEND Uma chamada, um campo obrigatório (flow_id). Mande o reference_id (o id do usuário no seu sistema): ele volta igual no webhook e é o que liga o resultado ao seu cadastro. Um UUID serve; CPF, telefone ou e-mail nunca. A versão curl está em Autenticação.
Você não gerencia chave de idempotência. Não existe header aqui: o reference_id (obrigatório) é a chave, do nosso lado. Um retry do seu backend (rede ruim, timeout, deploy no meio) com o mesmo reference_id recebe a mesma sessão, com o header Idempotent-Replay: true, em vez de criar uma segunda (e sessão duplicada seria cobrança duplicada). A selagem dura o que a sessão dura, 15 minutos: quando ela vence, o mesmo reference_id abre uma sessão nova, que é o que a pessoa precisa para tentar de novo.
TypeScript / Node · Criar a sessão · no seu servidor
Python · Criar a sessão · no seu servidor
PASSO 07 · MONTE O WIDGET NA PÁGINA O exemplo abaixo é a fronteira inteira do produto num arquivo: o servidor cria a sessão com a chave secreta e entrega ao navegador só o id da sessão. Ele também traz os cabeçalhos que a câmera exige, que é a segunda causa mais comum de widget que carrega e trava. TypeScript / Node · A página que o seu usuário abre · no seu servidor
O evento do navegador serve para a tela, nunca para liberar nada. O widget dispara unifokal:state a cada transição e unifokal:done no fim, e é assim que um aplicativo que abre a verificação num webview sabe a hora de fechar a tela. O contrato inteiro (o payload, os canais e o que o evento nunca carrega) está em O Widget, que é a página dona do assunto. O que não existe é rota de consulta do resultado com a sk_: o desfecho oficial chega ao seu backend pelo webhook, você grava, e o seu front pergunta ao seu backend. Resultado que passa pelo navegador é resultado que o usuário pode forjar, e por isso a decisão não passa por lá.
PASSO 08 · RECEBA O WEBHOOK E VALIDE A ASSINATURA Esta é a parte que mais sai errada e a que custa mais caro. A URL do seu webhook é alcançável por qualquer um na internet: sem validação, quem descobrir o endereço forja um POST com "status": "approved" e o seu sistema aprova quem não deveria. Os três exemplos abaixo validam antes de ler o corpo, comparam em tempo constante e fecham a janela de repetição. A explicação de cada linha está em Valide a assinatura do webhook. TypeScript / Node · Receber e validar o webhook · no seu servidor
Python · Receber e validar o webhook · no seu servidor
E o mesmo cálculo no terminal, para quando a pergunta for “o problema é o meu segredo ou o meu código?”: curl · Conferir uma assinatura na mão · no terminal

Os desfechos, e o que fazer com cada um

O campo status tem seis valores, e só seis. Trate os seis: um default que aprova é a forma mais rápida de transformar uma recusa nossa num cadastro liberado no seu sistema. Um módulo que depende de consulta paga também pode ficar pending por causa da conta, e não da fonte: com reason: "account_usage_limit" no check, o limite de uso da conta foi atingido. O check vem com data: null, fica fora da cobrança, e o limite volta às 00:00 UTC. Ao lado do status vêm recommendation (approve, review ou decline) e risk_level (low, medium ou high). Os dois existem para você apertar a sua regra além da nossa: mandar para análise humana todo approved com risk_level alto acima de um certo valor de transação, por exemplo. O que não recomendamos é ler só o score: ele é uma leitura informativa da evidência, comparável dentro de uma política, e a política pode mudar. O desfecho é o status. TypeScript / Node · Tratar os sete desfechos · no seu servidor
Python · Tratar os sete desfechos · no seu servidor
QUANDO O SEU SISTEMA FICA FORA DO AR Nada se perde. Liste o que não foi entregue e redispare: você recebe o corpo exato que teria recebido, com assinatura nova. curl · Recuperar entregas que falharam · no terminal

Receitas por jornada

Cada jornada da página de soluções vira um flow de sandbox com três chamadas, sempre nesta ordem. Primeiro o webhook de sandbox: flow sem webhook do mesmo ambiente é recusado com webhook_required. Depois o flow, com os módulos da jornada que estão à venda hoje. Por fim a sessão, com o reference_id obrigatório. As duas primeiras chamadas são as que o painel faz quando você cria o webhook e o flow na tela, e usam a sessão do painel. A terceira roda no seu servidor, com a chave secreta de sandbox. Troque cada valor entre < e > pelo seu, ou pelo id devolvido na chamada anterior. O segredo do webhook tem pelo menos 32 caracteres.

KYC de pessoa

A jornada completa, com o porquê de cada passo, está em /solucoes/kyc-pessoa. 1. POST Cadastre o webhook de sandbox com a sessão do painel
2. POST Crie o flow da jornada com a sessão do painel
3. POST Crie a sessão de verificação no seu servidor

KYB de empresa

A jornada completa, com o porquê de cada passo, está em /solucoes/kyb-empresa. Ficam fora do flow, por estarem “Em breve”: Certidão trabalhista (CNDT), Inscrição estadual. 1. POST Cadastre o webhook de sandbox com a sessão do painel
2. POST Crie o flow da jornada com a sessão do painel
3. POST Crie a sessão de verificação no seu servidor

Antifraude transacional

A jornada completa, com o porquê de cada passo, está em /solucoes/antifraude-transacional. Ficam fora do flow, por estarem “Em breve”: Sinais do aparelho. Ficam num flow próprio, porque este flow aceita só a decisão do pagamento: Reautenticação facial, Dispositivo PIX. 1. POST Cadastre o webhook de sandbox com a sessão do painel
2. POST Crie o flow da jornada com a sessão do painel
3. POST Crie a sessão de verificação no seu servidor

Background check

A jornada completa, com o porquê de cada passo, está em /solucoes/background-check. Ficam fora do flow, por estarem “Em breve”: Antecedentes Estaduais, Processos Judiciais, Antecedentes Criminais, Mandados e Interpol. 1. POST Cadastre o webhook de sandbox com a sessão do painel
2. POST Crie o flow da jornada com a sessão do painel
3. POST Crie a sessão de verificação no seu servidor

Humano verificado: qual peça para qual caso

A prova de humano verificado tira a decisão do canal em que o pedido chegou e a entrega ao titular, com a credencial dele, e devolve a prova disso com o mínimo de dado pessoal. Ela não é um módulo só: são peças que você liga no flow, cada uma respondendo a uma pergunta. As cinco perguntas, e a peça que responde cada uma.
  1. Há uma pessoa viva diante da câmera agora? A prova de vida, módulo liveness (documento, face match e prova de vida).
  2. É a mesma pessoa que você aprovou antes? A reautenticação facial, módulo face_reauth, contra a matrícula da própria conta (Reautenticação facial). O resultado é semelhança com a matrícula, e se lê como confirmação de que é a mesma pessoa.
  3. É a credencial que ela vinculou à conta? A passkey do titular, vinculada no onboarding com passkey_bind e conferida pelo módulo passkey (Aprovação de ato com passkey).
  4. Ela aprova este ato, por um canal que o pedido não controla? O bloco act na sessão, o step_up do gate transacional e o link de confirmação fora de banda, que você manda pelo canal que já tinha cadastrado.
  5. Como provar isso a um terceiro sem entregar a identidade? O atestado de pessoa verificada, que a plataforma confere e apresenta em parte.
Qual embalagem para qual caso. O que volta. Tudo chega no webhook assinado. O bloco do módulo passkey em check_details diz qual chave aprovou (passkey_id), como ela foi vinculada (bound_by e assurance), se ela é sincronizável (backup_eligible e backup_state), se houve verificação do usuário no aparelho (user_verified), qual ato ela assinou (act_digest e act_kind) e a evidência conferível sem nos consultar. Na confirmação, data.purpose e data.act casam a resposta com o seu pedido. No atestado, data.attestation traz o token assinado. Os eventos próprios são passkey.bound, passkey.revoked e act.rejected, este quando o titular diz que não reconhece o pedido. Os limites que mudam a sua decisão.
  • O atestado não é anônimo perante a emissora: a UNIFOKAL, que emite, consegue ligar o atestado à verificação que o originou. O que ele garante é que dois serviços que recebem atestados não ligam as contas entre si por meio dele.
  • A passkey sincronizada não fica num aparelho só: ela acompanha o titular nos aparelhos em que ele usa o mesmo gerenciador de senhas. Quando o seu caso exige um aparelho só, ligue no flow a opção “Só credencial de um aparelho”, e a chave sincronizável é recusada com passkey_not_device_bound. Sem a opção, leia backup_eligible no webhook.
  • Só a chave vinculada com rosto e prova de vida (assurance igual a identity) aprova ato e confirma pedido. A vinculada só com prova de vida (presence) prova continuidade da mesma pessoa, e nunca serve de fator.
  • O link de confirmação é transporte, não fator: quem o abre ainda precisa da passkey ou do rosto do titular. Mande-o sempre pelo canal que você já tinha, nunca pela conversa em que o pedido chegou.
Antes de ir para produção, integre e teste o fluxo inteiro no sandbox, com o mesmo webhook que vai receber estes blocos.