Configuración y Seguridad
Los webhooks permiten que Trébol te notifique automáticamente cuando ocurren eventos importantes, como la finalización de una verificación.- URL de entrega: Debe aceptar solicitudes HTTPS
POST. - Autenticación: Firma HMAC-SHA256 con un secreto por webhook.
Obtención del secreto de webhook
Cada webhook tiene un secreto único que se genera automáticamente cuando lo creas. Este secreto es esencial para verificar la autenticidad de los webhooks que recibes.Cómo obtener tu secreto
El secreto del webhook se genera y se muestra únicamente una vez cuando creas el webhook a través de la API. Es crucial que guardes este secreto de forma segura, ya que no podrás recuperarlo posteriormente.1
Crear webhook con API
Usa el endpoint
POST /v2/webhooks para crear un nuevo webhook. Consulta la documentación completa del endpoint, incluyendo parámetros y ejemplos de respuesta, en API Reference → Gestión de Webhooks.2
Guardar el secreto
En la respuesta de creación, encontrarás el campo
secret que contiene tu
secreto único. Este secreto es esencial para verificar la autenticidad de los
webhooks que recibes.3
Configurar en tu aplicación
Almacena el secreto de forma segura en tu aplicación:
Environment Variables
Configuration
Gestión de secretos
¿Qué hacer si pierdes tu secreto?
¿Qué hacer si pierdes tu secreto?
Si pierdes tu secreto de webhook, deberás crear un nuevo webhook para obtener un nuevo secreto. No es posible recuperar o regenerar el secreto de un webhook existente.
- Crea un nuevo webhook con la misma configuración
- Actualiza tu aplicación con el nuevo secreto
- Elimina el webhook anterior una vez que confirmes que el nuevo funciona correctamente
Rotación de secretos
Rotación de secretos
Para mayor seguridad, puedes implementar una rotación periódica de secretos:
- Crea un nuevo webhook con un nuevo secreto
- Actualiza tu aplicación para aceptar ambos secretos temporalmente
- Una vez confirmado que el nuevo webhook funciona, elimina el anterior
- Actualiza tu aplicación para usar solo el nuevo secreto
Secretos en diferentes entornos
Secretos en diferentes entornos
Es recomendable usar diferentes webhooks (y por tanto diferentes secretos) para cada entorno:
- Desarrollo:
whsec_dev_XXXXXXXXXXXXXXXXXXXXXXXX - Staging:
whsec_staging_XXXXXXXXXXXXXXXXXXXXXXXX - Producción:
whsec_prod_XXXXXXXXXXXXXXXXXXXXXXXX
Verificación de firmas de webhook
Para garantizar la seguridad y autenticidad de los webhooks, Trébol incluye una firma HMAC-SHA256 en el headerTrebol-Signature de cada solicitud. Esta firma te permite verificar que el webhook proviene realmente de Trébol y que el payload no ha sido modificado.
Formato del header de firma
El headerTrebol-Signature contiene múltiples elementos separados por comas:
t: Timestamp Unix de cuando se generó la firmav1: Firma HMAC-SHA256 del payload
Proceso de verificación
- Extraer elementos: Separa el header por comas y extrae el timestamp (
t) y la firma (v1) - Construir payload: Concatena el timestamp con el payload:
{timestamp}.{payload} - Generar firma esperada: Calcula HMAC-SHA256 usando tu secreto de webhook
- Comparar firmas: Usa comparación de tiempo constante para evitar ataques de timing
Ejemplos de implementación
Direcciones IP de origen
Trébol envía todos los webhooks desde las siguientes direcciones IP:35.170.236.12354.162.134.233
Estas IPs son estáticas y no cambiarán. Puedes configurar tu firewall para
permitir únicamente estas direcciones si necesitas restricciones adicionales
de seguridad.
Reintentos automáticos
Cuando tu endpoint no responde con un código de estado exitoso (2xx), Trébol reintentará automáticamente la entrega del webhook usando un esquema de backoff exponencial.
Comportamiento de reintentos
Después de 5 reintentos fallidos, el webhook se marca como fallido y no se reintentará más.
¿Cuándo se reintenta un webhook?
Trébol reintentará la entrega cuando:- Tu servidor responde con un código de error (
4xxo5xx) - Tu servidor no responde (timeout de conexión)
- Hay un error de red que impide la entrega
Evitar reintentos innecesarios
Para evitar que Trébol reintente webhooks que ya procesaste:- Responde con
200 OKinmediatamente después de validar la firma - Procesa el evento de forma asíncrona (ver Mejores prácticas)
- Maneja errores internamente sin retornar códigos de error HTTP
Mejores prácticas
Responde rápidamente con un código 2xx
Tu endpoint debe retornar un código de estado exitoso (2xx) inmediatamente antes de ejecutar cualquier lógica compleja que pueda causar un timeout. Si tu servidor tarda demasiado en responder, Trébol asumirá que la entrega falló y reintentará el envío.
❌ Incorrecto - Procesar antes de responder:
Maneja eventos duplicados
Ocasionalmente, tu endpoint puede recibir el mismo evento más de una vez. Para protegerte contra el procesamiento duplicado, debes implementar idempotencia en tu sistema. Estrategia recomendada: Usa la firma del headerTrebol-Signature como clave de deduplicación, ya que es única por evento.
Procesa eventos de forma asíncrona
Configura tu handler para procesar eventos entrantes con una cola asíncrona. Podrías encontrar problemas de escalabilidad si procesas eventos de forma síncrona, especialmente durante picos de tráfico.Ejemplo con RabbitMQ/SQS
Ejemplo con RabbitMQ/SQS
Ejemplo con Celery (Python)
Ejemplo con Celery (Python)
No dependas del orden de los eventos
Trébol no garantiza que los eventos lleguen en el orden en que fueron generados. Por ejemplo, podrías recibirverification_item.v2.completed antes de verification.v2.created.
Asegúrate de que tu integración pueda manejar eventos en cualquier orden y usa la API para obtener el estado actual si es necesario.
Crear y gestionar webhooks por API
Usa los endpoints enAPI Reference → Gestión de Webhooks para administrar tus webhooks.
- Crear:
POST /v2/webhooks - Listar:
GET /v2/webhooks - Obtener:
GET /v2/webhooks/{webhookId} - Actualizar:
PUT /v2/webhooks/{webhookId} - Eliminar:
DELETE /v2/webhooks/{webhookId}
Tipos de eventos
verification.v2.created
Se dispara cuando se crea una nueva verificación en el sistema.
Payload:
verification.v2.finished
Se dispara cuando una verificación ha sido completada exitosamente.
Payload:
verification.v2.extraction_completed
Se dispara cuando todos los items de extracción dentro de una verificación han completado su proceso de extracción. Esto ocurre antes de que la verificación sea marcada como finalizada (verification.v2.finished), permitiendo acceder a los datos extraídos de forma anticipada.
Payload:
extraction_completed_at(string): Timestamp ISO 8601 de cuando se completó la extracción de todos los items.
verification.v2.document_status_updated
Se dispara cada vez que cambia el estado documental (documents_status) de una
verificación; por ejemplo, cuando se completa el expediente (full_upload).
Aplica a cualquier verificación, sea creada por API o vía el widget.
Para recibirlo, incluye "verification.v2.document_status_updated" en el array
events al crear tu webhook:
status vuelve a pending.
A diferencia de los demás eventos verification.v2.*, el payload de este
evento no incluye account_name.
Payload:
string
ID único de la verificación asociada al evento.
string
ID único de la cuenta asociada a la verificación.
string
Timestamp ISO 8601 de creación de la verificación.
string
Estado del ciclo de vida de la verificación al momento de generar el evento:
pending, finished, error o pending_validation. Es una dimensión
independiente de documents_status: este evento puede llegar con cualquier
status (por ejemplo, con pending de nuevo después de una reapertura).string
Valor personalizado (
tag) que enviaste al crear la verificación. Úsalo para
correlacionar el evento con tu sistema.string
Nuevo estado documental de la verificación, el mismo que se describe en
Estados del expediente.
Valores posibles:
pending_upload: aún no se sube ningún documento requerido.partial_upload: se subieron algunos documentos requeridos, pero faltan otros.pending_external: todos los documentos requeridos están cargados, pero hay pasos externos pendientes, como formularios o beneficiarios finales (UBOs).full_upload: el expediente quedó completo.
full_upload a partial_upload.
Esto ocurre cuando una reapertura o un cambio en los requisitos vuelve a
dejar documentos pendientes.string | null
Estado documental anterior a la transición. Es
null cuando la verificación
aún no tenía un estado documental.string
Timestamp ISO 8601 del momento de la transición.
verification.v2.finished: full_upload
indica que el expediente está completo, mientras que finished indica que
Trébol terminó el análisis. Lo habitual es que el expediente se complete
primero (con status: pending) y la verificación finalice después. Usa este
evento para medir la carga documental y verification.v2.finished para saber
cuándo leer los resultados.
Como con el resto de los eventos, las entregas pueden llegar fuera de orden.
Para reconstruir la secuencia de un verification_id, ordena sus eventos por
updated_at y aplica siempre el más reciente. Si llega un evento con
updated_at anterior al último que aplicaste, descártalo. Como validación
adicional, el previous_documents_status de cada evento debe coincidir con el
documents_status del evento anterior en la cadena.
verification.v2.findings.updated
Se dispara cada vez que Trébol recalcula y guarda los hallazgos de la
Síntesis de Dictamen: los
puntos que le faltan al expediente o que requieren tu atención. No esperes a que
la verificación termine. También se emite en las corridas provisionales, que son
las únicas que existen mientras la verificación sigue abierta.
Es la forma de enterarte de cada corrida sin hacer polling. El bloque findings
de GET /verifications/{verification-id} te da el estado actual cuando lo
consultas; este evento te avisa en el momento en que cambia.
Se firma y se verifica igual que el resto: mismo header Trebol-Signature y
mismo procedimiento HMAC. Ver Verificación de firmas de
webhook.
Qué dispara una corrida. Trébol reevalúa los hallazgos cuando se completa un
item. Solo lo hace en dos condiciones: que el expediente ya esté quieto (todos
los items con archivo terminaron de procesarse) y que los hallazgos guardados
hayan quedado viejos frente a ese último item completado.
Las corridas se agrupan: una ráfaga de items que terminan juntos produce una
sola corrida cuando la ráfaga se calma, no una por item. Al finalizar la
verificación corre la final. Si una verificación finalizada recibe documentos
nuevos, vuelve a correr como final.
En la práctica esperas unas pocas corridas por verificación —típicamente una o
dos provisional mientras se carga el expediente, más la final—, no una por
documento.
Para recibirlo, incluye "verification.v2.findings.updated" en el array events
al crear tu webhook.
En un webhook que ya existe, el PUT actualiza solo los campos que mandas: si
envías únicamente events, la url y la description quedan intactas. Lo que
sí se reemplaza por completo es el array events, así que manda la lista
entera de eventos que quieres, no solo el nuevo. Si no la tienes a mano,
léela primero con GET /v2/webhooks/{webhookId} y agrégale el evento.
verification.v2.*, el payload de este evento
no incluye account_name, ni status, ni verification_tag.
status y el tag los resuelves con GET /verifications/{verification-id}
usando el verification_id del evento — ver Leer una
verificación. Ojo con el nombre: ahí el tag se
llama tag, no verification_tag.
account_name es el caso distinto: otros eventos verification.v2.* sí lo
traen, pero este no —sigue en eso a document_status_updated— y ese endpoint
tampoco lo devuelve. Si necesitas un nombre para mostrar, tenlo de tu lado:
account_id identifica tu propia cuenta. Ver OpenAPI.
Payload:
string
ID único de la verificación cuyos hallazgos recalculó Trébol.
string
ID único de la cuenta asociada a la verificación.
array
Los hallazgos de esta corrida. Un array vacío es un resultado legítimo, no un
error: significa que la corrida no encontró nada que señalar.Ojo con la forma: acá
findings es el array, y source / computed_at
viajan a su lado. En GET /verifications/{verification-id} es un objeto y los
hallazgos están en findings.items. No reutilices el mismo acceso al campo
para las dos superficies.string
provisional o final. Ver abajo.string
Timestamp ISO 8601 del momento exacto en que se calculó esta corrida. Es el
campo con el que ordenas corridas de una misma verificación.Es el mismo instante que devuelve
findings.computed_at en el GET, así que
puedes cruzarlos — pero compáralos parseando la fecha, no como strings: la
representación puede variar. Acá nunca llega null, porque el evento siempre
nace de una corrida recién calculada; en el GET sí puede serlo en
verificaciones antiguas.string
Identificador único de la corrida. Dos eventos con el mismo
run_id son la
misma corrida reentregada, no un recálculo.Existe solo en este evento: ni el bloque findings del GET ni el 202
de una corrida bajo demanda lo devuelven. No sirve para emparejar una corrida
que pediste con el evento que llega; para eso compara computed_at.provisional vs final:
Una corrida provisional se calcula antes de que la verificación finalice, con
un modelo más rápido. Corridas posteriores pueden reemplazarla. La corrida
final se calcula al finalizar la verificación y es la definitiva.
Como una final solo se escribe al completarse, source: "final" ya implica
que la verificación está completa: no necesitas un GET extra para saberlo.
Una verificación suele emitir varias corridas provisional y después una
final. Si se reabre y su expediente cambia, puede emitir una final nueva:
por eso también puedes recibir dos final para la misma verificación.
Al finalizar una verificación, Trébol calcula y emite la corrida final
antes de publicar verification.v2.finished. Pero las entregas pueden
llegar fuera de orden, así que no asumas esa secuencia al recibirlas. Si
necesitas los hallazgos definitivos al cerrar, espera el source: "final" en
vez de deducirlo de verification.v2.finished.
Un final con findings: [] significa que la última corrida no encontró nada
que señalar. Es el resultado limpio, y puedes tratarlo como tal.
Un
final sin hallazgos no es una aprobación formal de la verificación.
Para eso lee su status.verification_id, aplica siempre la corrida
más reciente por computed_at y descarta lo que llegue con una fecha anterior.
Entre dos corridas del mismo computed_at, final gana sobre provisional.
computed_at es el instante en que Trébol calculó la corrida, no el de la
entrega. Ordena corridas de este evento entre sí; no lo mezcles con el
updated_at de los demás eventos verification.*, que marca otra cosa.
La deduplicación general por firma (ver
Maneja eventos duplicados) y el run_id resuelven
problemas distintos, y conviene usar los dos. La firma descarta la misma
entrega repetida. El run_id distingue una reentrega de un recálculo.
Dos corridas distintas de la misma verificación traen firmas distintas y
run_id distintos. Por eso deduplicar solo por firma no descarta nada de más:
deja pasar los recálculos, que es justo lo que quieres.
No necesitas guardar los run_id para siempre. Los reintentos de una entrega se
agotan a los ~15 minutos, así que una ventana de 24 horas cubre de sobra
cualquier reentrega. Más allá de eso puedes purgarlos.
verification_item.v2.completed
Se dispara cuando un item específico dentro de una verificación ha sido completado.
Payload:
-
item_error(opcional): Código de error público asociado al ítem. Su valor depende deitem_type. Los más comunes son:- Comunes a ítems documentales:
password_protected_pdf(PDF con contraseña),get_input_file_info_failed(falló la obtención del archivo de entrada). doc_splitter:unsupported_file_type,unknown_custom_item_type,misconfigured_custom_item_type,no_splits_returned,pdf_slice_failed,pdf_slice_upload_failed,doc_splitter_request_failed. Ver la guía del divisor de documentos para el detalle de cada uno.doc_validation:invalid_document_type,ruleset_validation_failed.
stringopaco: pueden llegar otros valores específicos poritem_type(por ejemploprevalidation_failedencsf_mx) o, en errores inesperados, un mensaje libre en inglés. El listado completo vive en el schemaPublicVerificationItem.item_errordel OpenAPI. - Comunes a ítems documentales:
verification_item.v2.internal_status_changed
Se dispara cuando un item específico dentro de una verificación ha cambiado su estado.
Payload:
item_error(opcional): Código de error público asociado al ítem. Ver la lista completa y semántica de cada código enverification_item.v2.completedmás arriba.
verification_item.v2.extraction_completed
Se dispara cuando un item específico dentro de una verificación ha completado su proceso de extracción de información. Esto permite acceder a los datos extraídos del documento antes de que el item sea marcado como completado.
Payload:
extraction_completed_at(string): Timestamp ISO 8601 de cuando se completó la extracción del item.success(boolean): Indica si la extracción fue exitosa.item_error(opcional): Código de error público asociado al ítem. Ver la lista completa y semántica de cada código enverification_item.v2.completedmás arriba.
verification.v2.label_added
Trébol dispara este evento cuando asignas una etiqueta a una verificación o
cuando Trébol la asigna automáticamente. Las etiquetas pertenecen al catálogo de
la cuenta y te permiten marcar condiciones de negocio sobre una verificación.
Payload:
string
ID único de la verificación asociada al evento.
string
ID único de la cuenta asociada a la verificación.
string
Nombre de la cuenta asociada a la verificación.
string
Timestamp ISO 8601 de creación de la verificación.
string
Estado de la verificación al momento de generar el evento, no de la etiqueta.
Valores posibles:
pending, finished, error, pending_validation.string
Valor personalizado (
tag) que enviaste al crear la verificación. Úsalo para
correlacionar el evento con tu sistema.string
Discriminador del tipo de entidad asociada al evento. Para estos webhooks
siempre es
"label".string
Clave interna no traducible de la etiqueta.
string
Nombre legible de la etiqueta.
string | null
Categoría de la etiqueta cuando el catálogo la define. Es
null si la
etiqueta no tiene categoría.string | null
Comentario asociado a la asignación de la etiqueta.
string
Timestamp ISO 8601 de cuando se asignó la etiqueta.
El payload no incluye
reason ni correlation_id. Trata el par
label_removed + label_added para el mismo entity.label como una
conciliación del estado final de esa etiqueta.verification.v2.label_removed
Trébol dispara este evento cuando remueves una etiqueta de una verificación o
cuando Trébol remueve una asignación automática. También se emite como parte de
la actualización del comentario de una etiqueta existente.
Payload:
string
ID único de la verificación asociada al evento.
string
ID único de la cuenta asociada a la verificación.
string
Nombre de la cuenta asociada a la verificación.
string
Timestamp ISO 8601 de creación de la verificación.
string
Estado de la verificación al momento de generar el evento, no de la etiqueta.
Valores posibles:
pending, finished, error, pending_validation.string
Valor personalizado (
tag) que enviaste al crear la verificación. Úsalo para
correlacionar el evento con tu sistema.string
Discriminador del tipo de entidad asociada al evento. Para estos webhooks
siempre es
"label".string
Clave interna no traducible de la etiqueta.
string
Nombre legible de la etiqueta.
string | null
Categoría de la etiqueta cuando el catálogo la define. Es
null si la
etiqueta no tiene categoría.string | null
Comentario asociado a la etiqueta al momento de removerla.
string
Timestamp ISO 8601 de cuando se removió la etiqueta.
Este evento también se emite cuando actualizas el comentario de una etiqueta.
En ese caso, Trébol genera después
verification.v2.label_added con el
comentario nuevo. Como la entrega puede llegar fuera de orden, concilia por
verification_id, entity.label y timestamps.verification_people.curp_search_completed
Cuándo se dispara:
Este webhook se envía cuando el proceso de búsqueda de CURP para una persona de verificación ha finalizado. Esto puede ocurrir en los siguientes escenarios:
-
Después de extraer accionistas mediante procesamiento de tipos de acta: Cuando se procesan documentos como actas constitutivas (
ac_mx), actas de asamblea (aa_mx), o poderes notariales (pw_mx), y se extraen accionistas de estos documentos, Trébol realiza automáticamente una búsqueda de CURP para cada persona extraída. Una vez completada la búsqueda, se envía este webhook. -
Después de extraer personas desde items
person_id: Cuando se procesa un item de tipoperson_id(documentos de identidad como INE o pasaportes), y se crea o actualiza un registro de persona en la verificación, Trébol realiza una búsqueda de CURP para esa persona. Al finalizar la búsqueda, se envía este webhook.
Este webhook te permite estar al tanto de cuándo la información de CURP está
disponible para las personas en una verificación, lo cual es útil para acceder
a los datos de
external_identities que contienen la información obtenida de
RENAPO. Puedes usar el campo people_id para obtener a la persona en la
respuesta del endpoint people.verification_id(string): ID único de la verificación donde se actualizó la búsqueda de CURP.item_id(number, opcional): ID del item que originó la búsqueda de CURP. Puede ser un item de tipoperson_ido un item de tipo acta que extrajo personas.people_id(number): ID único de la persona de verificación para la cual se completó la búsqueda de CURP.people_error(string, opcional): Código de error si la búsqueda de CURP falló. Solo está presente cuando ocurre un error. Valores permitidos:curp_scrapper_error: Error al extraer información del CURP desde el servicio externo.curp_format_error: El formato del CURP proporcionado no es válido.curp_service_unavailable: El servicio de búsqueda de CURP no está disponible.
people_error_message(string, opcional): Mensaje descriptivo del error. Solo está presente cuandopeople_errortiene un valor.shareholder_id(number, opcional): ID del accionista relacionado, si la persona está asociada a un accionista en la verificación.account_name(string): Nombre de la cuenta asociada a la verificación.account_id(string): ID único de la cuenta.verification_tag(string): Etiqueta personalizada de la verificación.
Obtener datos CURP
Una vez que recibas el webhookverification_people.curp_search_completed, puedes obtener los datos de CURP consultando el endpoint de personas.
1
Recibir el webhook
Extrae
verification_id y people_id del payload del webhook:2
Consultar el endpoint de personas
Usa el
verification_id para llamar al endpoint de personas:3
Buscar la persona en full_list
En la respuesta JSON, localiza la persona cuyo
people_id coincida con el del webhook dentro del array full_list. Ahí es donde encontrarás el objeto completo de la persona junto con sus identidades externas.4
Acceder a los datos de CURP
Una vez que tengas la persona, lee los datos de CURP en el objeto
external_identities.curp:La URL en
curp_file es firmada e incluye Expires=…, por lo que caduca. Si necesitas reabrir el PDF después de la expiración, vuelve a consultar el endpoint de personas para obtener una URL renovada.Cuando
success es false, applicant_data y evidentiary_document_data pueden llegar en null y message describe la causa. Cuando además llega el campo people_error en el webhook, consulta la referencia de errores en consultas públicas para decidir si reintentas.