POST /v1/verify/init
Inicia uma nova verificacao. Retorna um verificationId mais tres URLs presigned (doc-front, doc-back, selfie) que o browser usa para fazer upload de imagens diretamente ao Cloudflare R2.
POST https://api.xxuxe.online/v1/verify/init
Por que pre-criar o verification ID
Chamar /init primeiro (em vez de apenas fazer upload e submeter) faz duas coisas:
- Permite que o cliente monte seus proprios logs antes que algo chegue ao backend
- Torna a chamada posterior
/submitidempotente — o mesmoverificationIdno submit body sempre significa a mesma linha no DB
Autenticacao
Bearer token. Publishable (qv_pub_*) ou secret (qv_sec_*).
Authorization: Bearer qv_pub_FJJWXMA2RN2XPRDK6YJX4KTVD0XSQHW9
Request body
Todos os campos sao opcionais, mas country e documentType melhoram significativamente o accuracy do OCR.
| Campo | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
userRef | string | Nao | Seu proprio identificador de usuario — ecoado em eventos de webhook. Max 128 chars |
country | string | Nao | Codigo ISO 3166-1 alpha-2 (ex: PY, BR, MX). Sugere tipo de documento |
documentType | string | Nao | Um de: dni, passport, drivers_license, national_id, other |
submittedFullName | string | Nao | Nome completo como o usuario digitou — para fuzzy matching. Max 255 chars |
Request de exemplo
curl
curl -X POST https://api.xxuxe.online/v1/verify/init \
-H "Authorization: Bearer qv_pub_FJJWXMA2RN2XPRDK6YJX4KTVD0XSQHW9" \
-H "Content-Type: application/json" \
-d '{
"userRef": "customer-12345",
"country": "BR",
"documentType": "national_id",
"submittedFullName": "Joao Carlos Silva"
}'
JavaScript / Node.js
const response = await fetch('https://api.xxuxe.online/v1/verify/init', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.VERIDIA_PUBLISHABLE_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
userRef: 'customer-12345',
country: 'BR',
documentType: 'national_id',
submittedFullName: 'Joao Carlos Silva',
}),
});
const data = await response.json();
console.log(data.verificationId);
Python
import os
import requests
response = requests.post(
"https://api.xxuxe.online/v1/verify/init",
headers={
"Authorization": f"Bearer {os.environ['VERIDIA_PUBLISHABLE_KEY']}",
"Content-Type": "application/json",
},
json={
"userRef": "customer-12345",
"country": "BR",
"documentType": "national_id",
"submittedFullName": "Joao Carlos Silva",
},
)
response.raise_for_status()
data = response.json()
print(data["verificationId"])
PHP
<?php
$payload = json_encode([
"userRef" => "customer-12345",
"country" => "BR",
"documentType" => "national_id",
"submittedFullName" => "Joao Carlos Silva",
]);
$ch = curl_init("https://api.xxuxe.online/v1/verify/init");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $_ENV['VERIDIA_PUBLISHABLE_KEY'],
"Content-Type: application/json",
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $data['verificationId'];
Resposta
200 OK
{
"verificationId": "vf_AG07CDWRRFQV4T05ZXG2",
"uploads": {
"docFront": {
"url": "https://...r2.cloudflarestorage.com/veridia-uploads/verif/tn_xyz/vf_AG07CDWRRFQV4T05ZXG2/doc-front.jpg?...",
"key": "verif/tn_xyz/vf_AG07CDWRRFQV4T05ZXG2/doc-front.jpg",
"method": "PUT",
"headers": {
"Content-Type": "image/jpeg"
}
},
"docBack": {
"url": "https://...r2.cloudflarestorage.com/veridia-uploads/verif/tn_xyz/vf_AG07CDWRRFQV4T05ZXG2/doc-back.jpg?...",
"key": "verif/tn_xyz/vf_AG07CDWRRFQV4T05ZXG2/doc-back.jpg",
"method": "PUT",
"headers": {
"Content-Type": "image/jpeg"
}
},
"selfie": {
"url": "https://...r2.cloudflarestorage.com/veridia-uploads/verif/tn_xyz/vf_AG07CDWRRFQV4T05ZXG2/selfie.jpg?...",
"key": "verif/tn_xyz/vf_AG07CDWRRFQV4T05ZXG2/selfie.jpg",
"method": "PUT",
"headers": {
"Content-Type": "image/jpeg"
}
}
},
"expiresAt": 1714604000
}
Campos de resposta
| Campo | Tipo | Descricao |
|---|---|---|
verificationId | string | ID unico desta verificacao — passar para /submit e /verify/:id |
uploads.docFront | object | URL presigned para a frente do documento (sempre retornada) |
uploads.docBack | object | URL presigned para o verso (usar apenas se necessario) |
uploads.selfie | object | URL presigned para a selfie (sempre retornada) |
uploads.*.url | string | A URL presigned completa — faca PUT com bytes raw aqui |
uploads.*.key | string | Handle opaco — passar de volta em /submit |
uploads.*.method | string | Sempre "PUT" |
uploads.*.headers | object | Headers que seu PUT deve incluir (tipicamente apenas Content-Type) |
expiresAt | number | Unix timestamp quando as URLs presigned param de funcionar (15 minutos apos init) |
Fazendo upload das imagens
Apos /init, seu cliente faz upload de cada imagem diretamente ao R2 usando a URL presigned. Nao proxie atraves do seu backend — voce estaria pagando bandwidth dobrada e adicionando latencia desnecessaria.
async function uploadImage(presigned, blob) {
const response = await fetch(presigned.url, {
method: presigned.method, // "PUT"
headers: presigned.headers,
body: blob,
});
if (!response.ok) {
throw new Error(`Upload falhou: ${response.status}`);
}
}
await uploadImage(initResponse.uploads.docFront, docFrontBlob);
await uploadImage(initResponse.uploads.selfie, selfieBlob);
// docBack apenas se seu tipo de documento exigir
O widget faz tudo isso por voce. Voce so precisa deste codigo se estiver construindo um fluxo custom mobile ou server-side.
Erros
| HTTP | Error code | Quando |
|---|---|---|
400 | invalid_body | O body falhou validacao Zod (veja detail.fieldErrors) |
401 | unauthorized | Header Authorization faltando |
401 | invalid_key | Key revogada, expirada, ou nunca existiu |
403 | origin_not_allowed | Publishable key chamada de dominio nao-whitelisted |
403 | insufficient_credits | O tenant tem 0 creditos |
429 | rate_limited | Atingiu o rate limit de /init (60 req/min por padrao) |
500 | internal | Algo quebrou do nosso lado — inclua o requestId ao reportar |
Catalogo completo: Erros.
Notas
- Formato de
verificationId: prefixovf_+ 16-24 chars alfanumericos (regex:^vf_[A-Za-z0-9]{16,24}$) - As URLs presigned sao validas por 15 minutos — suficiente para um usuario completar o fluxo do widget
- Layout de storage:
verif/<tenantId>/<verificationId>/<role>.jpg(assim o cleanup de retencao e direto) - O
submittedFullNamenao e salvo no path R2 — e PII e vive apenas no record de intent (e seu DB)
Proximos passos
Apos /init, seu cliente faz upload das imagens, depois chama: