Instalação
1. Obtenha suas chaves
Entre no seu painel da Veridia e abra a seção API keys. Você precisa de duas chaves, de duas famílias diferentes:
- Publicável —
qv_pubt_...(teste) ouqv_pub_...(produção). Vai na página. Este passo só precisa dela. - Secreta —
qv_sect_...(teste) ouqv_sec_...(produção). Fica no seu servidor. Você vai precisar dela no passo 3 para ler o veredito.
Chaves publicáveis podem ser expostas com segurança no HTML do lado do cliente. Elas identificam seu tenant e podem iniciar e enviar verificações, mas GET /v1/verify/{id} as recusa, então elas nunca conseguem ler um veredito.
Uma chave pode carregar uma lista de allowed origins, comparada contra o hostname puro (seuapp.com, curingas como *.seuapp.com são aceitos — não https://seuapp.com). O painel ainda não expõe esse campo, então toda chave é criada com uma lista vazia, e uma lista vazia permite todas as origens. Não há nada para configurar aqui, incluindo para localhost. Encare isso como uma forma de delimitar onde seu widget roda mais adiante, não como um controle de acesso.
2. Incorpore o widget
Insira duas tags de script e o custom element em qualquer página:
<!-- 1. Carregue o face-api.js (UMD) e depois o bundle do widget (módulo ESM).
A ordem importa: o widget lê window.faceapi na inicialização. -->
<script src="https://widget.xxuxe.online/face-api.js"></script>
<script type="module" src="https://widget.xxuxe.online/veridia-widget.min.js"></script>
<!-- 2. Insira o widget -->
<veridia-widget
publishable-key="qv_pubt_SUA_CHAVE_AQUI"
user-ref="customer-12345"
country="PY"
document-type="dni"
locale="es">
</veridia-widget>
<!-- 3. Escute os eventos -->
<script>
document.querySelector('veridia-widget')
.addEventListener('veridia:complete', (e) => {
// e.detail é { verificationId, status } — o veredito NÃO está aqui.
console.log('verification:', e.detail.verificationId);
});
</script>
Essa é a integração completa. Abra a página em um celular ou notebook com câmera, clique em "Start" e você tem um fluxo de captura biométrica funcionando.
veridia:complete entrega o verificationId e nada mais — não o seu user-ref. GET /v1/verify/{id} também não. Só o webhook devolve o userRef.
Então, quando o evento disparar, grave verificationId → seu id de usuário no seu próprio banco de dados imediatamente. Se você pular isso, um veredito que chegue depois por polling não terá como dizer a quem ele pertence.
Atributos de configuração
Dez atributos, todos opcionais exceto publishable-key.
| Atributo | Obrigatório | Padrão | Descrição |
|---|---|---|---|
publishable-key | Sim | — | Sua chave qv_pubt_* ou qv_pub_* do painel |
api-base | Não | https://api.xxuxe.online | Sobrescreve o endpoint da API. Você quase nunca precisa disso |
user-ref | Não | — | Seu próprio identificador de usuário (máx. 128 caracteres). Devolvido apenas em webhooks |
country | Não | — | Código de país ISO 3166-1 alpha-2 (PY, BR, MX) — melhora a precisão do OCR. É normalizado para maiúsculas automaticamente |
document-type | Não | — | Um entre: dni, passport, drivers_license, national_id, other |
submitted-full-name | Não | — | O nome completo do usuário, comparado por similaridade com o documento (máx. 255 caracteres). Gera a pontuação name_match |
require-doc-back | Não | depende — veja abaixo | Se o verso do documento deve ser capturado |
locale | Não | locale do navegador, depois en | Idioma da interface: en, es ou pt |
accent-color | Não | #0f172a | Cor de destaque para botões e estados ativos. Qualquer cor CSS válida, não só hexadecimal |
active-liveness | Não | false | Defina "true" para habilitar o desafio de prova de vida (liveness) ativa verificada pelo servidor |
require-doc-back é true por padrão para tudo, exceto passaportes
Este é o atributo com maior chance de te surpreender, então leia a regra com atenção.
Se você não definir o atributo de forma alguma, o widget calcula o padrão como document-type !== 'passport'. Um passaporte recebe duas capturas (frente + selfie); todo o resto — incluindo o caso em que você não define nenhum document-type — recebe três (frente + verso + selfie).
E, quando você define, apenas dois valores literais o desligam: "false" e "0". Qualquer outra string, incluindo "no", "off" e o atributo vazio require-doc-back="", resolve para true.
<!-- 3 capturas: frente, verso, selfie -->
<veridia-widget publishable-key="..." document-type="dni"></veridia-widget>
<!-- 2 capturas: frente, selfie -->
<veridia-widget publishable-key="..." document-type="dni" require-doc-back="false"></veridia-widget>
<!-- 2 capturas: passaportes não têm verso -->
<veridia-widget publishable-key="..." document-type="passport"></veridia-widget>
Desenhe seu funil em cima da contagem real antes de construir as telas em volta dela.
active-liveness vem desligado
Definir active-liveness="true" ativa o desafio de prova de vida (liveness) verificado pelo servidor: a API emite um plano de desafio em /v1/verify/init e revela os passos um a um, de modo que um vídeo pré-gravado ou injetado não consegue satisfazê-lo.
Ele vem desligado por padrão, o que significa que uma integração que nunca menciona o atributo roda sem ele. Se o seu modelo de risco inclui alguém injetando frames no navegador em vez de mostrar um rosto real, ligue-o.
Note que ele adiciona etapas de captura e, portanto, tempo ao fluxo do usuário, e faz a verificação emitir cerca de vinte uploads em vez de três — relevante para o limite de taxa por IP se muitos dos seus usuários compartilham um mesmo NAT.
Configurando programaticamente
Em vez de atributos, você pode atribuir um objeto de configuração:
const widget = document.querySelector('veridia-widget');
widget.config = {
publishableKey: 'qv_pubt_SUA_CHAVE',
userRef: 'customer-12345',
country: 'PY',
documentType: 'dni',
requireDocBack: false,
locale: 'es',
activeLiveness: true,
};
Definir qualquer atributo observado reconstrói a configuração apenas a partir dos atributos, descartando silenciosamente o que você tinha atribuído a .config — inclusive publishableKey. Se você configurar programaticamente e depois mudar, digamos, locale em tempo de execução para trocar de idioma, o widget perde sua chave e falha com invalid_api_key. Escolha um mecanismo por instância do widget.
Exemplos por framework
React
import { useEffect, useRef } from 'react';
export function VeridiaVerification({ userRef, onComplete }) {
const widgetRef = useRef(null);
useEffect(() => {
const handler = (e) => onComplete(e.detail);
const node = widgetRef.current;
node?.addEventListener('veridia:complete', handler);
return () => node?.removeEventListener('veridia:complete', handler);
}, [onComplete]);
return (
<veridia-widget
ref={widgetRef}
publishable-key={process.env.NEXT_PUBLIC_VERIDIA_KEY}
user-ref={userRef}
locale="es"
/>
);
}
Não esqueça de carregar as tags de script uma vez no seu _document.tsx ou index.html:
<script src="https://widget.xxuxe.online/face-api.js"></script>
<script type="module" src="https://widget.xxuxe.online/veridia-widget.min.js"></script>
Vue 3
<template>
<veridia-widget
ref="widget"
:publishable-key="publishableKey"
:user-ref="userRef"
locale="es"
/>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
const props = defineProps(['publishableKey', 'userRef']);
const emit = defineEmits(['complete']);
const widget = ref(null);
const handler = (e) => emit('complete', e.detail);
onMounted(() => {
widget.value?.addEventListener('veridia:complete', handler);
});
onUnmounted(() => {
widget.value?.removeEventListener('veridia:complete', handler);
});
</script>
O Vue trata <veridia-widget> como custom element automaticamente — nenhuma configuração extra é necessária.
JavaScript puro (sem framework)
<!DOCTYPE html>
<html>
<head>
<script src="https://widget.xxuxe.online/face-api.js"></script>
<script type="module" src="https://widget.xxuxe.online/veridia-widget.min.js"></script>
</head>
<body>
<veridia-widget
id="kyc"
publishable-key="qv_pubt_SUA_CHAVE"
user-ref="user-001"
document-type="dni"
country="PY"
locale="es">
</veridia-widget>
<script>
const widget = document.getElementById('kyc');
widget.addEventListener('veridia:complete', async (e) => {
const { verificationId } = e.detail;
// Registre verificationId -> seu id de usuário AGORA. É o único
// identificador que o polling devolve, e ele não carrega o user-ref.
await fetch('/api/kyc-started', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ verificationId, userId: 'user-001' }),
});
});
widget.addEventListener('veridia:error', (e) => {
// e.detail é { code, message, detail? }
console.error('Veridia error:', e.detail.code, e.detail.message);
});
</script>
</body>
</html>
Confirme que funciona
Abra a página em um navegador via HTTPS (ou localhost — os navegadores concedem acesso à câmera a esses dois e a mais nada). Você deve ver:
- Um botão "Start" abaixo do título "Identity verification" (ou seu equivalente traduzido)
- Depois de clicar em iniciar, um pedido de permissão de câmera
- As etapas de captura — frente do documento, verso do documento a menos que você o tenha desligado, e então a selfie
- Uma tela de confirmação "Submitted ✓"
Nas etapas de documento, o usuário pode usar a câmera ou escolher uma imagem existente na galeria. Nas etapas de selfie e de prova de vida, a opção de galeria está deliberadamente ausente: permitir um arquivo salvo ali anularia o propósito da captura. Vale saber disso antes que uma revisão de compliance pergunte.
Se algo der errado
A tela de erro do widget sempre mostra a mesma mensagem genérica — ela não nomeia a causa. A causa real está no evento veridia:error, então registre-a:
widget.addEventListener('veridia:error', (e) => {
console.error('code:', e.detail.code, '| message:', e.detail.message, '| detail:', e.detail);
});
O próximo passo lista todos os códigos que o widget emite e o que cada um significa. As duas causas mais comuns de falha logo no início são uma publishable-key digitada errado ou revogada (invalid_api_key) e um tenant de teste sem créditos (insufficient_credits).
Próximo passo
Execute uma verificação real de ponta a ponta e inspecione o resultado.