Saltar al contenido principal

Webhooks

Trusty envia un webhook a tu endpoint cuando una verificacion termina (approved o rejected).

Como funciona

  1. Tu usuario completa el flujo en el widget (documento + selfie)
  2. Trusty procesa las imagenes con IA
  3. Cuando termina, Trusty envia un POST HTTP a la URL que configuraste
  4. El webhook va firmado con HMAC-SHA256 para que puedas verificar que viene de Trusty

Evento

kyc.verification.completed

Header de firma

X-Trusty-Signature: sha256=<hmac>

El cuerpo del webhook se firma con HMAC-SHA256 usando tu webhook_secret. Siempre verifica la firma antes de procesar el payload.

Payload: verificacion aprobada

{
"event": "kyc.verification.completed",
"verification_id": "601e510f-b0c4-4f6d-a8a2-132fb9b40cf3",
"status": "approved",
"failure_reason": null,
"data": {
"document": {
"document_type": "national_id",
"issuing_country": "ESP",
"full_name": "GUILLERMO DANIEL CANELON LOVERA",
"document_number": "60518799A",
"date_of_birth": "1994-10-25",
"expiration_date": "2029-10-14",
"issue_date": "2024-10-14",
"readable": true,
"is_blurry": false,
"is_screen_recapture": false,
"is_photocopy": false,
"glare_detected": true
},
"liveness": {
"face_visible": true,
"single_face": true,
"eyes_visible": true,
"is_screen_recapture": false,
"is_printed_photo": false
},
"face_match": {
"same_person": true,
"confidence": "high"
}
},
"metadata": { "userId": "123" },
"completed_at": "2026-07-24T03:17:05.799Z"
}

Payload: verificacion rechazada

{
"event": "kyc.verification.completed",
"verification_id": "6ce8ef26-8a2b-48d9-ab97-638efe144137",
"status": "rejected",
"failure_reason": "document_unreadable,screen_recapture_detected",
"data": {
"document": {
"readable": false,
"is_blurry": true,
"is_screen_recapture": true,
"full_name": null,
"document_number": null
},
"liveness": { "face_visible": false },
"face_match": { "same_person": false, "confidence": "low" }
},
"metadata": null,
"completed_at": "2026-07-24T02:53:54.767Z"
}

Campos del payload

Nivel superior

CampoDescripcion
eventSiempre kyc.verification.completed
verification_idUUID de la verificacion
statusapproved o rejected
failure_reasonSi fue rechazada, los motivos separados por coma. Si fue aprobada, null
dataResultados del analisis (ver abajo)
metadataEl JSON que tu enviaste en el widget, sin modificar
completed_atTimestamp ISO 8601 de cuando termino

data.document

CampoDescripcion
document_typeTipo de documento: passport, national_id, drivers_license, other
issuing_countryPais emisor (codigo ISO 3 letras). null si no se pudo leer
full_nameNombre completo extraido del documento. null si no se pudo leer
document_numberNumero de documento. null si no se pudo leer
date_of_birthFecha de nacimiento (YYYY-MM-DD). null si no se pudo leer
expiration_dateFecha de expiracion (YYYY-MM-DD). null si no se pudo leer
issue_dateFecha de emision (YYYY-MM-DD). null si no se pudo leer
readabletrue si la IA pudo leer el documento correctamente
is_blurrytrue si el documento estaba borroso
is_screen_recapturetrue si se detecto que es una foto de una pantalla
is_photocopytrue si se detecto que es una fotocopia
glare_detectedtrue si se detectaron reflejos en el documento

data.liveness

CampoDescripcion
face_visibletrue si se detecto un rostro en el video selfie
single_facetrue si solo habia una persona en el video
eyes_visibletrue si los ojos eran visibles
is_screen_recapturetrue si se detecto que el selfie es de una pantalla
is_printed_phototrue si se detecto que el selfie es de una foto impresa

data.face_match

CampoDescripcion
same_persontrue si el rostro del selfie coincide con la foto del documento
confidenceNivel de confianza: high, medium, low

Motivos de rechazo (failure_reason)

Puede haber uno o varios separados por coma:

MotivoDescripcion
document_unreadableLa IA no pudo leer el documento
document_blurryEl documento estaba borroso
screen_recapture_detectedSe detecto foto de pantalla en documento o selfie
printed_photo_detectedSe detecto foto impresa en el selfie
face_not_visibleNo se detecto rostro en el selfie
multiple_faces_detectedHabia mas de una persona en el selfie
face_mismatchEl rostro del selfie no coincide con el documento
birth_date_unreadableNo se pudo leer la fecha de nacimiento del documento

Verificacion de firma

Node.js

import { createHmac, timingSafeEqual } from 'node:crypto'

const expected = createHmac('sha256', process.env.TRUSTY_WEBHOOK_SECRET)
.update(rawBody)
.digest('hex')

const valid = timingSafeEqual(
Buffer.from(signatureHeader),
Buffer.from(`sha256=${expected}`)
)

Python

import hmac, hashlib

expected = hmac.new(
webhook_secret.encode(),
raw_body,
hashlib.sha256
).hexdigest()

valid = hmac.compare_digest(signature_header, f"sha256={expected}")

PHP

$expected = hash_hmac('sha256', $rawBody, $webhookSecret);
$valid = hash_equals($signatureHeader, "sha256={$expected}");

Retries

  • 3 intentos con backoff lineal (2s, 4s, 6s)
  • 4xx (excepto 429): no reintenta
  • 5xx, timeout, error de red: reintenta
  • Timeout por intento: 10 segundos