Descripción General
Los eventos de webhook de transacciones le permiten recibir notificaciones en tiempo real cuando se crean o actualizan transacciones en su organización. Gu1 envía automáticamente solicitudes HTTP POST a su endpoint de webhook configurado, permitiéndole automatizar flujos de trabajo de monitoreo de transacciones, detección de fraude y cumplimiento normativo.
¿Por Qué Usar Webhooks de Transacciones?
Monitoreo en Tiempo Real Reciba notificaciones instantáneas sobre transacciones nuevas o actualizadas
Detección de Fraude Implemente verificaciones de seguridad adicionales en tiempo real
Automatización de Workflows Active procesos automáticos basados en actividad transaccional
Auditoría y Cumplimiento Mantenga registros de auditoría sincronizados en todos sus sistemas
Eventos Disponibles
Gu1 envía webhooks para los siguientes eventos de transacciones:
Tipo de Evento Descripción Cuándo se Activa transaction.createdTransacción creada Cuando se registra una nueva transacción en el sistema transaction.updatedTransacción actualizada Cuando se actualiza el estado o información de una transacción
Los eventos transaction.created y transaction.updated están actualmente en desarrollo y se activarán próximamente. La documentación está disponible para preparar su integración.
Estructura del Payload de Evento
Todos los eventos de webhook de transacciones siguen esta estructura estándar:
{
"event" : "transaction.created" ,
"timestamp" : "2025-01-29T15:30:00Z" ,
"organizationId" : "org-123" ,
"payload" : {
"transactionId" : "550e8400-e29b-41d4-a716-446655440000" ,
"externalId" : "txn_abc123" ,
"type" : "payment" ,
"status" : "CREATED" ,
"amount" : 5000.00 ,
"currency" : "USD"
// ... campos específicos del evento
}
}
Campos Comunes del Payload
El tipo de evento (por ejemplo, transaction.created)
Timestamp ISO 8601 cuando ocurrió el evento
El ID UUID de la transacción en Gu1
Su ID externo para la transacción
Tipo de transacción: payment, transfer, withdrawal, etc.
Estado actual de la transacción: CREATED, PROCESSING, SUSPENDED, SENT, SUCCESSFUL, DECLINED, REFUNDED, EXPIRED
Monto de la transacción en la moneda original
Código de moneda ISO 4217 (por ejemplo, USD, EUR, MXN)
Payloads Específicos de Eventos
transaction.created
Enviado cuando se registra una nueva transacción en el sistema.
{
"event" : "transaction.created" ,
"timestamp" : "2025-01-29T15:30:00Z" ,
"organizationId" : "org-123" ,
"payload" : {
"transactionId" : "550e8400-e29b-41d4-a716-446655440000" ,
"externalId" : "txn_abc123" ,
"type" : "payment" ,
"status" : "CREATED" ,
"amount" : 5000.00 ,
"currency" : "USD" ,
"amountInUsd" : 5000.00 ,
"origin" : {
"entityId" : "123e4567-e89b-12d3-a456-426614174001" ,
"externalId" : "customer_john" ,
"name" : "John Doe" ,
"country" : "US"
},
"destination" : {
"entityId" : "123e4567-e89b-12d3-a456-426614174002" ,
"externalId" : "merchant_acme" ,
"name" : "ACME Corp" ,
"country" : "US"
},
"transactedAt" : "2025-01-29T15:30:00Z" ,
"createdAt" : "2025-01-29T15:30:00Z"
}
}
Caso de uso : Active verificaciones de fraude adicionales, actualice saldos de cuenta en tiempo real, o inicie procesos de cumplimiento.
transaction.updated
Enviado cuando se actualiza una transacción existente (por ejemplo, cambio de estado).
{
"event" : "transaction.updated" ,
"timestamp" : "2025-01-29T15:35:00Z" ,
"organizationId" : "org-123" ,
"payload" : {
"transactionId" : "550e8400-e29b-41d4-a716-446655440000" ,
"externalId" : "txn_abc123" ,
"type" : "payment" ,
"status" : "SUCCESSFUL" ,
"amount" : 5000.00 ,
"currency" : "USD" ,
"amountInUsd" : 5000.00 ,
"origin" : {
"entityId" : "123e4567-e89b-12d3-a456-426614174001" ,
"externalId" : "customer_john" ,
"name" : "John Doe" ,
"country" : "US"
},
"destination" : {
"entityId" : "123e4567-e89b-12d3-a456-426614174002" ,
"externalId" : "merchant_acme" ,
"name" : "ACME Corp" ,
"country" : "US"
},
"previousStatus" : "PROCESSING" ,
"newStatus" : "SUCCESSFUL" ,
"updatedAt" : "2025-01-29T15:35:00Z"
}
}
Caso de uso : Notifique a clientes sobre el estado de su transacción, actualice dashboards en tiempo real, o active flujos de trabajo post-transacción.
Ejemplos de Código
Node.js - Manejo de Eventos de Transacciones
const express = require ( 'express' );
const crypto = require ( 'crypto' );
const app = express ();
app . use ( express . json ({
verify : ( req , res , buf ) => {
req . rawBody = buf . toString ( 'utf8' );
}
}));
app . post ( '/webhooks/transactions' , async ( req , res ) => {
try {
// Verificar firma de webhook (ver guía de seguridad)
const signature = req . headers [ 'x-webhook-signature' ];
const webhookSecret = process . env . GU1_WEBHOOK_SECRET ;
if ( ! verifySignature ( req . rawBody , signature , webhookSecret )) {
console . error ( 'Invalid webhook signature' );
return res . status ( 401 ). json ({ error: 'Invalid signature' });
}
// Extraer datos del webhook
const { event , timestamp , organizationId , payload } = req . body ;
console . log ( 'Received transaction webhook:' , {
event ,
transactionId: payload . transactionId ,
status: payload . status
});
// Procesar el webhook basado en el tipo de evento
await handleTransactionWebhook ( event , payload );
// Retornar 200 para confirmar recepción
res . status ( 200 ). json ({
success: true ,
message: 'Webhook received'
});
} catch ( error ) {
console . error ( 'Webhook error:' , error );
res . status ( 500 ). json ({
error: error . message
});
}
});
async function handleTransactionWebhook ( event , data ) {
const { transactionId , externalId , status , amount , currency } = data ;
// Actualizar su base de datos con la transacción de Gu1
await db . updateTransaction ( externalId , {
gu1TransactionId: transactionId ,
status: status ,
lastUpdated: new Date ()
});
// Realizar acciones basadas en el tipo de evento
switch ( event ) {
case 'transaction.created' :
console . log ( 'New transaction created:' , externalId );
// Verificaciones de fraude adicionales
if ( amount > 10000 ) {
await triggerHighValueReview ( transactionId );
}
// Notificar al cliente
await notifyCustomer ( data . origin . externalId , 'transaction-created' , {
amount ,
currency ,
recipient: data . destination . name
});
break ;
case 'transaction.updated' :
console . log ( 'Transaction status changed:' , {
externalId ,
from: data . previousStatus ,
to: data . newStatus
});
// Actualizar estado en su sistema
await db . updateTransaction ( externalId , {
status: data . newStatus ,
statusChangedAt: new Date ()
});
// Notificar sobre transacción completada
if ( data . newStatus === 'SUCCESSFUL' ) {
await notifyCustomer ( data . origin . externalId , 'transaction-completed' , {
amount ,
currency ,
recipient: data . destination . name
});
}
// Manejar transacciones rechazadas
if ( data . newStatus === 'DECLINED' ) {
await notifyCustomer ( data . origin . externalId , 'transaction-declined' , {
amount ,
currency
});
await logDeclinedTransaction ( transactionId , externalId );
}
break ;
}
}
function verifySignature ( rawBody , signature , secret ) {
const expectedSignature = crypto
. createHmac ( 'sha256' , secret )
. update ( rawBody )
. digest ( 'hex' );
return signature === expectedSignature ;
}
app . listen ( 3000 );
Python - Manejo de Eventos de Transacciones
from flask import Flask, request, jsonify
import hmac
import hashlib
from datetime import datetime
app = Flask( __name__ )
@app.route ( '/webhooks/transactions' , methods = [ 'POST' ])
def handle_transaction_webhook ():
try :
# Verificar firma de webhook
signature = request.headers.get( 'X-Webhook-Signature' )
webhook_secret = os.getenv( 'GU1_WEBHOOK_SECRET' )
if not verify_signature(request.data, signature, webhook_secret):
return jsonify({ 'error' : 'Invalid signature' }), 401
# Procesar webhook
data = request.json
event = data[ 'event' ]
payload = data[ 'payload' ]
print ( f 'Received transaction webhook: { event } ' )
# Manejar evento
handle_transaction_event(event, payload)
return jsonify({
'success' : True ,
'message' : 'Webhook received'
}), 200
except Exception as e:
print ( f 'Webhook error: { str (e) } ' )
return jsonify({ 'error' : str (e)}), 500
def handle_transaction_event ( event , data ):
transaction_id = data[ 'transactionId' ]
external_id = data[ 'externalId' ]
# Actualizar base de datos
db.update_transaction(
external_id = external_id,
gu1_transaction_id = transaction_id,
status = data[ 'status' ],
last_updated = datetime.now()
)
# Manejar diferentes eventos
if event == 'transaction.created' :
# Verificaciones de fraude
if data[ 'amount' ] > 10000 :
trigger_high_value_review(transaction_id)
# Notificar cliente
notify_customer(
data[ 'origin' ][ 'externalId' ],
'transaction-created' ,
data
)
elif event == 'transaction.updated' :
# Registrar cambio de estado
log_status_change(
external_id,
data.get( 'previousStatus' ),
data[ 'status' ]
)
# Notificar sobre completada
if data[ 'status' ] == 'SUCCESSFUL' :
notify_customer(
data[ 'origin' ][ 'externalId' ],
'transaction-completed' ,
data
)
# Manejar rechazadas
elif data[ 'status' ] == 'DECLINED' :
notify_customer(
data[ 'origin' ][ 'externalId' ],
'transaction-declined' ,
data
)
def verify_signature ( raw_body , signature , secret ):
expected = hmac.new(
secret.encode( 'utf-8' ),
raw_body,
hashlib.sha256
).hexdigest()
return signature == expected
if __name__ == '__main__' :
app.run( port = 3000 )
Mejores Prácticas
Use externalId para Búsqueda
El webhook incluye externalId que es el ID que usted proporcionó al crear la transacción. Úselo para buscar la transacción en su base de datos. const transaction = await db . findTransaction ({
externalId: data . externalId
});
Almacene IDs de Transacción de Gu1
Guarde el transactionId de Gu1 en su base de datos. Esto le permite consultar detalles de la transacción más tarde si es necesario. await db . updateTransaction ( transaction . id , {
gu1TransactionId: data . transactionId ,
status: data . status
});
Puede recibir el mismo webhook múltiples veces. Use el transactionId y el event para garantizar que procese cada evento solo una vez. async function handleWebhook ( webhook ) {
const alreadyProcessed = await db . checkWebhookProcessed (
webhook . payload . transactionId ,
webhook . event
);
if ( alreadyProcessed ) {
return ; // Saltar duplicado
}
// Procesar webhook
await processTransaction ( webhook . payload );
// Marcar como procesado
await db . markWebhookProcessed (
webhook . payload . transactionId ,
webhook . event
);
}
Siempre retorne un código de estado 200 lo más rápido posible para confirmar recepción. Procese el webhook asincrónicamente si es necesario. app . post ( '/webhooks/transactions' , async ( req , res ) => {
// Confirmar inmediatamente
res . status ( 200 ). send ( 'OK' );
// Procesar asincrónicamente
processWebhook ( req . body ). catch ( console . error );
});
Siempre verifique el header X-Webhook-Signature para garantizar que el webhook sea auténtico. Vea la guía de seguridad para detalles. const signature = req . headers [ 'x-webhook-signature' ];
if ( ! verifySignature ( req . rawBody , signature , secret )) {
return res . status ( 401 ). json ({ error: 'Invalid signature' });
}
Solución de Problemas
Verificar estos elementos:
URL del webhook es públicamente accesible vía HTTPS
Webhook está configurado y habilitado en el dashboard
Suscrito a los tipos de eventos correctos
Endpoint retorna código de estado 200 dentro de 30 segundos
Verificar logs del servidor para solicitudes recibidas
Los eventos de transacciones están actualmente en desarrollo - confirme que estén activados para su organización
Verificación de Firma Fallando
Causas comunes:
Usar secret incorrecto (verificar dashboard para secret actual)
Verificar firma en JSON parseado en vez de body raw
Secret no guardado correctamente después de crear webhook
Problemas de codificación (garantizar UTF-8)
Vea la guía de seguridad para implementación adecuada.
Recibiendo Webhooks Duplicados
Este es un comportamiento normal. Los webhooks pueden enviarse múltiples veces debido a problemas de red, timeouts o reintentos. Siempre implemente idempotencia usando el transactionId y tipo de event del webhook.
Próximos Pasos