Skip to main content

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 EventoDescripciónCuándo se Activa
transaction.createdTransacción creadaCuando se registra una nueva transacción en el sistema
transaction.updatedTransacción actualizadaCuando 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

event
string
El tipo de evento (por ejemplo, transaction.created)
timestamp
string
Timestamp ISO 8601 cuando ocurrió el evento
organizationId
string
Su ID de organización
payload.transactionId
string
El ID UUID de la transacción en Gu1
payload.externalId
string
Su ID externo para la transacción
payload.type
string
Tipo de transacción: payment, transfer, withdrawal, etc.
payload.status
string
Estado actual de la transacción: CREATED, PROCESSING, SUSPENDED, SENT, SUCCESSFUL, DECLINED, REFUNDED, EXPIRED
payload.amount
number
Monto de la transacción en la moneda original
payload.currency
string
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

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
});
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
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.
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