Documentation Index Fetch the complete documentation index at: https://docs.gu1.ai/llms.txt
Use this file to discover all available pages before exploring further.
Descripción General
Los eventos de webhook de entidades le permiten recibir notificaciones en tiempo real cuando se crean, actualizan entidades (personas, empresas, dispositivos, etc.) o su estado cambia en la plataforma Gu1. Estos eventos le permiten mantener sus sistemas sincronizados con Gu1 y automatizar flujos de trabajo basados en cambios en el ciclo de vida de las entidades.
¿Por Qué Usar Eventos de Entidades?
Sincronización en Tiempo Real Mantenga su base de datos sincronizada con los datos de entidades de Gu1
Flujos de Trabajo Automatizados Active acciones cuando el estado de la entidad cambie
Registro de Auditoría Rastree todos los cambios de entidades para cumplimiento
Eficiente No es necesario consultar la API para actualizaciones
Eventos Disponibles
entity.created
Se activa cuando se crea una nueva entidad en Gu1.
Cuándo se dispara :
Se crea una nueva persona, empresa, dispositivo u otra entidad a través de POST /entities
Filtros disponibles :
entityTypes: Solo recibe eventos para tipos de entidades específicos (ej., ["person", "company"])
entity.updated
Se activa cuando se actualizan los datos de una entidad (excluyendo cambios de estado).
Cuándo se dispara :
Se actualiza la información de la entidad a través de PATCH /entities/:id
Cambios en nombre, atributos, datos de entidad, ID fiscal, etc.
Nota : Los cambios de estado activan entity.status_changed en su lugar.
Filtros disponibles :
entityTypes: Solo recibe eventos para tipos de entidades específicos
entity.status_changed
Se activa cuando cambia el estado de una entidad.
Cuándo se dispara :
Transiciones de estado de entidad (ej., under_review → active, active → blocked)
Actualizaciones de estado a través de PATCH /entities/:id o acciones de cumplimiento automatizadas
Filtros disponibles :
entityTypes: Filtrar por tipo de entidad
statusChanges.from: Solo activar cuando cambie DESDE un estado específico
statusChanges.to: Solo activar cuando cambie A un estado específico
Ejemplos de Payload de Eventos
entity.created
{
"event" : "entity.created" ,
"timestamp" : "2025-01-07T10:00:00.000Z" ,
"payload" : {
"entity" : {
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"externalId" : "customer_abc123" ,
"name" : "John Doe" ,
"type" : "person" ,
"taxId" : "123-45-6789" ,
"countryCode" : "US" ,
"status" : "under_review" ,
"isClient" : false ,
"attributes" : {
"email" : "john.doe@example.com" ,
"phone" : "+1234567890" ,
"customerTier" : "premium"
},
"entityData" : {
"person" : {
"firstName" : "John" ,
"lastName" : "Doe" ,
"dateOfBirth" : "1990-01-15" ,
"nationality" : "US" ,
"occupation" : "Software Engineer"
}
},
"createdAt" : "2025-01-07T10:00:00.000Z" ,
"updatedAt" : "2025-01-07T10:00:00.000Z"
},
"createdBy" : "user_xyz789" ,
"metadata" : {
"source" : "api" ,
"userAgent" : "Mozilla/5.0..." ,
"ipAddress" : "192.168.1.100"
}
}
}
Campos Clave :
entity: Objeto de entidad completo con todos los datos
entity.externalId: Su identificador único para la entidad
entity.type: Tipo de entidad (person, company, device, etc.)
entity.status: Estado actual (under_review, active, blocked, etc.)
createdBy: ID del usuario que creó la entidad
metadata: Contexto adicional sobre la creación
entity.updated
{
"event" : "entity.updated" ,
"timestamp" : "2025-01-07T10:05:00.000Z" ,
"payload" : {
"entity" : {
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"externalId" : "customer_abc123" ,
"name" : "John Doe" ,
"type" : "person" ,
"taxId" : "123-45-6789" ,
"countryCode" : "US" ,
"status" : "active" ,
"isClient" : false ,
"attributes" : {
"email" : "john.doe@newemail.com" ,
"phone" : "+1234567890" ,
"customerTier" : "premium"
},
"entityData" : {
"person" : {
"firstName" : "John" ,
"lastName" : "Doe" ,
"dateOfBirth" : "1990-01-15" ,
"nationality" : "US" ,
"occupation" : "Senior Software Engineer"
}
},
"updatedAt" : "2025-01-07T10:05:00.000Z"
},
"changes" : {
"attributes.email" : {
"old" : "john.doe@example.com" ,
"new" : "john.doe@newemail.com"
},
"entityData.person.occupation" : {
"old" : "Software Engineer" ,
"new" : "Senior Software Engineer"
}
},
"updatedBy" : "user_xyz789" ,
"reason" : "Customer provided updated information"
}
}
Campos Clave :
entity: Objeto de entidad completo con datos actualizados
changes: Objeto que muestra qué cambió (valores antiguos vs nuevos)
updatedBy: ID del usuario que actualizó la entidad
reason: Razón opcional para la actualización
entity.status_changed
{
"event" : "entity.status_changed" ,
"timestamp" : "2025-01-07T10:10:00.000Z" ,
"payload" : {
"status" : "active" ,
"previousStatus" : "under_review" ,
"reason" : "KYC verification completed successfully" ,
"entity" : {
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"externalId" : "customer_abc123" ,
"name" : "John Doe" ,
"type" : "person" ,
"taxId" : "123-45-6789" ,
"countryCode" : "US" ,
"status" : "active" ,
"updatedAt" : "2025-01-07T10:10:00.000Z"
}
}
}
Campos Clave :
status: Nuevo estado
previousStatus: Estado anterior
reason: Por qué cambió el estado
entity: Objeto de entidad completo
Configuración de Filtros
Filtrar por Tipo de Entidad
Solo reciba eventos para tipos de entidades específicos:
{
"eventTypes" : [ "entity.created" , "entity.updated" ],
"filters" : {
"entityTypes" : [ "person" , "company" ]
}
}
Esta configuración solo activará webhooks para entidades de persona y empresa, ignorando dispositivos y otros tipos.
Filtrar por Cambio de Estado
Solo reciba eventos cuando el estado de la entidad cambie a valores específicos:
{
"eventTypes" : [ "entity.status_changed" ],
"filters" : {
"entityTypes" : [ "person" ],
"statusChanges" : {
"to" : "blocked"
}
}
}
Esto solo se activará cuando una entidad de persona sea cambiada A estado blocked.
Filtrar cuando cambie DESDE un estado específico :
{
"eventTypes" : [ "entity.status_changed" ],
"filters" : {
"statusChanges" : {
"from" : "active" ,
"to" : "suspended"
}
}
}
Esto solo se activará cuando el estado cambie de active a suspended.
Ejemplos de Código
Node.js - Manejo de Eventos de Entidades
const express = require ( 'express' );
const app = express ();
app . use ( express . json ({
verify : ( req , res , buf ) => {
req . rawBody = buf . toString ( 'utf8' );
}
}));
app . post ( '/webhooks/entity' , async ( req , res ) => {
try {
// Verificar firma (ver guía de seguridad)
if ( ! verifySignature ( req . rawBody , req . headers [ 'x-webhook-signature' ])) {
return res . status ( 401 ). json ({ error: 'Invalid signature' });
}
const { event , payload } = req . body ;
// Redirigir al controlador apropiado
switch ( event ) {
case 'entity.created' :
await handleEntityCreated ( payload );
break ;
case 'entity.updated' :
await handleEntityUpdated ( payload );
break ;
case 'entity.status_changed' :
await handleEntityStatusChanged ( payload );
break ;
default :
console . warn ( 'Unknown event type:' , event );
}
res . status ( 200 ). json ({ success: true });
} catch ( error ) {
console . error ( 'Webhook error:' , error );
res . status ( 500 ). json ({ error: error . message });
}
});
async function handleEntityCreated ( payload ) {
const { entity , createdBy , metadata } = payload ;
console . log ( `Entity created: ${ entity . name } ( ${ entity . type } )` );
// Sincronizar con su base de datos
await db . entities . create ({
data: {
gu1Id: entity . id ,
externalId: entity . externalId ,
name: entity . name ,
type: entity . type ,
status: entity . status ,
data: entity . entityData ,
attributes: entity . attributes ,
createdBy ,
metadata
}
});
// Activar flujos de trabajo basados en tipo de entidad
if ( entity . type === 'person' ) {
await sendWelcomeEmail ( entity . attributes . email );
}
}
async function handleEntityUpdated ( payload ) {
const { entity , changes , updatedBy , reason } = payload ;
console . log ( `Entity updated: ${ entity . name } ` );
console . log ( 'Changes:' , changes );
// Actualizar su base de datos
await db . entities . update ({
where: { gu1Id: entity . id },
data: {
name: entity . name ,
status: entity . status ,
data: entity . entityData ,
attributes: entity . attributes ,
lastUpdatedBy: updatedBy ,
updatedAt: new Date ()
}
});
// Registrar cambios para registro de auditoría
await db . entityChanges . create ({
data: {
entityId: entity . id ,
changes ,
changedBy: updatedBy ,
reason ,
timestamp: new Date ()
}
});
}
async function handleEntityStatusChanged ( payload ) {
const { entity , status , previousStatus , reason } = payload ;
console . log ( `Entity status changed: ${ previousStatus } → ${ status } ` );
// Actualizar base de datos
await db . entities . update ({
where: { gu1Id: entity . id },
data: {
status ,
statusChangedAt: new Date ()
}
});
// Tomar acción basada en nuevo estado
switch ( status ) {
case 'active' :
await activateCustomerAccount ( entity . externalId );
await sendNotification ( entity , 'Your account has been activated' );
break ;
case 'blocked' :
await deactivateCustomerAccount ( entity . externalId );
await sendNotification ( entity , 'Your account has been blocked' );
break ;
case 'suspended' :
await suspendCustomerAccount ( entity . externalId );
await sendNotification ( entity , 'Your account has been suspended' );
break ;
}
// Registrar cambio de estado
await db . statusHistory . create ({
data: {
entityId: entity . id ,
fromStatus: previousStatus ,
toStatus: status ,
reason ,
timestamp: new Date ()
}
});
}
app . listen ( 3000 );
Python - Manejo de Eventos de Entidades
from flask import Flask, request, jsonify
import logging
app = Flask( __name__ )
@app.route ( '/webhooks/entity' , methods = [ 'POST' ])
def entity_webhook ():
try :
# Verificar firma (ver guía de seguridad)
signature = request.headers.get( 'X-Webhook-Signature' )
raw_body = request.get_data( as_text = True )
if not verify_signature(raw_body, signature):
return jsonify({ 'error' : 'Invalid signature' }), 401
# Analizar webhook
payload = request.json
event = payload[ 'event' ]
data = payload[ 'payload' ]
# Redirigir al controlador
handlers = {
'entity.created' : handle_entity_created,
'entity.updated' : handle_entity_updated,
'entity.status_changed' : handle_entity_status_changed
}
handler = handlers.get(event)
if handler:
handler(data)
else :
logging.warning( f 'Unknown event type: { event } ' )
return jsonify({ 'success' : True }), 200
except Exception as e:
logging.error( f 'Webhook error: { e } ' )
return jsonify({ 'error' : str (e)}), 500
def handle_entity_created ( data ):
entity = data[ 'entity' ]
created_by = data[ 'createdBy' ]
logging.info( f "Entity created: { entity[ 'name' ] } ( { entity[ 'type' ] } )" )
# Sincronizar con base de datos
db.entities.insert({
'gu1_id' : entity[ 'id' ],
'external_id' : entity[ 'externalId' ],
'name' : entity[ 'name' ],
'type' : entity[ 'type' ],
'status' : entity[ 'status' ],
'data' : entity[ 'entityData' ],
'attributes' : entity[ 'attributes' ],
'created_by' : created_by
})
# Enviar correo de bienvenida para personas
if entity[ 'type' ] == 'person' and 'email' in entity[ 'attributes' ]:
send_welcome_email(entity[ 'attributes' ][ 'email' ])
def handle_entity_updated ( data ):
entity = data[ 'entity' ]
changes = data[ 'changes' ]
updated_by = data.get( 'updatedBy' )
reason = data.get( 'reason' )
logging.info( f "Entity updated: { entity[ 'name' ] } " )
# Actualizar base de datos
db.entities.update(
{ 'gu1_id' : entity[ 'id' ]},
{
'name' : entity[ 'name' ],
'status' : entity[ 'status' ],
'data' : entity[ 'entityData' ],
'attributes' : entity[ 'attributes' ],
'last_updated_by' : updated_by
}
)
# Registrar cambios
db.entity_changes.insert({
'entity_id' : entity[ 'id' ],
'changes' : changes,
'changed_by' : updated_by,
'reason' : reason
})
def handle_entity_status_changed ( data ):
entity = data[ 'entity' ]
status = data[ 'status' ]
previous_status = data[ 'previousStatus' ]
reason = data.get( 'reason' )
logging.info( f "Status changed: { previous_status } → { status } " )
# Actualizar base de datos
db.entities.update(
{ 'gu1_id' : entity[ 'id' ]},
{ 'status' : status}
)
# Tomar acción basada en estado
if status == 'active' :
activate_customer_account(entity[ 'externalId' ])
send_notification(entity, 'Your account has been activated' )
elif status == 'blocked' :
deactivate_customer_account(entity[ 'externalId' ])
send_notification(entity, 'Your account has been blocked' )
# Registrar cambio de estado
db.status_history.insert({
'entity_id' : entity[ 'id' ],
'from_status' : previous_status,
'to_status' : status,
'reason' : reason
})
if __name__ == '__main__' :
app.run( port = 3000 )
Casos de Uso
Caso de Uso 1: Sincronización de Base de Datos en Tiempo Real
Mantenga su base de datos local sincronizada con Gu1:
async function syncEntityToDatabase ( entity ) {
await db . customers . upsert ({
where: { gu1Id: entity . id },
update: {
name: entity . name ,
status: entity . status ,
data: entity . entityData ,
attributes: entity . attributes ,
syncedAt: new Date ()
},
create: {
gu1Id: entity . id ,
externalId: entity . externalId ,
name: entity . name ,
type: entity . type ,
status: entity . status ,
data: entity . entityData ,
attributes: entity . attributes ,
syncedAt: new Date ()
}
});
}
Caso de Uso 2: Activación Automática de Cuenta
Active automáticamente cuentas de clientes cuando el estado cambie a active:
async function handleEntityStatusChanged ( payload ) {
const { entity , status , previousStatus } = payload ;
if ( status === 'active' && previousStatus === 'under_review' ) {
// Habilitar inicio de sesión
await auth . enableUser ( entity . externalId );
// Otorgar acceso a servicios
await services . grantAccess ( entity . externalId );
// Enviar correo de bienvenida
await email . send ({
to: entity . attributes . email ,
subject: 'Welcome! Your account is now active' ,
template: 'account-activated' ,
data: { name: entity . name }
});
// Registrar evento
console . log ( `Account activated: ${ entity . name } ` );
}
}
Caso de Uso 3: Monitoreo de Cumplimiento
Rastree y responda a cambios de estado de entidades para cumplimiento:
async function handleEntityStatusChanged ( payload ) {
const { entity , status , previousStatus , reason } = payload ;
// Alertar al equipo de cumplimiento cuando una entidad es bloqueada
if ( status === 'blocked' ) {
await slack . send ({
channel: '#compliance-alerts' ,
message: `🚨 Entity blocked: ${ entity . name } ( ${ entity . externalId } )` ,
fields: {
'Entity ID' : entity . id ,
'Previous Status' : previousStatus ,
'Reason' : reason ,
'Blocked At' : new Date (). toISOString ()
}
});
// Crear caso en sistema de cumplimiento
await compliance . createCase ({
entityId: entity . id ,
type: 'blocked_entity' ,
priority: 'high' ,
data: entity
});
}
}
Caso de Uso 4: Notificaciones a Clientes
Notifique a los clientes cuando su información cambie:
async function handleEntityUpdated ( payload ) {
const { entity , changes } = payload ;
// Verificar si se actualizó el correo
if ( changes [ 'attributes.email' ]) {
await sendEmail ({
to: changes [ 'attributes.email' ]. new ,
subject: 'Email address updated' ,
body: 'Your email address has been updated. If this was not you, please contact support.'
});
// También enviar al correo antiguo
await sendEmail ({
to: changes [ 'attributes.email' ]. old ,
subject: 'Email address changed' ,
body: 'Your email address has been changed. If this was not you, please contact support immediately.'
});
}
// Notificar en cambios de campos importantes
const importantFields = [ 'taxId' , 'countryCode' , 'name' ];
const importantChanges = Object . keys ( changes ). some ( key =>
importantFields . some ( field => key . includes ( field ))
);
if ( importantChanges ) {
await sendSecurityAlert ( entity , changes );
}
}
Mejores Prácticas
Use externalId para Búsquedas
El entity.externalId es su identificador único. Úselo para buscar entidades en su base de datos: const customer = await db . customers . findUnique ({
where: { externalId: entity . externalId }
});
Almacene el ID de Entidad de Gu1
Siempre almacene el ID de entidad de Gu1 en su base de datos para referencia: await db . customers . create ({
data: {
externalId: entity . externalId ,
gu1Id: entity . id , // Almacenar esto
name: entity . name
}
});
Maneje Todos los Tipos de Eventos
Incluso si solo se suscribe a eventos específicos, maneje todos los tipos de eventos con gracia: switch ( event ) {
case 'entity.created' :
await handleEntityCreated ( payload );
break ;
default :
console . warn ( 'Unhandled event type:' , event );
// Aún así devolver 200
}
Registre Cambios para Auditoría
Mantenga un registro de auditoría de todos los cambios de entidades: await db . auditLog . create ({
data: {
entityId: entity . id ,
event ,
changes ,
timestamp: new Date (),
webhook: req . body
}
});
Use el ID de entidad y timestamp para prevenir procesamiento duplicado: const webhookId = ` ${ entity . id } _ ${ event } _ ${ timestamp } ` ;
const processed = await db . webhookLog . findUnique ({
where: { webhookId }
});
if ( processed ) {
return ; // Omitir duplicado
}
Use Filtros para Reducir Ruido
Configure filtros para recibir solo eventos relevantes: {
"eventTypes" : [ "entity.status_changed" ],
"filters" : {
"entityTypes" : [ "person" ],
"statusChanges" : {
"to" : "active"
}
}
}
Solución de Problemas
No Recibo Eventos entity.created
Verificar :
El webhook está suscrito al evento entity.created
El tipo de entidad coincide con sus filtros (si están configurados)
El webhook está habilitado en el dashboard
El endpoint es públicamente accesible
Probar :# Crear una entidad de prueba
curl -X POST https://api.gu1.io/entities \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{"name":"Test","type":"person"}'
Faltan Cambios en entity.updated
El objeto changes solo incluye campos que realmente cambiaron. Si no ve un campo, significa que no se actualizó. Ejemplo :{
"changes" : {
"name" : {
"old" : "John" ,
"new" : "John Doe"
}
}
}
Solo cambió name, otros campos permanecen igual.
entity.status_changed No Se Dispara
Verificar :
El estado realmente cambió (no solo se actualizó la entidad)
Los filtros coinciden con el cambio de estado (from/to)
El cambio de estado no está siendo filtrado
Ejemplo de filtro que podría bloquear eventos :{
"filters" : {
"statusChanges" : {
"to" : "blocked"
}
}
}
Esto SOLO se disparará cuando el estado cambie A blocked.
Próximos Pasos
Eventos KYC Maneje eventos de verificación KYC
Eventos de Reglas Procese activaciones de reglas de cumplimiento
Seguridad de Webhooks Asegure sus endpoints de webhook
Configuración Configure ajustes de webhook