SDKs
A Veridia publica quatro SDKs. Três são clientes de servidor/API (JavaScript, Python, PHP). Um é uma UI de captura mobile (Flutter).
Todos os quatro estão na 0.1.0. A superfície da API é estável, mas trate a versão pelo que ela diz ser: pré-1.0.
Os quatro
| SDK | Pacote | Registro | Requer | O que é |
|---|---|---|---|---|
| JavaScript / TypeScript | @veridia/sdk | npm | Node 18.17+ (ou um navegador) | Cliente da API + verificação de webhook |
| Python | veridia | PyPI | Python 3.11+ | Cliente da API (sync + async) + verificação de webhook |
| PHP | veridia/veridia-php | Composer | PHP 8.2+ | Cliente da API + verificação de webhook |
| Flutter | veridia_sdk | git privado | Dart 3.10.3+ / Flutter 3.38.4+ | UI de captura por câmera como um único widget |
O nome do pacote para JavaScript é @veridia/sdk. Não @veridia/sdk-js.
Não existe SDK de React Native
Nunca existiu. Se você encontrou uma referência a @veridia/react-native ou uma entrada "React Native" em uma versão antiga desta barra lateral, ela apontava para um pacote que não existe em nenhum registro.
Para React Native hoje, suas opções são a API HTTP diretamente mais suas próprias telas de captura, ou uma WebView hospedando o widget web.
Qual deles eu preciso?
A etapa de captura e a etapa de resultado são trabalhos diferentes, e precisam de chaves diferentes.
Capturar imagens — acesso à câmera, checagens de qualidade, envio dos bytes. Isso roda onde o usuário está: o widget web em um navegador, ou o SDK Flutter em um app. Ambos usam uma chave publicável.
Ler o desfecho — isso roda no seu servidor, com uma chave secreta. Qualquer um dos três SDKs de servidor faz isso, e uma simples requisição HTTP também.
Os três SDKs de servidor também conseguem executar init e submit, que é o que você quer se captura as imagens com seu próprio código e só precisa de um cliente tipado para a API.
Tipos de chave, e qual SDK consegue ler um veredicto
| Prefixo | Tipo | Onde vive | init + submit | Ler veredictos |
|---|---|---|---|---|
qv_pub_, qv_pubt_ | publicável | navegador, app mobile | sim | não |
qv_sec_, qv_sect_ | secreta | somente no seu servidor | sim | sim |
As variantes com t são modo de teste. O prefixo de teste é qv_pubt_ / qv_sect_ — não qv_pub_test_.
GET /v1/verify/{id} recusa uma chave publicável com 401 secret_key_required. Isso é deliberado: uma chave publicável fica no código-fonte da página, onde qualquer pessoa pode lê-la, e um resultado de verificação carrega os campos de identidade extraídos. Uma chave publicável que pudesse ler resultados publicaria os desfechos de KYC de todos os seus clientes para todo visitante.
É por isso que o SDK Flutter aceita apenas uma publishableKey e não consegue buscar um veredicto. Embarcar uma chave secreta dentro do binário de um app não é uma alternativa — um APK é desempacotado em minutos, e a chave que ele entrega lê os veredictos de todos os clientes do seu tenant, não apenas o do dono do telefone.
| SDK | Captura imagens | Faz init / submit | Lê um veredicto |
|---|---|---|---|
| JavaScript | não | sim | sim, com secretKey |
| Python | não | sim | sim, com uma chave qv_sec_* |
| PHP | não | sim | sim, com uma chave qv_sec_* |
| Flutter | sim | sim | não, por design |
O fluxo que todo SDK encapsula
init → PUT de cada imagem → submit → webhook (ou polling)
POST /v1/verify/initretorna um slot de upload por imagem (docFront,docBack,selfie), mais umexpiresAtem segundos unix.PUTdos bytes para a URL de cada slot. Envie osheadersdo slot literalmente — veja abaixo.POST /v1/verify/submitcom askeysda resposta do init.keysé obrigatório.- O pipeline leva cerca de 15 segundos. O desfecho chega por webhook, ou você consulta
GET /v1/verify/{id}com uma chave secreta.
Todo SDK expõe um helper que junta as keys para você — keysFrom (JS), keys_from (Python), VerifySubmitKeys::fromInit (PHP) — porque esquecê-las é a forma mais comum de tomar um 400 do submit.
Os uploads não vão para o R2
As URLs dos slots apontam para um endpoint da Veridia, não para armazenamento de objetos pré-assinado. Elas se autenticam com X-Veridia-Upload-Token, uma credencial de vida curta por verificação carregada dentro dos próprios headers do slot. Sua chave de API não autentica esse endpoint de forma alguma.
Duas consequências que vale conhecer antes de escrever qualquer código de upload à mão:
- Repasse
slot.headersliteralmente. Reconstruir os headers você mesmo — ou enviar apenasContent-Type— descarta o token, e todo upload falha. Os quatro SDKs fazem isso corretamente. - Libere o host da API, não um host de armazenamento. Se você está escrevendo uma CSP ou uma regra de firewall de saída, os bytes vão para
api.xxuxe.online.
O corpo precisa ser um JPEG de verdade (o endpoint checa o número mágico FF D8 FF) e ter no máximo 8 MB.
Você ainda pode ver "presigned R2 upload" no README de algum SDK ou em um comentário de código. Esse texto está desatualizado; o código nos quatro SDKs repassa os headers do slot e está correto.
status não é verdict
Dois eixos independentes, e confundi-los é o erro mais caro que esta API oferece.
| Campo | Pergunta que responde | Valores |
|---|---|---|
status | O pipeline rodou? | queued processing completed failed |
verdict | A pessoa passou? | approved review rejected — ausente até completar |
completed significa que o pipeline chegou a uma conclusão. Uma verificação aprovada, uma que exige revisão e uma rejeitada são todas completed. Ramificar por status para admitir um usuário admite todo candidato rejeitado.
Faça polling no status. Decida pelo verdict.
Duas armadilhas relacionadas: um veredicto nulo não é uma rejeição (significa que nenhuma decisão foi alcançada, seja porque ainda está rodando ou porque failed), e review é final — significa que um humano precisa olhar, não que o resultado ainda está se assentando. Fazer polling em um review esperando que ele se resolva espera para sempre.
metadata não sobrevive
POST /v1/verify/submit aceita um objeto metadata, mas ele é descartado na borda: não chega ao pipeline e não está presente no payload do webhook. Não o use para rotear nem reconciliar nada.
userRef, definido no init, é o campo que liga um evento de volta a um usuário no seu sistema. Ele é ecoado no webhook. Se você também precisa correlacionar no caminho de polling, guarde você mesmo o mapeamento verificationId → usuário: GET /v1/verify/{id} não retorna userRef.
Webhooks
Os quatro SDKs trazem verificação de assinatura HMAC-SHA256. Use-a — o desfecho de uma revisão humana pode chegar muito depois de o submit ter retornado, e o webhook é o único canal que o carrega.
Fatos que valem independentemente da linguagem:
- O cabeçalho é
Veridia-Signature: t=<unix>,v1=<hex>. Não existeX-Veridia-Signaturenem um cabeçalho de timestamp separado — o timestamp fica dentro do valor da assinatura. - O MAC cobre os bytes
"<t>." + rawBody. Verifique contra o corpo bruto. Reserializar o JSON muda o digest e a checagem falha. - O payload é plano —
verdict,verificationId,userRefno nível superior. Não existe envelopedata. - O discriminador é
type, nãoevent. - Exatamente três tipos de evento:
verification.approved,verification.review_required,verification.rejected. Não existe eventocreatednemexpiredpara esperar. - A entrega é ao menos uma vez. Deduplique por
id(evt_<hex>), que é estável entre retentativas. - A tolerância padrão de replay de 300 segundos está correta. Não a amplie — o dispatcher reassina a cada retentativa, então até a última retentativa chega com um
tfresco. fieldsExtractedcarrega PII de identidade: nome completo, número do documento, data de nascimento. É por isso que o endpoint precisa serhttps, e por que o payload não deve ser escrito literalmente nos logs da aplicação.
Detalhes completos na seção de webhooks.
Verificar um webhook é trabalho de servidor. O SDK Flutter expõe um WebhookVerifier, mas um app mobile não é destino de webhook — ele não tem URL estável e não pode guardar o segredo de assinatura.
Para onde ir agora
- SDK JavaScript
- SDK Python
- SDK PHP
- SDK Flutter
- Referência da API HTTP — para qualquer linguagem sem SDK