Pular para o conteúdo principal

Autenticação

A Veridia usa autenticação por bearer token:

Authorization: Bearer qv_pub_FJJWXMA2RN2XPRDK6YJX4KTVD0XSQHW9

Dois endpoints são a exceção: PUT /v1/verify/upload/... e GET /v1/verify/challenge/.../next não aceitam chave de API alguma. Eles se autenticam com o token de upload de vida curta que o /init entrega. Veja Enviando as imagens.

Famílias de chaves

FamíliaUsar a partir dePode fazerNão pode fazer
PublicávelNavegador, widget, app mobilePOST /v1/verify/init, POST /v1/verify/submitLer veredictos
SecretaApenas no seu servidorTudo o que uma chave publicável faz, mais GET /v1/verify/:id

A chave publicável é segura para embarcar na sua página. Ela foi projetada para isso. Ela pode iniciar verificações contra o seu saldo e pode submetê-las — mas nunca pode ler um resultado.

A chave secreta nunca é segura para embarcar. Ela pode obter o veredicto, os campos de identidade extraídos e os scores de qualquer verificação do seu tenant. Trate-a como a senha de um banco de dados.

Por que a separação existe

Uma chave publicável é, por definição, legível por qualquer pessoa que abra o código-fonte da sua página. Se essa chave pudesse chamar GET /v1/verify/:id, então todos os resultados de KYC dos seus clientes — veredicto, confiança, número do documento, data de nascimento — estariam a um fetch de distância de qualquer pessoa com as ferramentas de desenvolvedor abertas.

Por isso o endpoint de resultados recusa chaves publicáveis com um código de erro dedicado, secret_key_required, em vez de uma falha genérica de autenticação. O código existe justamente para que você não saia caçando um erro de digitação em uma chave que é perfeitamente válida.

Ambientes

Todo tenant recebe dois conjuntos paralelos de chaves. Repare bem nos prefixos de teste — eles são qv_pubt_ e qv_sect_, com o t antes do underscore. Não qv_pub_test_.

AmbientePublicávelSecreta
Testeqv_pubt_...qv_sect_...
Produçãoqv_pub_...qv_sec_...

Uma chave de teste percorre todo o fio, nada do trabalho. Cada request faz a mesma jornada que produção — autenticação de upload real, uma linha de verificação real, um webhook real assinado com seu segredo real e retentado na mesma escada, legível com sua chave secreta de teste — mas nenhum OCR roda, nenhum pipeline de ML roda, nenhum crédito é gasto, e o veredicto é escolhido por você, deterministicamente:

userRef contémVeredictoEvento do webhook
+rejectrejectedverification.rejected
+reviewreviewverification.review
qualquer outra coisaapprovedverification.approved
{ "userRef": "qa-user-17+reject", "documentType": "passport", "country": "PY" }

Resultados determinísticos significam que seu CI pode assertar sobre cada ramo do webhook em vez de torcer para o pipeline opinar igual duas vezes. As imagens enviadas ainda precisam ser JPEGs reais dentro dos limites de tamanho — o caminho dos bytes é exercitado de propósito — mas o conteúdo é ignorado: os campos extraídos voltam como marcadores inconfundíveis (TEST PERSONA, TEST-000000).

Sua URL de webhook recebe OS DOIS mundos

Chaves de teste e de produção entregam na mesma URL de webhook do tenant. Por isso todo envelope de evento carrega um campo env"test" ou "live" — e seu handler precisa ramificar sobre ele. Um verification.approved sintético ativando uma conta real é exatamente o acidente que esse campo existe para prevenir.

Fluxo de trabalho recomendado: desenvolva com chaves de teste, asserte os três resultados no CI, e então troque para chaves de produção. Nunca use uma chave de produção em staging.

Lista de domínios permitidos (chaves publicáveis)

Uma chave publicável pode carregar uma lista de origens permitidas. Quando essa lista não está vazia, uma requisição de navegador cujo Origin não esteja nela é rejeitada com origin_not_allowed (403).

As entradas são comparadas com o hostname puro — sem esquema, sem porta:

yourapp.com
staging.yourapp.com
localhost

http://localhost:3000 não é uma entrada válida. Ela nunca vai casar com nada, porque a checagem compara com o hostname localhost.

Curingas funcionam: *.yourapp.com casa com app.yourapp.com mas deliberadamente não casa com yourapp.com em si. Liste os dois se precisar dos dois.

Leia isto antes de confiar na lista de origens para qualquer coisa

A garantia funciona ao contrário do que a maioria das pessoas espera.

  • Toda chave é criada com uma lista vazia, e uma lista vazia permite todas as origens. A checagem é pulada inteiramente quando a lista está vazia. É opt-in, não opt-out. O painel não expõe hoje um campo para preenchê-la.
  • Ela só se aplica a requisições de navegador. curl, um servidor, um script ou qualquer um dos nossos SDKs server-side não envia cabeçalho Origin, então não há nada a comparar e a requisição segue. Ela nunca consegue restringir uso fora do navegador.
  • Adicionar a sua primeira entrada vira a chave de "qualquer origem" para "somente esta lista". Se você adicionar https://yourapp.com — com o esquema, que não vai casar — você vai de tudo permitido para tudo bloqueado em um único passo. Adicione o hostname puro.

O que essa lista de fato faz é delimitar onde o seu widget pode rodar. Ela não é um controle de acesso. O que protege uma chave publicável é o fato de ela não poder ler resultados, somados aos seus limites de taxa e ao seu saldo de créditos.

Trate uma chave publicável como pública, porque ela é.

Usando a chave secreta

Somente do lado do servidor. Todos os exemplos abaixo obtêm um veredicto.

curl

curl -X GET https://api.xxuxe.online/v1/verify/vf_AG07CDWRRFQV4T05ZXG2 \
-H "Authorization: Bearer qv_sec_YOUR_SECRET"

Em modo de teste a chave começa com qv_sect_.

JavaScript / Node.js

const response = await fetch(`https://api.xxuxe.online/v1/verify/${id}`, {
headers: {
'Authorization': `Bearer ${process.env.VERIDIA_SECRET_KEY}`,
},
});
const data = await response.json();

Python

import os, requests

response = requests.get(
f"https://api.xxuxe.online/v1/verify/{verification_id}",
headers={"Authorization": f"Bearer {os.environ['VERIDIA_SECRET_KEY']}"},
)
data = response.json()

PHP

<?php
$ch = curl_init("https://api.xxuxe.online/v1/verify/$verificationId");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $_ENV['VERIDIA_SECRET_KEY'],
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);

Substituindo uma chave

O painel suporta duas operações: criar e revogar. Não há rotação, e não há período de carência.

A revogação tem efeito imediato

Revogar uma chave a apaga do edge store na hora. Toda requisição em andamento que a use começa a falhar com invalid_api_key no mesmo instante — não existe janela de sobreposição em que a chave antiga continue funcionando.

Então a ordem segura é: crie a chave nova primeiro, faça o deploy dela em todos os lugares, confirme que o tráfego está passando por ela, e só então revogue a antiga. Fazer na ordem inversa é uma indisponibilidade.

Se você suspeita de um vazamento, é exatamente aí que você quer o corte imediato — revogue primeiro e aceite a interrupção. Só faça isso com consciência.

Boas práticas

  • Nunca commite chaves secretas. Variáveis de ambiente ou um gerenciador de segredos.
  • Chaves separadas por ambiente. Nunca uma chave de produção em staging.
  • Criar-e-depois-revogar ao substituir uma chave, pelo motivo acima.
  • Registre o requestId das respostas em log. Isso transforma um chamado de suporte vago em um rastreável.
  • Para qualquer chamada server-side, use a chave secreta. A chave publicável é para clientes.

Erros de autenticação

HTTPCódigo de erroO que significa
401missing_api_keySem cabeçalho Authorization, ou não é o esquema Bearer
401invalid_api_keyA chave não existe, foi revogada, ou o prefixo/formato não é parseável
401secret_key_requiredUma chave publicável foi usada em GET /v1/verify/:id
402insufficient_creditsO saldo de créditos do tenant está zerado
403origin_not_allowedRequisição de navegador vinda de uma origem fora de uma lista permitida não vazia
429rate_limitedVeja Limites de taxa — pode ser a camada por IP, verificada antes da sua chave
503backend_unavailablePipeline inacessível — transitório, tente de novo com backoff

Repare que insufficient_credits é 402, não 403. Ele também é levantado durante a autenticação, o que significa que pode aparecer no /init antes de você ter feito qualquer outra coisa — uma causa comum de "o widget só diz que algo deu errado" em uma conta de teste esgotada.

Veja Erros para o catálogo completo.

O que vem a seguir