Saltar al contenido principal

Errores

Todos los errores de la API Veridia siguen un shape consistente. Esta pagina es la referencia canonica para cada codigo de error que podes ver.

Shape de respuesta de error

Cada respuesta de error incluye:

{
"error": "invalid_body",
"message": "Request body failed validation",
"requestId": "9f511d92ac11236d-SJC",
"detail": {
"fieldErrors": {
"country": ["expected 2 characters"]
}
}
}
CampoTipoDescripcion
errorstringCodigo machine-readable — switcha en este en tu codigo
messagestringResumen human-readable, mayormente para logs
requestIdstringID unico de esta request — incluilo en tickets de soporte
detailobjectOpcional. Contexto extra (errores de campo, razon de mismatch de keys, etc.)

El mismo requestId tambien se devuelve en el response header X-Request-Id — util cuando el parsing JSON falla.

Catalogo de errores

invalid_body400 Bad Request

El body de la request fallo validacion del schema Zod. Revisa detail.fieldErrors por especificos.

Causas comunes:

  • Campo requerido faltante
  • Tipo equivocado (ej. string donde se esperaba number)
  • String muy largo (ej. userRef > 128 chars)
  • Valor enum invalido (ej. documentType: "id" en lugar de "dni")
  • verificationId no matchea ^vf_[A-Za-z0-9]{16,24}$

En /submit especificamente, detail.reason puede ser:

ReasonSignificado
doc_front_key_mismatchEl keys.docFront no coincide con lo que /init devolvio
selfie_key_mismatchEl keys.selfie no coincide con lo que /init devolvio
doc_back_key_mismatchEl keys.docBack no coincide con lo que /init devolvio
doc_front_not_uploadedEl objeto R2 del frente no existe — el cliente nunca subio
selfie_not_uploadedEl objeto R2 de la selfie no existe
doc_front_disappearedEl objeto R2 existia durante HEAD pero desaparecio antes del OCR (extremadamente raro)

Recovery: Arregla la request y reintenta. Estos son errores del cliente.

unauthorized401 Unauthorized

El header Authorization falta, esta malformado, o no usa el scheme Bearer.

Recovery: Agrega un header Authorization: Bearer <key> valido.

invalid_key401 Unauthorized

El bearer token no corresponde a una key valida. Nunca existio, fue revocada, o expiro.

Recovery: Genera una nueva key en el dashboard. Verifica que estes usando la key correcta para el environment correcto.

origin_not_allowed403 Forbidden

La publishable key fue usada desde un dominio que no esta en su lista de allowed origins.

Recovery: Agrega tu dominio a la lista de allowed origins en el dashboard. Para desarrollo local, agrega http://localhost:PORT.

wrong_environment403 Forbidden

Una test key (qv_pub_test_* / qv_sec_test_*) fue usada con un endpoint live, o viceversa.

Recovery: Usa el environment matcheante. Test keys para testing, live keys para produccion.

insufficient_credits403 Forbidden

El tenant tiene 0 creditos. Nuevas verificaciones no pueden iniciar.

Recovery: Top up creditos en el dashboard, o contacta soporte si estas en un plan custom.

verification_not_found404 Not Found

El verificationId no existe, no pertenece a este tenant, o el intent expiro (>1 hora despues del /init).

Recovery:

  • Verifica que el ID no tenga typos
  • Asegurate que estes usando la misma API key (o otra del mismo tenant)
  • Si paso mas de 1 hora desde /init, reinicia el flow

not_found404 Not Found

La ruta no existe.

Recovery: Verifica la URL. Typos comunes: /v1/verifications en lugar de /v1/verify/:id.

rate_limited429 Too Many Requests

Hit el rate limit por tenant. El response header Retry-After te dice cuanto esperar (en segundos).

EndpointLimite por defecto
/v1/verify/init60 / minuto
/v1/verify/submit30 / minuto
/v1/verify/:id600 / minuto

Recovery:

  • Espera la duracion en Retry-After, despues reintenta
  • Agrega throttling de tu lado
  • Contacta soporte para subir limites por-tenant

internal500 Internal Server Error

Algo se rompio del lado de Veridia. Raro.

Recovery:

  • Reintenta con backoff exponencial (el issue puede ser transitorio)
  • Si persiste, manda un ticket de soporte con el requestId de la respuesta

Manejando errores bien

JavaScript / Node.js

async function callVeridia(url, options) {
const response = await fetch(url, options);

if (response.ok) {
return response.json();
}

const error = await response.json();

// Switch en el error code, no en HTTP status
switch (error.error) {
case 'invalid_body':
console.error('Validation fallo:', error.detail?.fieldErrors);
throw new ValidationError(error);

case 'rate_limited':
const retryAfter = response.headers.get('Retry-After') || 1;
await new Promise(r => setTimeout(r, retryAfter * 1000));
return callVeridia(url, options); // reintenta una vez

case 'insufficient_credits':
// Notifica ops, fallback a revision manual
await notifyCreditsExhausted();
throw new BusinessError(error);

case 'verification_not_found':
// Error logico — reinicia el flow
throw new NotFoundError(error);

case 'internal':
// Issue de Veridia — loguea y alerta
logger.error('Veridia internal error', {
requestId: error.requestId,
url,
});
throw new ExternalServiceError(error);

default:
throw new Error(`Veridia error no manejado: ${error.error}`);
}
}

Python

import time
import requests

def call_veridia(url, **kwargs):
response = requests.request(**kwargs, url=url)

if response.ok:
return response.json()

error = response.json()

if error["error"] == "invalid_body":
raise ValidationError(error)

if error["error"] == "rate_limited":
retry_after = int(response.headers.get("Retry-After", 1))
time.sleep(retry_after)
return call_veridia(url, **kwargs)

if error["error"] == "insufficient_credits":
notify_credits_exhausted()
raise BusinessError(error)

if error["error"] == "verification_not_found":
raise NotFoundError(error)

if error["error"] == "internal":
logger.error(
"Veridia internal error",
extra={"request_id": error["requestId"], "url": url},
)
raise ExternalServiceError(error)

raise Exception(f"Veridia error no manejado: {error['error']}")

Best practices

  • Switch en error.error, no en HTTP status. Los codigos HTTP pueden cambiar por razones no-breaking; el codigo error string es parte de nuestro contrato publico de API
  • Siempre loguea el requestId. Es el camino mas rapido a diagnostico si abris un ticket de soporte
  • Reintenta con backoff para internal y rate_limited. No reintentes invalid_body, unauthorized, verification_not_found, o insufficient_credits
  • Surface errores de validation a tus developers, no a tus usuarios finales. Los usuarios finales deberian ver "Algo salio mal, por favor reintenta"
  • Monitorea insufficient_credits como business alert — significa que se esta perdiendo facturacion

Que sigue